410a6498274eaa1352323fd5267eb4623b4c08df
[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 #if USE(CFNETWORK)
30
31 #include "FormDataStreamCFNet.h"
32 #include "ResourceRequest.h"
33
34 #include <CFNetwork/CFURLRequestPriv.h>
35 #include <WebKitSystemInterface/WebKitSystemInterface.h>
36
37 namespace WebCore {
38
39 typedef void (*CFURLRequestSetContentDispositionEncodingFallbackArrayFunction)(CFMutableURLRequestRef, CFArrayRef);
40 typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction)(CFURLRequestRef);
41
42 static HMODULE findCFNetworkModule()
43 {
44 #ifndef DEBUG_ALL
45     return GetModuleHandleA("CFNetwork");
46 #else
47     return GetModuleHandleA("CFNetwork_debug");
48 #endif
49 }
50
51 static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction()
52 {
53     return reinterpret_cast<CFURLRequestSetContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestSetContentDispositionEncodingFallbackArray"));
54 }
55
56 static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction()
57 {
58     return reinterpret_cast<CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestCopyContentDispositionEncodingFallbackArray"));
59 }
60
61 static void setContentDispositionEncodingFallbackArray(CFMutableURLRequestRef request, CFArrayRef fallbackArray)
62 {
63     static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction();
64     if (function)
65         function(request, fallbackArray);
66 }
67
68 static CFArrayRef copyContentDispositionEncodingFallbackArray(CFURLRequestRef request)
69 {
70     static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction();
71     if (!function)
72         return 0;
73     return function(request);
74 }
75
76 CFURLRequestRef ResourceRequest::cfURLRequest() const
77 {
78     updatePlatformRequest();
79
80     return m_cfRequest.get();
81 }
82
83 static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders) 
84 {
85     // Remove existing headers first, as some of them may no longer be present in the map.
86     RetainPtr<CFDictionaryRef> oldHeaderFields(AdoptCF, CFURLRequestCopyAllHTTPHeaderFields(request));
87     CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get());
88     if (oldHeaderFieldCount) {
89         Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount);
90         CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0);
91         for (CFIndex i = 0; i < oldHeaderFieldCount; ++i)
92             CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0);
93     }
94
95     HTTPHeaderMap::const_iterator end = requestHeaders.end();
96     for (HTTPHeaderMap::const_iterator it = requestHeaders.begin(); it != end; ++it) {
97         CFStringRef key = it->first.createCFString();
98         CFStringRef value = it->second.createCFString();
99         CFURLRequestSetHTTPHeaderFieldValue(request, key, value);
100         CFRelease(key);
101         CFRelease(value);
102     }
103 }
104
105 void ResourceRequest::doUpdatePlatformRequest()
106 {
107     CFMutableURLRequestRef cfRequest;
108
109     RetainPtr<CFURLRef> url(AdoptCF, ResourceRequest::url().createCFURL());
110     RetainPtr<CFURLRef> firstPartyForCookies(AdoptCF, ResourceRequest::firstPartyForCookies().createCFURL());
111     if (m_cfRequest) {
112         cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
113         CFURLRequestSetURL(cfRequest, url.get());
114         CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get());
115         CFURLRequestSetCachePolicy(cfRequest, (CFURLRequestCachePolicy)cachePolicy());
116         CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval());
117     } else {
118         cfRequest = CFURLRequestCreateMutable(0, url.get(), (CFURLRequestCachePolicy)cachePolicy(), timeoutInterval(), firstPartyForCookies.get());
119     }
120
121     RetainPtr<CFStringRef> requestMethod(AdoptCF, httpMethod().createCFString());
122     CFURLRequestSetHTTPRequestMethod(cfRequest, requestMethod.get());
123
124     setHeaderFields(cfRequest, httpHeaderFields());
125     WebCore::setHTTPBody(cfRequest, httpBody());
126     CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies());
127
128     unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size();
129     RetainPtr<CFMutableArrayRef> encodingFallbacks(AdoptCF, CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0));
130     for (unsigned i = 0; i != fallbackCount; ++i) {
131         RetainPtr<CFStringRef> encodingName(AdoptCF, m_responseContentDispositionEncodingFallbackArray[i].createCFString());
132         CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get());
133         if (encoding != kCFStringEncodingInvalidId)
134             CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding));
135     }
136     setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get());
137
138     if (m_cfRequest) {
139         RetainPtr<CFHTTPCookieStorageRef> cookieStorage(AdoptCF, CFURLRequestCopyHTTPCookieStorage(m_cfRequest.get()));
140         if (cookieStorage)
141             CFURLRequestSetHTTPCookieStorage(cfRequest, cookieStorage.get());
142         CFURLRequestSetHTTPCookieStorageAcceptPolicy(cfRequest, CFURLRequestGetHTTPCookieStorageAcceptPolicy(m_cfRequest.get()));
143         CFURLRequestSetSSLProperties(cfRequest, CFURLRequestGetSSLProperties(m_cfRequest.get()));
144     }
145
146     m_cfRequest.adoptCF(cfRequest);
147 }
148
149 void ResourceRequest::doUpdateResourceRequest()
150 {
151     if (!m_cfRequest) {
152         *this = ResourceRequest();
153         return;
154     }
155
156     m_url = CFURLRequestGetURL(m_cfRequest.get());
157
158     m_cachePolicy = (ResourceRequestCachePolicy)CFURLRequestGetCachePolicy(m_cfRequest.get());
159     m_timeoutInterval = CFURLRequestGetTimeoutInterval(m_cfRequest.get());
160     m_firstPartyForCookies = CFURLRequestGetMainDocumentURL(m_cfRequest.get());
161     if (CFStringRef method = CFURLRequestCopyHTTPRequestMethod(m_cfRequest.get())) {
162         m_httpMethod = method;
163         CFRelease(method);
164     }
165     m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get());
166
167     m_httpHeaderFields.clear();
168     if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) {
169         CFIndex headerCount = CFDictionaryGetCount(headers);
170         Vector<const void*, 128> keys(headerCount);
171         Vector<const void*, 128> values(headerCount);
172         CFDictionaryGetKeysAndValues(headers, keys.data(), values.data());
173         for (int i = 0; i < headerCount; ++i)
174             m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]);
175         CFRelease(headers);
176     }
177
178     m_responseContentDispositionEncodingFallbackArray.clear();
179     RetainPtr<CFArrayRef> encodingFallbacks(AdoptCF, copyContentDispositionEncodingFallbackArray(m_cfRequest.get()));
180     if (encodingFallbacks) {
181         CFIndex count = CFArrayGetCount(encodingFallbacks.get());
182         for (CFIndex i = 0; i < count; ++i) {
183             CFStringEncoding encoding = reinterpret_cast<CFIndex>(CFArrayGetValueAtIndex(encodingFallbacks.get(), i));
184             if (encoding != kCFStringEncodingInvalidId)
185                 m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding));
186         }
187     }
188
189     m_httpBody = httpBodyFromRequest(m_cfRequest.get());
190 }
191
192 unsigned initializeMaximumHTTPConnectionCountPerHost()
193 {
194     static const unsigned preferredConnectionCount = 6;
195     return wkInitializeMaximumHTTPConnectionCountPerHost(preferredConnectionCount);
196 }
197
198 } // namespace WebCore
199
200 #endif // USE(CFNETWORK)