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