Home | History | Annotate | Download | only in win
      1 /*
      2  * Copyright (C) 2006, 2007, 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 #include "config.h"
     27 #include "CookieJar.h"
     28 
     29 #include "Cookie.h"
     30 #include "CookieStorageWin.h"
     31 #include "Document.h"
     32 #include "KURL.h"
     33 #include "PlatformString.h"
     34 #include "ResourceHandle.h"
     35 #include <CFNetwork/CFHTTPCookiesPriv.h>
     36 #include <CoreFoundation/CoreFoundation.h>
     37 #include <WebKitSystemInterface/WebKitSystemInterface.h>
     38 #include <windows.h>
     39 
     40 namespace WebCore {
     41 
     42 static const CFStringRef s_setCookieKeyCF = CFSTR("Set-Cookie");
     43 static const CFStringRef s_cookieCF = CFSTR("Cookie");
     44 
     45 static RetainPtr<CFArrayRef> filterCookies(CFArrayRef unfilteredCookies)
     46 {
     47     CFIndex count = CFArrayGetCount(unfilteredCookies);
     48     RetainPtr<CFMutableArrayRef> filteredCookies(AdoptCF, CFArrayCreateMutable(0, count, &kCFTypeArrayCallBacks));
     49     for (CFIndex i = 0; i < count; ++i) {
     50         CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(unfilteredCookies, i);
     51 
     52         // <rdar://problem/5632883> CFHTTPCookieStorage 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 (!CFStringGetLength(CFHTTPCookieGetName(cookie)))
     57             continue;
     58 
     59         if (CFHTTPCookieIsHTTPOnly(cookie))
     60             continue;
     61 
     62         CFArrayAppendValue(filteredCookies.get(), cookie);
     63     }
     64     return filteredCookies;
     65 }
     66 
     67 void setCookies(Document* document, const KURL& url, const String& value)
     68 {
     69     // <rdar://problem/5632883> CFHTTPCookieStorage stores an empty cookie, which would be sent as "Cookie: =".
     70     if (value.isEmpty())
     71         return;
     72 
     73     CFHTTPCookieStorageRef cookieStorage = currentCookieStorage();
     74     if (!cookieStorage)
     75         return;
     76 
     77     RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL());
     78     RetainPtr<CFURLRef> firstPartyForCookiesCF(AdoptCF, document->firstPartyForCookies().createCFURL());
     79 
     80     // <http://bugs.webkit.org/show_bug.cgi?id=6531>, <rdar://4409034>
     81     // cookiesWithResponseHeaderFields doesn't parse cookies without a value
     82     String cookieString = value.contains('=') ? value : value + "=";
     83 
     84     RetainPtr<CFStringRef> cookieStringCF(AdoptCF, cookieString.createCFString());
     85     RetainPtr<CFDictionaryRef> headerFieldsCF(AdoptCF, CFDictionaryCreate(kCFAllocatorDefault,
     86         (const void**)&s_setCookieKeyCF, (const void**)&cookieStringCF, 1,
     87         &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks));
     88 
     89     RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieCreateWithResponseHeaderFields(kCFAllocatorDefault,
     90         headerFieldsCF.get(), urlCF.get()));
     91 
     92     CFHTTPCookieStorageSetCookies(cookieStorage, filterCookies(cookiesCF.get()).get(), urlCF.get(), firstPartyForCookiesCF.get());
     93 }
     94 
     95 String cookies(const Document* /*document*/, const KURL& url)
     96 {
     97     CFHTTPCookieStorageRef cookieStorage = currentCookieStorage();
     98     if (!cookieStorage)
     99         return String();
    100 
    101     RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL());
    102 
    103     bool secure = url.protocolIs("https");
    104     RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), secure));
    105     RetainPtr<CFDictionaryRef> headerCF(AdoptCF, CFHTTPCookieCopyRequestHeaderFields(kCFAllocatorDefault, filterCookies(cookiesCF.get()).get()));
    106     return (CFStringRef)CFDictionaryGetValue(headerCF.get(), s_cookieCF);
    107 }
    108 
    109 String cookieRequestHeaderFieldValue(const Document* /*document*/, const KURL& url)
    110 {
    111     CFHTTPCookieStorageRef cookieStorage = currentCookieStorage();
    112     if (!cookieStorage)
    113         return String();
    114 
    115     RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL());
    116 
    117     bool secure = url.protocolIs("https");
    118     RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), secure));
    119     RetainPtr<CFDictionaryRef> headerCF(AdoptCF, CFHTTPCookieCopyRequestHeaderFields(kCFAllocatorDefault, cookiesCF.get()));
    120     return (CFStringRef)CFDictionaryGetValue(headerCF.get(), s_cookieCF);
    121 }
    122 
    123 bool cookiesEnabled(const Document* /*document*/)
    124 {
    125     CFHTTPCookieStorageAcceptPolicy policy = CFHTTPCookieStorageAcceptPolicyOnlyFromMainDocumentDomain;
    126     if (CFHTTPCookieStorageRef cookieStorage = currentCookieStorage())
    127         policy = CFHTTPCookieStorageGetCookieAcceptPolicy(cookieStorage);
    128     return policy == CFHTTPCookieStorageAcceptPolicyOnlyFromMainDocumentDomain || policy == CFHTTPCookieStorageAcceptPolicyAlways;
    129 }
    130 
    131 bool getRawCookies(const Document*, const KURL& url, Vector<Cookie>& rawCookies)
    132 {
    133     rawCookies.clear();
    134     CFHTTPCookieStorageRef cookieStorage = currentCookieStorage();
    135     if (!cookieStorage)
    136         return false;
    137 
    138     RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL());
    139 
    140     bool sendSecureCookies = url.protocolIs("https");
    141     RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), sendSecureCookies));
    142 
    143     CFIndex count = CFArrayGetCount(cookiesCF.get());
    144     rawCookies.reserveCapacity(count);
    145 
    146     for (CFIndex i = 0; i < count; i++) {
    147        CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i);
    148        String name = CFHTTPCookieGetName(cookie);
    149        String value = CFHTTPCookieGetValue(cookie);
    150        String domain = CFHTTPCookieGetDomain(cookie);
    151        String path = CFHTTPCookieGetPath(cookie);
    152 
    153        double expires = (CFDateGetAbsoluteTime(CFHTTPCookieGetExpiratonDate(cookie)) + kCFAbsoluteTimeIntervalSince1970) * 1000;
    154 
    155        bool httpOnly = CFHTTPCookieIsHTTPOnly(cookie);
    156        bool secure = CFHTTPCookieIsSecure(cookie);
    157        bool session = false;    // FIXME: Need API for if a cookie is a session cookie.
    158 
    159        rawCookies.uncheckedAppend(Cookie(name, value, domain, path, expires, httpOnly, secure, session));
    160     }
    161 
    162     return true;
    163 }
    164 
    165 void deleteCookie(const Document*, const KURL& url, const String& name)
    166 {
    167     CFHTTPCookieStorageRef cookieStorage = currentCookieStorage();
    168     if (!cookieStorage)
    169         return;
    170 
    171     RetainPtr<CFURLRef> urlCF(AdoptCF, url.createCFURL());
    172 
    173     bool sendSecureCookies = url.protocolIs("https");
    174     RetainPtr<CFArrayRef> cookiesCF(AdoptCF, CFHTTPCookieStorageCopyCookiesForURL(cookieStorage, urlCF.get(), sendSecureCookies));
    175 
    176     CFIndex count = CFArrayGetCount(cookiesCF.get());
    177     for (CFIndex i = 0; i < count; i++) {
    178         CFHTTPCookieRef cookie = (CFHTTPCookieRef)CFArrayGetValueAtIndex(cookiesCF.get(), i);
    179         String cookieName = CFHTTPCookieGetName(cookie);
    180         if (cookieName == name) {
    181             CFHTTPCookieStorageDeleteCookie(cookieStorage, cookie);
    182             break;
    183         }
    184     }
    185 }
    186 
    187 }
    188