1/* 2 * Copyright (C) 2003, 2006, 2008 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 "CookieJar.h" 28 29#import "BlockExceptions.h" 30#import "Cookie.h" 31#import "CookieStorage.h" 32#import "Document.h" 33#import "KURL.h" 34#import "WebCoreSystemInterface.h" 35#import <wtf/RetainPtr.h> 36 37#ifdef BUILDING_ON_TIGER 38typedef unsigned NSUInteger; 39#endif 40 41@interface NSHTTPCookie (WebCoreHTTPOnlyCookies) 42- (BOOL)isHTTPOnly; 43@end 44 45namespace WebCore { 46 47static bool isHTTPOnly(NSHTTPCookie *cookie) 48{ 49 // Once we require a newer version of Foundation with the isHTTPOnly method, 50 // we can eliminate the instancesRespondToSelector: check. 51 static bool supportsHTTPOnlyCookies = [NSHTTPCookie instancesRespondToSelector:@selector(isHTTPOnly)]; 52 return supportsHTTPOnlyCookies && [cookie isHTTPOnly]; 53} 54 55static RetainPtr<NSArray> filterCookies(NSArray *unfilteredCookies) 56{ 57 NSUInteger count = [unfilteredCookies count]; 58 RetainPtr<NSMutableArray> filteredCookies(AdoptNS, [[NSMutableArray alloc] initWithCapacity:count]); 59 60 for (NSUInteger i = 0; i < count; ++i) { 61 NSHTTPCookie *cookie = (NSHTTPCookie *)[unfilteredCookies objectAtIndex:i]; 62 63 // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie, 64 // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent 65 // that, but we also need to avoid sending cookies that were previously stored, and 66 // there's no harm to doing this check because such a cookie is never valid. 67 if (![[cookie name] length]) 68 continue; 69 70 if (isHTTPOnly(cookie)) 71 continue; 72 73 [filteredCookies.get() addObject:cookie]; 74 } 75 76 return filteredCookies; 77} 78 79String cookies(const Document*, const KURL& url) 80{ 81 BEGIN_BLOCK_OBJC_EXCEPTIONS; 82 83 NSURL *cookieURL = url; 84 NSArray *cookies; 85#if USE(CFURLSTORAGESESSIONS) 86 if (CFHTTPCookieStorageRef cookieStorage = privateBrowsingCookieStorage().get()) 87 cookies = wkHTTPCookiesForURL(cookieStorage, cookieURL); 88 else 89#endif 90 cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL]; 91 92 return [[NSHTTPCookie requestHeaderFieldsWithCookies:filterCookies(cookies).get()] objectForKey:@"Cookie"]; 93 94 END_BLOCK_OBJC_EXCEPTIONS; 95 return String(); 96} 97 98String cookieRequestHeaderFieldValue(const Document*, const KURL& url) 99{ 100 BEGIN_BLOCK_OBJC_EXCEPTIONS; 101 102 NSURL *cookieURL = url; 103 NSArray *cookies; 104#if USE(CFURLSTORAGESESSIONS) 105 if (CFHTTPCookieStorageRef cookieStorage = privateBrowsingCookieStorage().get()) 106 cookies = wkHTTPCookiesForURL(cookieStorage, cookieURL); 107 else 108#endif 109 cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL]; 110 111 return [[NSHTTPCookie requestHeaderFieldsWithCookies:cookies] objectForKey:@"Cookie"]; 112 113 END_BLOCK_OBJC_EXCEPTIONS; 114 return String(); 115} 116 117void setCookies(Document* document, const KURL& url, const String& cookieStr) 118{ 119 BEGIN_BLOCK_OBJC_EXCEPTIONS; 120 121 // <rdar://problem/5632883> On 10.5, NSHTTPCookieStorage would store an empty cookie, 122 // which would be sent as "Cookie: =". 123 if (cookieStr.isEmpty()) 124 return; 125 126 // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034> 127 // cookiesWithResponseHeaderFields doesn't parse cookies without a value 128 String cookieString = cookieStr.contains('=') ? cookieStr : cookieStr + "="; 129 130 NSURL *cookieURL = url; 131 RetainPtr<NSArray> filteredCookies = filterCookies([NSHTTPCookie cookiesWithResponseHeaderFields:[NSDictionary dictionaryWithObject:cookieString forKey:@"Set-Cookie"] forURL:cookieURL]); 132 133#if USE(CFURLSTORAGESESSIONS) 134 if (CFHTTPCookieStorageRef cookieStorage = privateBrowsingCookieStorage().get()) 135 wkSetHTTPCookiesForURL(cookieStorage, filteredCookies.get(), cookieURL, document->firstPartyForCookies()); 136 else 137#endif 138 [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:filteredCookies.get() forURL:cookieURL mainDocumentURL:document->firstPartyForCookies()]; 139 140 END_BLOCK_OBJC_EXCEPTIONS; 141} 142 143bool cookiesEnabled(const Document*) 144{ 145 BEGIN_BLOCK_OBJC_EXCEPTIONS; 146 147 NSHTTPCookieAcceptPolicy cookieAcceptPolicy; 148#if USE(CFURLSTORAGESESSIONS) 149 if (CFHTTPCookieStorageRef cookieStorage = privateBrowsingCookieStorage().get()) 150 cookieAcceptPolicy = wkGetHTTPCookieAcceptPolicy(cookieStorage); 151 else 152#endif 153 cookieAcceptPolicy = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookieAcceptPolicy]; 154 155 return cookieAcceptPolicy == NSHTTPCookieAcceptPolicyAlways || cookieAcceptPolicy == NSHTTPCookieAcceptPolicyOnlyFromMainDocumentDomain; 156 157 END_BLOCK_OBJC_EXCEPTIONS; 158 return false; 159} 160 161bool getRawCookies(const Document*, const KURL& url, Vector<Cookie>& rawCookies) 162{ 163 rawCookies.clear(); 164 BEGIN_BLOCK_OBJC_EXCEPTIONS; 165 166 NSURL *cookieURL = url; 167 NSArray *cookies; 168#if USE(CFURLSTORAGESESSIONS) 169 if (CFHTTPCookieStorageRef cookieStorage = privateBrowsingCookieStorage().get()) 170 cookies = wkHTTPCookiesForURL(cookieStorage, cookieURL); 171 else 172#endif 173 cookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:cookieURL]; 174 175 NSUInteger count = [cookies count]; 176 rawCookies.reserveCapacity(count); 177 for (NSUInteger i = 0; i < count; ++i) { 178 NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i]; 179 NSString *name = [cookie name]; 180 NSString *value = [cookie value]; 181 NSString *domain = [cookie domain]; 182 NSString *path = [cookie path]; 183 NSTimeInterval expires = [[cookie expiresDate] timeIntervalSince1970] * 1000; 184 bool httpOnly = [cookie isHTTPOnly]; 185 bool secure = [cookie isSecure]; 186 bool session = [cookie isSessionOnly]; 187 rawCookies.uncheckedAppend(Cookie(name, value, domain, path, expires, httpOnly, secure, session)); 188 } 189 190 END_BLOCK_OBJC_EXCEPTIONS; 191 return true; 192} 193 194void deleteCookie(const Document*, const KURL& url, const String& cookieName) 195{ 196 BEGIN_BLOCK_OBJC_EXCEPTIONS; 197 198 NSURL *cookieURL = url; 199 NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 200 NSArray *cookies; 201#if USE(CFURLSTORAGESESSIONS) 202 CFHTTPCookieStorageRef cfCookieStorage = privateBrowsingCookieStorage().get(); 203 if (cfCookieStorage) 204 cookies = wkHTTPCookiesForURL(cfCookieStorage, cookieURL); 205 else 206#endif 207 cookies = [cookieStorage cookiesForURL:cookieURL]; 208 209 NSString *cookieNameString = (NSString *) cookieName; 210 211 NSUInteger count = [cookies count]; 212 for (NSUInteger i = 0; i < count; ++i) { 213 NSHTTPCookie *cookie = (NSHTTPCookie *)[cookies objectAtIndex:i]; 214 if ([[cookie name] isEqualToString:cookieNameString]) { 215#if USE(CFURLSTORAGESESSIONS) 216 if (cfCookieStorage) 217 wkDeleteHTTPCookie(cfCookieStorage, cookie); 218 else 219#endif 220 [cookieStorage deleteCookie:cookie]; 221 break; 222 } 223 } 224 225 END_BLOCK_OBJC_EXCEPTIONS; 226} 227 228void getHostnamesWithCookies(HashSet<String>& hostnames) 229{ 230 BEGIN_BLOCK_OBJC_EXCEPTIONS; 231 232 NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 233 NSArray *cookies = [cookieStorage cookies]; 234 235 for (NSHTTPCookie* cookie in cookies) 236 hostnames.add([cookie domain]); 237 238 END_BLOCK_OBJC_EXCEPTIONS; 239} 240 241void deleteCookiesForHostname(const String& hostname) 242{ 243 BEGIN_BLOCK_OBJC_EXCEPTIONS; 244 245 NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 246 NSArray *cookies = [cookieStorage cookies]; 247 if (!cookies) 248 return; 249 250 for (NSHTTPCookie* cookie in cookies) { 251 if (hostname == String([cookie domain])) 252 [cookieStorage deleteCookie:cookie]; 253 } 254 255 END_BLOCK_OBJC_EXCEPTIONS; 256} 257 258void deleteAllCookies() 259{ 260 BEGIN_BLOCK_OBJC_EXCEPTIONS; 261 262 NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage]; 263 NSArray *cookies = [cookieStorage cookies]; 264 if (!cookies) 265 return; 266 267 for (NSHTTPCookie* cookie in cookies) 268 [cookieStorage deleteCookie:cookie]; 269 270 END_BLOCK_OBJC_EXCEPTIONS; 271} 272 273} 274