3cd1d2d1f44e4eba1714696bc2443a3f81fdec97
[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 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 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 @interface NSHTTPCookieStorage (Details)
43 - (void)removeCookiesSinceDate:(NSDate *)date;
44 @end
45
46 namespace WebCore {
47
48 static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies)
49 {
50     NSUInteger count = [unfilteredCookies count];
51     RetainPtr<NSMutableArray> filteredCookies = adoptNS([[NSMutableArray alloc] initWithCapacity:count]);
52
53     for (NSUInteger i = 0; i < count; ++i) {
54         NSHTTPCookie *cookie = (NSHTTPCookie *)[unfilteredCookies objectAtIndex:i];
55
56         // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
57         // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent
58         // that, but we also need to avoid sending cookies that were previously stored, and
59         // there's no harm to doing this check because such a cookie is never valid.
60         if (![[cookie name] length])
61             continue;
62
63         if ([cookie isHTTPOnly])
64             continue;
65
66         [filteredCookies.get() addObject:cookie];
67     }
68
69     return filteredCookies;
70 }
71
72 String cookiesForDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
73 {
74     BEGIN_BLOCK_OBJC_EXCEPTIONS;
75
76     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
77     return [[NSHTTPCookie requestHeaderFieldsWithCookies:filterCookies(cookies).get()] objectForKey:@"Cookie"];
78
79     END_BLOCK_OBJC_EXCEPTIONS;
80     return String();
81 }
82
83 String cookieRequestHeaderFieldValue(const NetworkStorageSession& session, const URL& firstParty, const URL& url)
84 {
85     BEGIN_BLOCK_OBJC_EXCEPTIONS;
86
87     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
88     return [[NSHTTPCookie requestHeaderFieldsWithCookies:cookies] objectForKey:@"Cookie"];
89
90     END_BLOCK_OBJC_EXCEPTIONS;
91     return String();
92 }
93
94 void setCookiesFromDOM(const NetworkStorageSession& session, const URL& firstParty, const URL& url, const String& cookieStr)
95 {
96     BEGIN_BLOCK_OBJC_EXCEPTIONS;
97
98     // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie,
99     // which would be sent as "Cookie: =".
100     if (cookieStr.isEmpty())
101         return;
102
103     // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034>
104     // cookiesWithResponseHeaderFields doesn't parse cookies without a value
105     String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "=";
106
107     NSURL *cookieURL = url;
108     RetainPtr<NSArray> filteredCookies = filterCookies([NSHTTPCookie cookiesWithResponseHeaderFields:[NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"] forURL:cookieURL]);
109     ASSERT([filteredCookies.get() count] <= 1);
110
111     wkSetHTTPCookiesForURL(session.cookieStorage().get(), filteredCookies.get(), cookieURL, firstParty);
112
113     END_BLOCK_OBJC_EXCEPTIONS;
114 }
115
116 bool cookiesEnabled(const NetworkStorageSession& session, const URL& /*firstParty*/, const URL& /*url*/)
117 {
118     BEGIN_BLOCK_OBJC_EXCEPTIONS;
119
120     NSHTTPCookieAcceptPolicy cookieAcceptPolicy = static_cast<NSHTTPCookieAcceptPolicy>(wkGetHTTPCookieAcceptPolicy(session.cookieStorage().get()));
121     return cookieAcceptPolicy == NSHTTPCookieAcceptPolicyAlways || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyExclusivelyFromMainDocumentDomain;
122
123     END_BLOCK_OBJC_EXCEPTIONS;
124     return false;
125 }
126
127 bool getRawCookies(const NetworkStorageSession& session, const URL& firstParty, const URL& url, Vector<Cookie>& rawCookies)
128 {
129     rawCookies.clear();
130     BEGIN_BLOCK_OBJC_EXCEPTIONS;
131
132     NSArray *cookies = wkHTTPCookiesForURL(session.cookieStorage().get(), firstParty, url);
133     NSUInteger count = [cookies count];
134     rawCookies.reserveCapacity(count);
135     for (NSUInteger i = 0; i < count; ++i) {
136         NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
137         NSTimeInterval expires = [[cookie expiresDate] timeIntervalSince1970] * 1000;
138         rawCookies.uncheckedAppend(Cookie([cookie name], [cookie value], [cookie domain], [cookie path], expires,
139             [cookie isHTTPOnly], [cookie isSecure], [cookie isSessionOnly]));
140     }
141
142     END_BLOCK_OBJC_EXCEPTIONS;
143     return true;
144 }
145
146 void deleteCookie(const NetworkStorageSession& session, const URL& url, const String& cookieName)
147 {
148     BEGIN_BLOCK_OBJC_EXCEPTIONS;
149
150     RetainPtr<CFHTTPCookieStorageRef> cookieStorage = session.cookieStorage();
151     NSArray *cookies = wkHTTPCookiesForURL(cookieStorage.get(), 0, url);
152
153     NSString *cookieNameString = cookieName;
154
155     NSUInteger count = [cookies count];
156     for (NSUInteger i = 0; i < count; ++i) {
157         NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i];
158         if ([[cookie name] isEqualToString:cookieNameString])
159             wkDeleteHTTPCookie(cookieStorage.get(), cookie);
160     }
161
162     END_BLOCK_OBJC_EXCEPTIONS;
163 }
164
165 void getHostnamesWithCookies(const NetworkStorageSession& session, HashSet<String>& hostnames)
166 {
167     BEGIN_BLOCK_OBJC_EXCEPTIONS;
168
169     NSArray *cookies = wkHTTPCookies(session.cookieStorage().get());
170     
171     for (NSHTTPCookie* cookie in cookies)
172         hostnames.add([cookie domain]);
173     
174     END_BLOCK_OBJC_EXCEPTIONS;
175 }
176
177 void deleteCookiesForHostname(const NetworkStorageSession& session, const String& hostname)
178 {
179     BEGIN_BLOCK_OBJC_EXCEPTIONS;
180
181     RetainPtr<CFHTTPCookieStorageRef> cookieStorage = session.cookieStorage();
182     NSArray *cookies = wkHTTPCookies(cookieStorage.get());
183     if (!cookies)
184         return;
185     
186     for (NSHTTPCookie* cookie in cookies) {
187         if (hostname == String([cookie domain]))
188             wkDeleteHTTPCookie(cookieStorage.get(), cookie);
189     }
190     
191     END_BLOCK_OBJC_EXCEPTIONS;
192 }
193
194 void deleteAllCookies(const NetworkStorageSession& session)
195 {
196     wkDeleteAllHTTPCookies(session.cookieStorage().get());
197 }
198
199 void deleteAllCookiesModifiedAfterDate(const NetworkStorageSession& session, double date)
200 {
201     UNUSED_PARAM(session);
202
203     NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
204     if ([cookieStorage respondsToSelector:@selector(removeCookiesSinceDate:)])
205         [cookieStorage removeCookiesSinceDate:[NSDate dateWithTimeIntervalSince1970:date]];
206 }
207
208 }
209
210 #endif // !USE(CFNETWORK)