Home | History | Annotate | Download | only in cf
      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 "ResourceRequestCFNet.h"
     28 
     29 #include "ResourceRequest.h"
     30 
     31 #if PLATFORM(MAC)
     32 #include "ResourceLoadPriority.h"
     33 #include "WebCoreSystemInterface.h"
     34 #endif
     35 
     36 #if USE(CFNETWORK)
     37 #include "FormDataStreamCFNet.h"
     38 #include <CFNetwork/CFURLRequestPriv.h>
     39 #include <WebKitSystemInterface/WebKitSystemInterface.h>
     40 #endif
     41 
     42 namespace WebCore {
     43 
     44 bool ResourceRequest::s_httpPipeliningEnabled = false;
     45 
     46 #if USE(CFNETWORK)
     47 
     48 typedef void (*CFURLRequestSetContentDispositionEncodingFallbackArrayFunction)(CFMutableURLRequestRef, CFArrayRef);
     49 typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction)(CFURLRequestRef);
     50 
     51 static HMODULE findCFNetworkModule()
     52 {
     53 #ifndef DEBUG_ALL
     54     return GetModuleHandleA("CFNetwork");
     55 #else
     56     return GetModuleHandleA("CFNetwork_debug");
     57 #endif
     58 }
     59 
     60 static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction()
     61 {
     62     return reinterpret_cast<CFURLRequestSetContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestSetContentDispositionEncodingFallbackArray"));
     63 }
     64 
     65 static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction()
     66 {
     67     return reinterpret_cast<CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestCopyContentDispositionEncodingFallbackArray"));
     68 }
     69 
     70 static void setContentDispositionEncodingFallbackArray(CFMutableURLRequestRef request, CFArrayRef fallbackArray)
     71 {
     72     static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction();
     73     if (function)
     74         function(request, fallbackArray);
     75 }
     76 
     77 static CFArrayRef copyContentDispositionEncodingFallbackArray(CFURLRequestRef request)
     78 {
     79     static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction();
     80     if (!function)
     81         return 0;
     82     return function(request);
     83 }
     84 
     85 CFURLRequestRef ResourceRequest::cfURLRequest() const
     86 {
     87     updatePlatformRequest();
     88 
     89     return m_cfRequest.get();
     90 }
     91 
     92 static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders)
     93 {
     94     // Remove existing headers first, as some of them may no longer be present in the map.
     95     RetainPtr<CFDictionaryRef> oldHeaderFields(AdoptCF, CFURLRequestCopyAllHTTPHeaderFields(request));
     96     CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get());
     97     if (oldHeaderFieldCount) {
     98         Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount);
     99         CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0);
    100         for (CFIndex i = 0; i < oldHeaderFieldCount; ++i)
    101             CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0);
    102     }
    103 
    104     HTTPHeaderMap::const_iterator end = requestHeaders.end();
    105     for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
    106         CFStringRef key = it->first.createCFString();
    107         CFStringRef value = it->second.createCFString();
    108         CFURLRequestSetHTTPHeaderFieldValue(request, key, value);
    109         CFRelease(key);
    110         CFRelease(value);
    111     }
    112 }
    113 
    114 void ResourceRequest::doUpdatePlatformRequest()
    115 {
    116     CFMutableURLRequestRef cfRequest;
    117 
    118     RetainPtr<CFURLRef> url(AdoptCF, ResourceRequest::url().createCFURL());
    119     RetainPtr<CFURLRef> firstPartyForCookies(AdoptCF, ResourceRequest::firstPartyForCookies().createCFURL());
    120     if (m_cfRequest) {
    121         cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
    122         CFURLRequestSetURL(cfRequest, url.get());
    123         CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get());
    124         CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy());
    125         CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval());
    126     } else {
    127         cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get());
    128     }
    129 
    130     RetainPtr<CFStringRef> requestMethod(AdoptCF, httpMethod().createCFString());
    131     CFURLRequestSetHTTPRequestMethod(cfRequest, requestMethod.get());
    132 
    133     setHeaderFields(cfRequest, httpHeaderFields());
    134     WebCore::setHTTPBody(cfRequest, httpBody());
    135     CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies());
    136 
    137     unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size();
    138     RetainPtr<CFMutableArrayRef> encodingFallbacks(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0));
    139     for (unsigned i = 0; i != fallbackCount; ++i) {
    140         RetainPtr<CFStringRef> encodingName(AdoptCF, m_responseContentDispositionEncodingFallbackArray[i].createCFString());
    141         CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get());
    142         if (encoding != kCFStringEncodingInvalidId)
    143             CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding));
    144     }
    145     setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get());
    146 
    147     if (m_cfRequest) {
    148         RetainPtr<CFHTTPCookieStorageRef> cookieStorage(AdoptCF, CFURLRequestCopyHTTPCookieStorage(m_cfRequest.get()));
    149         if (cookieStorage)
    150             CFURLRequestSetHTTPCookieStorage(cfRequest, cookieStorage.get());
    151         CFURLRequestSetHTTPCookieStorageAcceptPolicy(cfRequest, CFURLRequestGetHTTPCookieStorageAcceptPolicy(m_cfRequest.get()));
    152         CFURLRequestSetSSLProperties(cfRequest, CFURLRequestGetSSLProperties(m_cfRequest.get()));
    153     }
    154 
    155     m_cfRequest.adoptCF(cfRequest);
    156 }
    157 
    158 void ResourceRequest::doUpdateResourceRequest()
    159 {
    160     if (!m_cfRequest) {
    161         *this = ResourceRequest();
    162         return;
    163     }
    164 
    165     m_url = CFURLRequestGetURL(m_cfRequest.get());
    166 
    167     m_cachePolicy = (ResourceRequestCachePolicy)CFURLRequestGetCachePolicy(m_cfRequest.get());
    168     m_timeoutInterval = CFURLRequestGetTimeoutInterval(m_cfRequest.get());
    169     m_firstPartyForCookies = CFURLRequestGetMainDocumentURL(m_cfRequest.get());
    170     if (CFStringRef method = CFURLRequestCopyHTTPRequestMethod(m_cfRequest.get())) {
    171         m_httpMethod = method;
    172         CFRelease(method);
    173     }
    174     m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get());
    175 
    176     m_httpHeaderFields.clear();
    177     if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) {
    178         CFIndex headerCount = CFDictionaryGetCount(headers);
    179         Vector<const void*, 128> keys(headerCount);
    180         Vector<const void*, 128> values(headerCount);
    181         CFDictionaryGetKeysAndValues(headers, keys.data(), values.data());
    182         for (int i = 0; i < headerCount; ++i)
    183             m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]);
    184         CFRelease(headers);
    185     }
    186 
    187     m_responseContentDispositionEncodingFallbackArray.clear();
    188     RetainPtr<CFArrayRef> encodingFallbacks(AdoptCF, copyContentDispositionEncodingFallbackArray(m_cfRequest.get()));
    189     if (encodingFallbacks) {
    190         CFIndex count = CFArrayGetCount(encodingFallbacks.get());
    191         for (CFIndex i = 0; i < count; ++i) {
    192             CFStringEncoding encoding = reinterpret_cast<CFIndex>(CFArrayGetValueAtIndex(encodingFallbacks.get(), i));
    193             if (encoding != kCFStringEncodingInvalidId)
    194                 m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding));
    195         }
    196     }
    197 
    198     m_httpBody = httpBodyFromRequest(m_cfRequest.get());
    199 }
    200 
    201 #if USE(CFURLSTORAGESESSIONS)
    202 
    203 void ResourceRequest::setStorageSession(CFURLStorageSessionRef storageSession)
    204 {
    205     CFMutableURLRequestRef cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
    206     wkSetRequestStorageSession(storageSession, cfRequest);
    207     m_cfRequest.adoptCF(cfRequest);
    208 }
    209 
    210 #endif
    211 
    212 #endif // USE(CFNETWORK)
    213 
    214 bool ResourceRequest::httpPipeliningEnabled()
    215 {
    216     return s_httpPipeliningEnabled;
    217 }
    218 
    219 void ResourceRequest::setHTTPPipeliningEnabled(bool flag)
    220 {
    221     s_httpPipeliningEnabled = flag;
    222 }
    223 
    224 unsigned initializeMaximumHTTPConnectionCountPerHost()
    225 {
    226     static const unsigned preferredConnectionCount = 6;
    227     static const unsigned unlimitedConnectionCount = 10000;
    228 
    229     // Always set the connection count per host, even when pipelining.
    230     unsigned maximumHTTPConnectionCountPerHost = wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount);
    231 
    232 #if PLATFORM(MAC)
    233     if (ResourceRequest::httpPipeliningEnabled()) {
    234         wkSetHTTPPipeliningMaximumPriority(ResourceLoadPriorityHighest);
    235         wkSetHTTPPipeliningMinimumFastLanePriority(ResourceLoadPriorityMedium);
    236         // When pipelining do not rate-limit requests sent from WebCore since CFNetwork handles that.
    237         return unlimitedConnectionCount;
    238     }
    239 #endif
    240 
    241     return maximumHTTPConnectionCountPerHost;
    242 }
    243 
    244 } // namespace WebCore
    245