/* * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" #include "CookieJar.h" #include "Cookie.h" #include "CookieStorageWin.h" #include "Document.h" #include "KURL.h" #include "PlatformString.h" #include "ResourceHandle.h" #include #include #include #include namespace WebCore { static const CFStringRef s_setCookieKeyCF = CFSTR("Set-Cookie"); static const CFStringRef s_cookieCF = CFSTR("Cookie"); static RetainPtr filterCookies(CFArrayRef unfilteredCookies) { CFIndex count = CFArrayGetCount(unfilteredCookies); RetainPtr filteredCookies(AdoptCF, CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks)); for (CFIndex i = 0; i < count; ++i) { CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(unfilteredCookies, i); // CFHTTPCookieStorage would store an empty cookie, // which would be sent as "Cookie: =". We have a workaround in setCookies() to prevent // that, but we also need to avoid sending cookies that were previously stored, and // there's no harm to doing this check because such a cookie is never valid. if (!CFStringGetLength(CFHTTPCookieGetName(cookie))) continue; if (CFHTTPCookieIsHTTPOnly(cookie)) continue; CFArrayAppendValue(filteredCookies.get(), cookie); } return filteredCookies; } void setCookies(Document* document, const KURL& url, const String& value) { // CFHTTPCookieStorage stores an empty cookie, which would be sent as "Cookie: =". if (value.isEmpty()) return; CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); if (!cookieStorage) return; RetainPtr urlCF(AdoptCF, url.createCFURL()); RetainPtr firstPartyForCookiesCF(AdoptCF, document->firstPartyForCookies().createCFURL()); // , // cookiesWithResponseHeaderFields doesn't parse cookies without a value String cookieString = value.contains('=') ? value : value + "="; RetainPtr cookieStringCF(AdoptCF, cookieString.createCFString()); RetainPtr headerFieldsCF(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault, (const void**)&s_setCookieKeyCF, (const void**)&cookieStringCF, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks)); RetainPtr cookiesCF(AdoptCF, CFHTTPCookieCreateWithResponseHeaderFields(kCFAllocatorDefault, headerFieldsCF.get(), urlCF.get())); CFHTTPCookieStorageSetCookies(cookieStorage, filterCookies(cookiesCF.get()).get(), urlCF.get(), firstPartyForCookiesCF.get()); } String cookies(const Document* /*document*/, const KURL& url) { CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); if (!cookieStorage) return String(); RetainPtr urlCF(AdoptCF, url.createCFURL()); bool secure = url.protocolIs("https"); RetainPtr cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), secure)); RetainPtr headerCF(AdoptCF, CFHTTPCookieCopyRequestHeaderFields(kCFAllocatorDefault, filterCookies(cookiesCF.get()).get())); return (CFStringRef)CFDictionaryGetValue(headerCF.get(), s_cookieCF); } String cookieRequestHeaderFieldValue(const Document* /*document*/, const KURL& url) { CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); if (!cookieStorage) return String(); RetainPtr urlCF(AdoptCF, url.createCFURL()); bool secure = url.protocolIs("https"); RetainPtr cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), secure)); RetainPtr headerCF(AdoptCF, CFHTTPCookieCopyRequestHeaderFields(kCFAllocatorDefault, cookiesCF.get())); return (CFStringRef)CFDictionaryGetValue(headerCF.get(), s_cookieCF); } bool cookiesEnabled(const Document* /*document*/) { CFHTTPCookieStorageAcceptPolicy policy = CFHTTPCookieStorageAcceptPolicyOnlyFromMainDocumentDomain; if (CFHTTPCookieStorageRef cookieStorage = currentCookieStorage()) policy = CFHTTPCookieStorageGetCookieAcceptPolicy(cookieStorage); return policy == CFHTTPCookieStorageAcceptPolicyOnlyFromMainDocumentDomain || policy == CFHTTPCookieStorageAcceptPolicyAlways; } bool getRawCookies(const Document*, const KURL& url, Vector& rawCookies) { rawCookies.clear(); CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); if (!cookieStorage) return false; RetainPtr urlCF(AdoptCF, url.createCFURL()); bool sendSecureCookies = url.protocolIs("https"); RetainPtr cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), sendSecureCookies)); CFIndex count = CFArrayGetCount(cookiesCF.get()); rawCookies.reserveCapacity(count); for (CFIndex i = 0; i < count; i++) { CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i); String name = CFHTTPCookieGetName(cookie); String value = CFHTTPCookieGetValue(cookie); String domain = CFHTTPCookieGetDomain(cookie); String path = CFHTTPCookieGetPath(cookie); double expires = (CFDateGetAbsoluteTime(CFHTTPCookieGetExpiratonDate(cookie)) + kCFAbsoluteTimeIntervalSince1970) * 1000; bool httpOnly = CFHTTPCookieIsHTTPOnly(cookie); bool secure = CFHTTPCookieIsSecure(cookie); bool session = false; // FIXME: Need API for if a cookie is a session cookie. rawCookies.uncheckedAppend(Cookie(name, value, domain, path, expires, httpOnly, secure, session)); } return true; } void deleteCookie(const Document*, const KURL& url, const String& name) { CFHTTPCookieStorageRef cookieStorage = currentCookieStorage(); if (!cookieStorage) return; RetainPtr urlCF(AdoptCF, url.createCFURL()); bool sendSecureCookies = url.protocolIs("https"); RetainPtr cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), sendSecureCookies)); CFIndex count = CFArrayGetCount(cookiesCF.get()); for (CFIndex i = 0; i < count; i++) { CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i); String cookieName = CFHTTPCookieGetName(cookie); if (cookieName == name) { CFHTTPCookieStorageDeleteCookie(cookieStorage, cookie); break; } } } }