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