[Mac] [iOS] Add support for CFHTTPCookieStorageAcceptPolicyExclusivelyFromMainDocumen...
[WebKit-https.git] / Source / WebCore / platform / network / mac / CookieJarMac.mm
1 /*
2  * Copyright (C) 2003, 2006, 2008, 2012 Apple Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
14  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL APPLE COMPUTER, INC. OR
17  * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
18  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
19  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
20  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
21  * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
22  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #import "config.h"
27 #import "PlatformCookieJar.h"
28
29 #if !USE(CFNETWORK)
30
31 #import "BlockExceptions.h"
32 #import "Cookie.h"
33 #import "CookieStorage.h"
34 #import "URL.h"
35 #import "NetworkStorageSession.h"
36 #import "WebCoreSystemInterface.h"
37
38 enum {
39     NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain = 3
40 };
41
42 namespace WebCore {
43
44 static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies)
45 {
46     NSUInteger count = [unfilteredCookies count];
47     RetainPtr<NSMutableArray> filteredCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:count]);
48
49     for (NSUInteger i = 0; i < count; ++i) {
50         NSHTTPCookie *cookie = (NSHTTPCookie *)[unfilteredCookies objectAtIndex:i];
51
52         // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
53         // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent
54         // that, but we also need to avoid sending cookies that were previously stored, and
55         // there's no harm to doing this check because such a cookie is never valid.
56         if (![[cookie name] length])
57             continue;
58
59         if ([cookie isHTTPOnly])
60             continue;
61
62         [filteredCookies.get() addObject:cookie];
63     }
64
65     return filteredCookies;
66 }
67
68 String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
69 {
70     BEGIN_BLOCK_OBJC_EXCEPTIONS;
71
72     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
73     return [[NSHTTPCookie requestHeaderFieldsWithCookies:filterCookies(cookies).get()] objectForKey:@"Cookie"];
74
75     END_BLOCK_OBJC_EXCEPTIONS;
76     return String();
77 }
78
79 String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
80 {
81     BEGIN_BLOCK_OBJC_EXCEPTIONS;
82
83     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
84     return [[NSHTTPCookie requestHeaderFieldsWithCookies:cookies] objectForKey:@"Cookie"];
85
86     END_BLOCK_OBJC_EXCEPTIONS;
87     return String();
88 }
89
90 void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& cookieStr)
91 {
92     BEGIN_BLOCK_OBJC_EXCEPTIONS;
93
94     // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
95     // which would be sent as "Cookie: =".
96     if (cookieStr.isEmpty())
97         return;
98
99     // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034>
100     // cookiesWithResponseHeaderFields doesn't parse cookies without a value
101     String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "=";
102
103     NSURL *cookieURL = url;
104     RetainPtr<NSArray> filteredCookies = filterCookies([NSHTTPCookie cookiesWithResponseHeaderFields:[NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"] forURL:cookieURL]);
105     ASSERT([filteredCookies.get() count] <= 1);
106
107     wkSetHTTPCookiesForURL(session.cookieStorage().get(), filteredCookies.get(), cookieURL, firstParty);
108
109     END_BLOCK_OBJC_EXCEPTIONS;
110 }
111
112 bool cookiesEnabled(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/)
113 {
114     BEGIN_BLOCK_OBJC_EXCEPTIONS;
115
116     NSHTTPCookieAcceptPolicy cookieAcceptPolicy = static_cast<NSHTTPCookieAcceptPolicy>(wkGetHTTPCookieAcceptPolicy(session.cookieStorage().get()));
117     return cookieAcceptPolicy == NSHTTPCookieAcceptPolicyAlways || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
118
119     END_BLOCK_OBJC_EXCEPTIONS;
120     return false;
121 }
122
123 bool getRawCookies(const NetworkStorageSession& session, const URL& firstParty, const URL& url, Vector<Cookie>& rawCookies)
124 {
125     rawCookies.clear();
126     BEGIN_BLOCK_OBJC_EXCEPTIONS;
127
128     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
129     NSUInteger count = [cookies count];
130     rawCookies.reserveCapacity(count);
131     for (NSUInteger i = 0; i < count; ++i) {
132         NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
133         NSTimeInterval expires = [[cookie expiresDate] timeIntervalSince1970] * 1000;
134         rawCookies.uncheckedAppend(Cookie([cookie name], [cookie value], [cookie domain], [cookie path], expires,
135             [cookie isHTTPOnly], [cookie isSecure], [cookie isSessionOnly]));
136     }
137
138     END_BLOCK_OBJC_EXCEPTIONS;
139     return true;
140 }
141
142 void deleteCookie(const NetworkStorageSession& session, const URL& url, const String& cookieName)
143 {
144     BEGIN_BLOCK_OBJC_EXCEPTIONS;
145
146     RetainPtr<CFHTTPCookieStorageRef> cookieStorage = session.cookieStorage();
147     NSArray *cookies = wkHTTPCookiesForURL(cookieStorage.get(), 0, url);
148
149     NSString *cookieNameString = cookieName;
150
151     NSUInteger count = [cookies count];
152     for (NSUInteger i = 0; i < count; ++i) {
153         NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
154         if ([[cookie name] isEqualToString:cookieNameString])
155             wkDeleteHTTPCookie(cookieStorage.get(), cookie);
156     }
157
158     END_BLOCK_OBJC_EXCEPTIONS;
159 }
160
161 void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<String>& hostnames)
162 {
163     BEGIN_BLOCK_OBJC_EXCEPTIONS;
164
165     NSArray *cookies = wkHTTPCookies(session.cookieStorage().get());
166     
167     for (NSHTTPCookie* cookie in cookies)
168         hostnames.add([cookie domain]);
169     
170     END_BLOCK_OBJC_EXCEPTIONS;
171 }
172
173 void deleteCookiesForHostname(const NetworkStorageSession& session, const String& hostname)
174 {
175     BEGIN_BLOCK_OBJC_EXCEPTIONS;
176
177     RetainPtr<CFHTTPCookieStorageRef> cookieStorage = session.cookieStorage();
178     NSArray *cookies = wkHTTPCookies(cookieStorage.get());
179     if (!cookies)
180         return;
181     
182     for (NSHTTPCookie* cookie in cookies) {
183         if (hostname == String([cookie domain]))
184             wkDeleteHTTPCookie(cookieStorage.get(), cookie);
185     }
186     
187     END_BLOCK_OBJC_EXCEPTIONS;
188 }
189
190 void deleteAllCookies(const NetworkStorageSession& session)
191 {
192     wkDeleteAllHTTPCookies(session.cookieStorage().get());
193 }
194
195 }
196
197 #endif // !USE(CFNETWORK)