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