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