2 * Copyright (C) 2006, 2007, 2008 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ResourceRequestCFNet.h"
29 #include "ResourceHandle.h"
30 #include "ResourceRequest.h"
33 #include "FormDataStreamCFNet.h"
34 #include <CFNetwork/CFURLRequestPriv.h>
38 #include "ResourceLoadPriority.h"
39 #include "WebCoreSystemInterface.h"
44 #include <WebKitSystemInterface/WebKitSystemInterface.h>
49 bool ResourceRequest::s_httpPipeliningEnabled = false;
53 typedef void (*CFURLRequestSetContentDispositionEncodingFallbackArrayFunction)(CFMutableURLRequestRef, CFArrayRef);
54 typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction)(CFURLRequestRef);
57 static HMODULE findCFNetworkModule()
60 return GetModuleHandleA("CFNetwork");
62 return GetModuleHandleA("CFNetwork_debug");
66 static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction()
68 return reinterpret_cast<CFURLRequestSetContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestSetContentDispositionEncodingFallbackArray"));
71 static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction()
73 return reinterpret_cast<CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestCopyContentDispositionEncodingFallbackArray"));
76 static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction()
78 return reinterpret_cast<CFURLRequestSetContentDispositionEncodingFallbackArrayFunction>(dlsym(RTLD_DEFAULT, "_CFURLRequestSetContentDispositionEncodingFallbackArray"));
81 static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction()
83 return reinterpret_cast<CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction>(dlsym(RTLD_DEFAULT, "_CFURLRequestCopyContentDispositionEncodingFallbackArray"));
87 static void setContentDispositionEncodingFallbackArray(CFMutableURLRequestRef request, CFArrayRef fallbackArray)
89 static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction();
91 function(request, fallbackArray);
94 static CFArrayRef copyContentDispositionEncodingFallbackArray(CFURLRequestRef request)
96 static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction();
99 return function(request);
102 CFURLRequestRef ResourceRequest::cfURLRequest() const
104 updatePlatformRequest();
106 return m_cfRequest.get();
109 static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders)
111 // Remove existing headers first, as some of them may no longer be present in the map.
112 RetainPtr<CFDictionaryRef> oldHeaderFields(AdoptCF, CFURLRequestCopyAllHTTPHeaderFields(request));
113 CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get());
114 if (oldHeaderFieldCount) {
115 Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount);
116 CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0);
117 for (CFIndex i = 0; i < oldHeaderFieldCount; ++i)
118 CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0);
121 HTTPHeaderMap::const_iterator end = requestHeaders.end();
122 for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
123 CFStringRef key = it->first.createCFString();
124 CFStringRef value = it->second.createCFString();
125 CFURLRequestSetHTTPHeaderFieldValue(request, key, value);
131 void ResourceRequest::doUpdatePlatformRequest()
133 CFMutableURLRequestRef cfRequest;
135 RetainPtr<CFURLRef> url(AdoptCF, ResourceRequest::url().createCFURL());
136 RetainPtr<CFURLRef> firstPartyForCookies(AdoptCF, ResourceRequest::firstPartyForCookies().createCFURL());
138 cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
139 CFURLRequestSetURL(cfRequest, url.get());
140 CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get());
141 CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy());
142 CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval());
144 cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get());
145 #if USE(CFURLSTORAGESESSIONS)
146 wkSetRequestStorageSession(ResourceHandle::currentStorageSession(), cfRequest);
149 RetainPtr<CFStringRef> requestMethod(AdoptCF, httpMethod().createCFString());
150 CFURLRequestSetHTTPRequestMethod(cfRequest, requestMethod.get());
152 if (httpPipeliningEnabled())
153 wkSetHTTPPipeliningPriority(cfRequest, toHTTPPipeliningPriority(m_priority));
155 wkCFURLRequestAllowAllPostCaching(cfRequest);
158 setHeaderFields(cfRequest, httpHeaderFields());
159 RefPtr<FormData> formData = httpBody();
160 if (formData && !formData->isEmpty())
161 WebCore::setHTTPBody(cfRequest, formData);
162 CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies());
164 unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size();
165 RetainPtr<CFMutableArrayRef> encodingFallbacks(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0));
166 for (unsigned i = 0; i != fallbackCount; ++i) {
167 RetainPtr<CFStringRef> encodingName(AdoptCF, m_responseContentDispositionEncodingFallbackArray[i].createCFString());
168 CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get());
169 if (encoding != kCFStringEncodingInvalidId)
170 CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding));
172 setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get());
175 RetainPtr<CFHTTPCookieStorageRef> cookieStorage(AdoptCF, CFURLRequestCopyHTTPCookieStorage(m_cfRequest.get()));
177 CFURLRequestSetHTTPCookieStorage(cfRequest, cookieStorage.get());
178 CFURLRequestSetHTTPCookieStorageAcceptPolicy(cfRequest, CFURLRequestGetHTTPCookieStorageAcceptPolicy(m_cfRequest.get()));
179 CFURLRequestSetSSLProperties(cfRequest, CFURLRequestGetSSLProperties(m_cfRequest.get()));
182 m_cfRequest.adoptCF(cfRequest);
184 updateNSURLRequest();
188 void ResourceRequest::doUpdateResourceRequest()
191 *this = ResourceRequest();
195 m_url = CFURLRequestGetURL(m_cfRequest.get());
197 m_cachePolicy = (ResourceRequestCachePolicy)CFURLRequestGetCachePolicy(m_cfRequest.get());
198 m_timeoutInterval = CFURLRequestGetTimeoutInterval(m_cfRequest.get());
199 m_firstPartyForCookies = CFURLRequestGetMainDocumentURL(m_cfRequest.get());
200 if (CFStringRef method = CFURLRequestCopyHTTPRequestMethod(m_cfRequest.get())) {
201 m_httpMethod = method;
204 m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get());
206 if (httpPipeliningEnabled())
207 m_priority = toResourceLoadPriority(wkGetHTTPPipeliningPriority(m_cfRequest.get()));
209 m_httpHeaderFields.clear();
210 if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) {
211 CFIndex headerCount = CFDictionaryGetCount(headers);
212 Vector<const void*, 128> keys(headerCount);
213 Vector<const void*, 128> values(headerCount);
214 CFDictionaryGetKeysAndValues(headers, keys.data(), values.data());
215 for (int i = 0; i < headerCount; ++i)
216 m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]);
220 m_responseContentDispositionEncodingFallbackArray.clear();
221 RetainPtr<CFArrayRef> encodingFallbacks(AdoptCF, copyContentDispositionEncodingFallbackArray(m_cfRequest.get()));
222 if (encodingFallbacks) {
223 CFIndex count = CFArrayGetCount(encodingFallbacks.get());
224 for (CFIndex i = 0; i < count; ++i) {
225 CFStringEncoding encoding = reinterpret_cast<CFIndex>(CFArrayGetValueAtIndex(encodingFallbacks.get(), i));
226 if (encoding != kCFStringEncodingInvalidId)
227 m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding));
231 m_httpBody = httpBodyFromRequest(m_cfRequest.get());
234 #if USE(CFURLSTORAGESESSIONS)
236 void ResourceRequest::setStorageSession(CFURLStorageSessionRef storageSession)
238 CFMutableURLRequestRef cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
239 wkSetRequestStorageSession(storageSession, cfRequest);
240 m_cfRequest.adoptCF(cfRequest);
242 updateNSURLRequest();
249 void ResourceRequest::applyWebArchiveHackForMail()
251 // Hack because Mail checks for this property to detect data / archive loads
252 _CFURLRequestSetProtocolProperty(cfURLRequest(), CFSTR("WebDataRequest"), CFSTR(""));
256 #endif // USE(CFNETWORK)
258 bool ResourceRequest::httpPipeliningEnabled()
260 return s_httpPipeliningEnabled;
263 void ResourceRequest::setHTTPPipeliningEnabled(bool flag)
265 s_httpPipeliningEnabled = flag;
268 #if USE(CFNETWORK) || PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
269 static inline bool readBooleanPreference(CFStringRef key)
271 Boolean keyExistsAndHasValidFormat;
272 Boolean result = CFPreferencesGetAppBooleanValue(key, kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
273 return keyExistsAndHasValidFormat ? result : false;
277 unsigned initializeMaximumHTTPConnectionCountPerHost()
279 static const unsigned preferredConnectionCount = 6;
281 // Always set the connection count per host, even when pipelining.
282 unsigned maximumHTTPConnectionCountPerHost = wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount);
284 #if USE(CFNETWORK) || PLATFORM(MAC) && !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_SNOW_LEOPARD)
285 static const unsigned unlimitedConnectionCount = 10000;
287 if (!ResourceRequest::httpPipeliningEnabled() && readBooleanPreference(CFSTR("WebKitEnableHTTPPipelining")))
288 ResourceRequest::setHTTPPipeliningEnabled(true);
290 if (ResourceRequest::httpPipeliningEnabled()) {
291 wkSetHTTPPipeliningMaximumPriority(toHTTPPipeliningPriority(ResourceLoadPriorityHighest));
293 // FIXME: <rdar://problem/9375609> Implement minimum fast lane priority setting on Windows
294 wkSetHTTPPipeliningMinimumFastLanePriority(toHTTPPipeliningPriority(ResourceLoadPriorityMedium));
296 // When pipelining do not rate-limit requests sent from WebCore since CFNetwork handles that.
297 return unlimitedConnectionCount;
301 return maximumHTTPConnectionCountPerHost;
304 } // namespace WebCore