c2379043782979f720a30e303eb02247b73a6e60
[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 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 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 "HTTPHeaderNames.h"
30 #include "ResourceRequest.h"
31 #include <pal/spi/cf/CFNetworkSPI.h>
32 #include <wtf/cf/TypeCastsCF.h>
33
34 #if ENABLE(PUBLIC_SUFFIX_LIST)
35 #include "PublicSuffix.h"
36 #endif
37
38 #if USE(CFURLCONNECTION)
39 #include "FormDataStreamCFNet.h"
40 #include <CFNetwork/CFURLRequestPriv.h>
41 #include <wtf/text/CString.h>
42 #endif
43
44 #if PLATFORM(COCOA)
45 #include "ResourceLoadPriority.h"
46 #include <dlfcn.h>
47 #endif
48
49 WTF_DECLARE_CF_TYPE_TRAIT(CFURL);
50
51 namespace WebCore {
52
53 // FIXME: Make this a NetworkingContext property.
54 #if PLATFORM(IOS_FAMILY)
55 bool ResourceRequest::s_httpPipeliningEnabled = true;
56 #else
57 bool ResourceRequest::s_httpPipeliningEnabled = false;
58 #endif
59
60 #if USE(CFURLCONNECTION)
61
62 typedef void (*CFURLRequestSetContentDispositionEncodingFallbackArrayFunction)(CFMutableURLRequestRef, CFArrayRef);
63 typedef CFArrayRef (*CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction)(CFURLRequestRef);
64
65 #if PLATFORM(WIN)
66 static HMODULE findCFNetworkModule()
67 {
68 #ifndef DEBUG_ALL
69     return GetModuleHandleA("CFNetwork");
70 #else
71     return GetModuleHandleA("CFNetwork_debug");
72 #endif
73 }
74
75 static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction()
76 {
77     return reinterpret_cast<CFURLRequestSetContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestSetContentDispositionEncodingFallbackArray"));
78 }
79
80 static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction()
81 {
82     return reinterpret_cast<CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction>(GetProcAddress(findCFNetworkModule(), "_CFURLRequestCopyContentDispositionEncodingFallbackArray"));
83 }
84 #endif
85
86 static void setContentDispositionEncodingFallbackArray(CFMutableURLRequestRef request, CFArrayRef fallbackArray)
87 {
88     static CFURLRequestSetContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestSetContentDispositionEncodingFallbackArrayFunction();
89     if (function)
90         function(request, fallbackArray);
91 }
92
93 static CFArrayRef copyContentDispositionEncodingFallbackArray(CFURLRequestRef request)
94 {
95     static CFURLRequestCopyContentDispositionEncodingFallbackArrayFunction function = findCFURLRequestCopyContentDispositionEncodingFallbackArrayFunction();
96     if (!function)
97         return 0;
98     return function(request);
99 }
100
101 CFURLRequestRef ResourceRequest::cfURLRequest(HTTPBodyUpdatePolicy bodyPolicy) const
102 {
103     updatePlatformRequest(bodyPolicy);
104
105     return m_cfRequest.get();
106 }
107
108 static inline void setHeaderFields(CFMutableURLRequestRef request, const HTTPHeaderMap& requestHeaders) 
109 {
110     // Remove existing headers first, as some of them may no longer be present in the map.
111     RetainPtr<CFDictionaryRef> oldHeaderFields = adoptCF(CFURLRequestCopyAllHTTPHeaderFields(request));
112     CFIndex oldHeaderFieldCount = CFDictionaryGetCount(oldHeaderFields.get());
113     if (oldHeaderFieldCount) {
114         Vector<CFStringRef> oldHeaderFieldNames(oldHeaderFieldCount);
115         CFDictionaryGetKeysAndValues(oldHeaderFields.get(), reinterpret_cast<const void**>(&oldHeaderFieldNames[0]), 0);
116         for (CFIndex i = 0; i < oldHeaderFieldCount; ++i)
117             CFURLRequestSetHTTPHeaderFieldValue(request, oldHeaderFieldNames[i], 0);
118     }
119
120     for (const auto& header : requestHeaders)
121         CFURLRequestSetHTTPHeaderFieldValue(request, header.key.createCFString().get(), header.value.createCFString().get());
122 }
123
124 static inline CFURLRequestCachePolicy toPlatformRequestCachePolicy(ResourceRequestCachePolicy policy)
125 {
126     switch (policy) {
127     case ResourceRequestCachePolicy::UseProtocolCachePolicy:
128         return kCFURLRequestCachePolicyProtocolDefault;
129     case ResourceRequestCachePolicy::ReturnCacheDataElseLoad:
130         return kCFURLRequestCachePolicyReturnCacheDataElseLoad;
131     case ResourceRequestCachePolicy::ReturnCacheDataDontLoad:
132         return kCFURLRequestCachePolicyReturnCacheDataDontLoad;
133     case ResourceRequestCachePolicy::ReloadIgnoringCacheData:
134     case ResourceRequestCachePolicy::DoNotUseAnyCache:
135     case ResourceRequestCachePolicy::RefreshAnyCacheData:
136         return kCFURLRequestCachePolicyReloadIgnoringCache;
137     }
138
139     ASSERT_NOT_REACHED();
140     return kCFURLRequestCachePolicyReloadIgnoringCache;
141 }
142
143 static inline ResourceRequestCachePolicy fromPlatformRequestCachePolicy(CFURLRequestCachePolicy policy)
144 {
145     switch (policy) {
146     case kCFURLRequestCachePolicyProtocolDefault:
147         return ResourceRequestCachePolicy::UseProtocolCachePolicy;
148     case kCFURLRequestCachePolicyReloadIgnoringCache:
149         return ResourceRequestCachePolicy::ReloadIgnoringCacheData;
150     case kCFURLRequestCachePolicyReturnCacheDataElseLoad:
151         return ResourceRequestCachePolicy::ReturnCacheDataElseLoad;
152     case kCFURLRequestCachePolicyReturnCacheDataDontLoad:
153         return ResourceRequestCachePolicy::ReturnCacheDataDontLoad;
154     default:
155         return ResourceRequestCachePolicy::ReloadIgnoringCacheData;
156     }
157 }
158
159 #if PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000
160 static CFURLRef siteForCookies(ResourceRequest::SameSiteDisposition disposition, CFURLRef url)
161 {
162     switch (disposition) {
163     case ResourceRequest::SameSiteDisposition::Unspecified:
164         return { };
165     case ResourceRequest::SameSiteDisposition::SameSite:
166         return url;
167     case ResourceRequest::SameSiteDisposition::CrossSite:
168         static CFURLRef emptyURL = CFURLCreateWithString(nullptr, CFSTR(""), nullptr);
169         return emptyURL;
170     }
171 }
172 #endif
173
174 void ResourceRequest::doUpdatePlatformRequest()
175 {
176     CFMutableURLRequestRef cfRequest;
177
178     RetainPtr<CFURLRef> url = ResourceRequest::url().createCFURL();
179     RetainPtr<CFURLRef> firstPartyForCookies = ResourceRequest::firstPartyForCookies().createCFURL();
180     double timeoutInterval = ResourceRequestBase::timeoutInterval() ? ResourceRequestBase::timeoutInterval() : ResourceRequestBase::defaultTimeoutInterval();
181     if (m_cfRequest) {
182         cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
183         CFURLRequestSetURL(cfRequest, url.get());
184         CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get());
185         CFURLRequestSetCachePolicy(cfRequest, toPlatformRequestCachePolicy(cachePolicy()));
186         CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval);
187     } else
188         cfRequest = CFURLRequestCreateMutable(0, url.get(), toPlatformRequestCachePolicy(cachePolicy()), timeoutInterval, firstPartyForCookies.get());
189
190     CFURLRequestSetHTTPRequestMethod(cfRequest, httpMethod().createCFString().get());
191
192     if (httpPipeliningEnabled())
193         CFURLRequestSetShouldPipelineHTTP(cfRequest, true, true);
194
195     if (resourcePrioritiesEnabled())
196         CFURLRequestSetRequestPriority(cfRequest, toPlatformRequestPriority(priority()));
197
198     setHeaderFields(cfRequest, httpHeaderFields());
199
200     CFURLRequestSetShouldHandleHTTPCookies(cfRequest, allowCookies());
201
202 #if PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000
203     _CFURLRequestSetProtocolProperty(cfRequest, CFSTR("_kCFHTTPCookiePolicyPropertySiteForCookies"), siteForCookies(m_sameSiteDisposition, url.get()));
204
205     int isTopSite = m_isTopSite;
206     RetainPtr<CFNumberRef> isTopSiteCF = adoptCF(CFNumberCreate(nullptr, kCFNumberIntType, &isTopSite));
207     _CFURLRequestSetProtocolProperty(cfRequest, CFSTR("_kCFHTTPCookiePolicyPropertyisTopSite"), isTopSiteCF.get());
208 #endif
209
210     unsigned fallbackCount = m_responseContentDispositionEncodingFallbackArray.size();
211     RetainPtr<CFMutableArrayRef> encodingFallbacks = adoptCF(CFArrayCreateMutable(kCFAllocatorDefault, fallbackCount, 0));
212     for (unsigned i = 0; i != fallbackCount; ++i) {
213         RetainPtr<CFStringRef> encodingName = m_responseContentDispositionEncodingFallbackArray[i].createCFString();
214         CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding(encodingName.get());
215         if (encoding != kCFStringEncodingInvalidId)
216             CFArrayAppendValue(encodingFallbacks.get(), reinterpret_cast<const void*>(encoding));
217     }
218     setContentDispositionEncodingFallbackArray(cfRequest, encodingFallbacks.get());
219
220 #if ENABLE(CACHE_PARTITIONING)
221     String partition = cachePartition();
222     if (!partition.isNull() && !partition.isEmpty()) {
223         CString utf8String = partition.utf8();
224         RetainPtr<CFStringRef> partitionValue = adoptCF(CFStringCreateWithBytes(0, reinterpret_cast<const UInt8*>(utf8String.data()), utf8String.length(), kCFStringEncodingUTF8, false));
225         _CFURLRequestSetProtocolProperty(cfRequest, _kCFURLCachePartitionKey, partitionValue.get());
226     }
227 #endif
228
229     m_cfRequest = adoptCF(cfRequest);
230 }
231
232 void ResourceRequest::doUpdatePlatformHTTPBody()
233 {
234     CFMutableURLRequestRef cfRequest;
235
236     RetainPtr<CFURLRef> url = ResourceRequest::url().createCFURL();
237     RetainPtr<CFURLRef> firstPartyForCookies = ResourceRequest::firstPartyForCookies().createCFURL();
238     double timeoutInterval = ResourceRequestBase::timeoutInterval() ? ResourceRequestBase::timeoutInterval() : ResourceRequestBase::defaultTimeoutInterval();
239     if (m_cfRequest) {
240         cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
241         CFURLRequestSetURL(cfRequest, url.get());
242         CFURLRequestSetMainDocumentURL(cfRequest, firstPartyForCookies.get());
243         CFURLRequestSetCachePolicy(cfRequest, toPlatformRequestCachePolicy(cachePolicy()));
244         CFURLRequestSetTimeoutInterval(cfRequest, timeoutInterval);
245     } else
246         cfRequest = CFURLRequestCreateMutable(0, url.get(), toPlatformRequestCachePolicy(cachePolicy()), timeoutInterval, firstPartyForCookies.get());
247
248     FormData* formData = httpBody();
249     if (formData && !formData->isEmpty())
250         WebCore::setHTTPBody(cfRequest, formData);
251
252     if (RetainPtr<CFReadStreamRef> bodyStream = adoptCF(CFURLRequestCopyHTTPRequestBodyStream(cfRequest))) {
253         // For streams, provide a Content-Length to avoid using chunked encoding, and to get accurate total length in callbacks.
254         if (RetainPtr<CFStringRef> lengthString = adoptCF(static_cast<CFStringRef>(CFReadStreamCopyProperty(bodyStream.get(), formDataStreamLengthPropertyName())))) {
255             CFURLRequestSetHTTPHeaderFieldValue(cfRequest, CFSTR("Content-Length"), lengthString.get());
256             // Since resource request is already marked updated, we need to keep it up to date too.
257             ASSERT(m_resourceRequestUpdated);
258             m_httpHeaderFields.set(HTTPHeaderName::ContentLength, lengthString.get());
259         }
260     }
261
262     m_cfRequest = adoptCF(cfRequest);
263 }
264
265 void ResourceRequest::doUpdateResourceRequest()
266 {
267     if (!m_cfRequest) {
268         *this = ResourceRequest();
269         return;
270     }
271
272     m_url = CFURLRequestGetURL(m_cfRequest.get());
273
274     if (m_cachePolicy == ResourceRequestCachePolicy::UseProtocolCachePolicy)
275         m_cachePolicy = fromPlatformRequestCachePolicy(CFURLRequestGetCachePolicy(m_cfRequest.get()));
276     m_timeoutInterval = CFURLRequestGetTimeoutInterval(m_cfRequest.get());
277     m_firstPartyForCookies = CFURLRequestGetMainDocumentURL(m_cfRequest.get());
278     if (CFStringRef method = CFURLRequestCopyHTTPRequestMethod(m_cfRequest.get())) {
279         m_httpMethod = method;
280         CFRelease(method);
281     }
282     m_allowCookies = CFURLRequestShouldHandleHTTPCookies(m_cfRequest.get());
283
284     if (resourcePrioritiesEnabled())
285         m_priority = toResourceLoadPriority(CFURLRequestGetRequestPriority(m_cfRequest.get()));
286
287 #if PLATFORM(IOS_FAMILY) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 120000
288     RetainPtr<CFURLRef> siteForCookies = adoptCF(checked_cf_cast<CFURLRef>(_CFURLRequestCopyProtocolPropertyForKey(m_cfRequest.get(), CFSTR("_kCFHTTPCookiePolicyPropertySiteForCookies"))));
289     m_sameSiteDisposition = !siteForCookies ? SameSiteDisposition::Unspecified : (registrableDomainsAreEqual(siteForCookies.get(), m_url) ? SameSiteDisposition::SameSite : SameSiteDisposition::CrossSite);
290
291     RetainPtr<CFNumberRef> isTopSiteCF = adoptCF(checked_cf_cast<CFNumber>(_CFURLRequestCopyProtocolPropertyForKey(m_cfRequest.get(), CFSTR("_kCFHTTPCookiePolicyPropertyisTopSite"))));
292     if (!isTopSiteCF)
293         m_isTopSite = false;
294     else {
295         int isTopSite = 0;
296         CFNumberGetValue(isTopSiteCF.get(), kCFNumberIntType, &isTopSite);
297         m_isTopSite = isTopSite;
298     }
299 #endif
300
301     m_httpHeaderFields.clear();
302     if (CFDictionaryRef headers = CFURLRequestCopyAllHTTPHeaderFields(m_cfRequest.get())) {
303         CFIndex headerCount = CFDictionaryGetCount(headers);
304         Vector<const void*, 128> keys(headerCount);
305         Vector<const void*, 128> values(headerCount);
306         CFDictionaryGetKeysAndValues(headers, keys.data(), values.data());
307         for (int i = 0; i < headerCount; ++i)
308             m_httpHeaderFields.set((CFStringRef)keys[i], (CFStringRef)values[i]);
309         CFRelease(headers);
310     }
311
312     m_responseContentDispositionEncodingFallbackArray.clear();
313     RetainPtr<CFArrayRef> encodingFallbacks = adoptCF(copyContentDispositionEncodingFallbackArray(m_cfRequest.get()));
314     if (encodingFallbacks) {
315         CFIndex count = CFArrayGetCount(encodingFallbacks.get());
316         for (CFIndex i = 0; i < count; ++i) {
317             CFStringEncoding encoding = reinterpret_cast<CFIndex>(CFArrayGetValueAtIndex(encodingFallbacks.get(), i));
318             if (encoding != kCFStringEncodingInvalidId)
319                 m_responseContentDispositionEncodingFallbackArray.append(CFStringConvertEncodingToIANACharSetName(encoding));
320         }
321     }
322
323 #if ENABLE(CACHE_PARTITIONING)
324     RetainPtr<CFStringRef> cachePartition = adoptCF(static_cast<CFStringRef>(_CFURLRequestCopyProtocolPropertyForKey(m_cfRequest.get(), _kCFURLCachePartitionKey)));
325     if (cachePartition)
326         m_cachePartition = cachePartition.get();
327 #endif
328 }
329
330 void ResourceRequest::doUpdateResourceHTTPBody()
331 {
332     if (!m_cfRequest) {
333         m_httpBody = nullptr;
334         return;
335     }
336
337     if (RetainPtr<CFDataRef> bodyData = adoptCF(CFURLRequestCopyHTTPRequestBody(m_cfRequest.get())))
338         m_httpBody = FormData::create(CFDataGetBytePtr(bodyData.get()), CFDataGetLength(bodyData.get()));
339     else if (RetainPtr<CFReadStreamRef> bodyStream = adoptCF(CFURLRequestCopyHTTPRequestBodyStream(m_cfRequest.get()))) {
340         FormData* formData = httpBodyFromStream(bodyStream.get());
341         // There is no FormData object if a client provided a custom data stream.
342         // We shouldn't be looking at http body after client callbacks.
343         ASSERT(formData);
344         if (formData)
345             m_httpBody = formData;
346     }
347 }
348
349
350 void ResourceRequest::setStorageSession(CFURLStorageSessionRef storageSession)
351 {
352     updatePlatformRequest();
353
354     auto cfRequest = CFURLRequestCreateMutableCopy(0, m_cfRequest.get());
355     if (storageSession)
356         _CFURLRequestSetStorageSession(cfRequest, storageSession);
357     m_cfRequest = adoptCF(cfRequest);
358 }
359
360 #endif // USE(CFURLCONNECTION)
361
362 void ResourceRequest::updateFromDelegatePreservingOldProperties(const ResourceRequest& delegateProvidedRequest)
363 {
364     // These are things we don't want willSendRequest delegate to mutate or reset.
365     ResourceLoadPriority oldPriority = priority();
366     RefPtr<FormData> oldHTTPBody = httpBody();
367     bool isHiddenFromInspector = hiddenFromInspector();
368     auto oldRequester = requester();
369     auto oldInitiatorIdentifier = initiatorIdentifier();
370     auto oldInspectorInitiatorNodeIdentifier = inspectorInitiatorNodeIdentifier();
371
372     *this = delegateProvidedRequest;
373
374     setPriority(oldPriority);
375     setHTTPBody(WTFMove(oldHTTPBody));
376     setHiddenFromInspector(isHiddenFromInspector);
377     setRequester(oldRequester);
378     setInitiatorIdentifier(oldInitiatorIdentifier);
379     if (oldInspectorInitiatorNodeIdentifier)
380         setInspectorInitiatorNodeIdentifier(*oldInspectorInitiatorNodeIdentifier);
381 }
382
383 bool ResourceRequest::httpPipeliningEnabled()
384 {
385     return s_httpPipeliningEnabled;
386 }
387
388 void ResourceRequest::setHTTPPipeliningEnabled(bool flag)
389 {
390     s_httpPipeliningEnabled = flag;
391 }
392
393 // FIXME: It is confusing that this function both sets connection count and determines maximum request count at network layer. This can and should be done separately.
394 unsigned initializeMaximumHTTPConnectionCountPerHost()
395 {
396     static const unsigned preferredConnectionCount = 6;
397     static const unsigned unlimitedRequestCount = 10000;
398
399     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPLoadWidth, preferredConnectionCount);
400     unsigned maximumHTTPConnectionCountPerHost = _CFNetworkHTTPConnectionCacheGetLimit(kHTTPLoadWidth);
401
402     Boolean keyExistsAndHasValidFormat = false;
403     Boolean prefValue = CFPreferencesGetAppBooleanValue(CFSTR("WebKitEnableHTTPPipelining"), kCFPreferencesCurrentApplication, &keyExistsAndHasValidFormat);
404     if (keyExistsAndHasValidFormat)
405         ResourceRequest::setHTTPPipeliningEnabled(prefValue);
406
407     // Use WebCore scheduler when we can't use request priorities with CFNetwork.
408     if (!ResourceRequest::resourcePrioritiesEnabled())
409         return maximumHTTPConnectionCountPerHost;
410
411     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPPriorityNumLevels, toPlatformRequestPriority(ResourceLoadPriority::Highest));
412 #if !PLATFORM(WIN)
413     // FIXME: <rdar://problem/9375609> Implement minimum fast lane priority setting on Windows
414     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPMinimumFastLanePriority, toPlatformRequestPriority(ResourceLoadPriority::Medium));
415 #endif
416
417     return unlimitedRequestCount;
418 }
419
420 #if PLATFORM(IOS_FAMILY)
421 void initializeHTTPConnectionSettingsOnStartup()
422 {
423     // This need to be called from WebKitInitialize so the calls happen early enough, before any requests are made. <rdar://problem/9691871>
424     // Desktop doesn't have early initialization so it is not clear how this should be done there. The CFNetwork SPI probably
425     // needs to become more forgiving.
426     // We can't read settings here as this is called too early for that. All values need to be constants.
427     static const unsigned preferredConnectionCount = 6;
428     static const unsigned fastLaneConnectionCount = 1;
429     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPLoadWidth, preferredConnectionCount);
430     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPPriorityNumLevels, toPlatformRequestPriority(ResourceLoadPriority::Highest));
431     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPMinimumFastLanePriority, toPlatformRequestPriority(ResourceLoadPriority::Medium));
432     _CFNetworkHTTPConnectionCacheSetLimit(kHTTPNumFastLanes, fastLaneConnectionCount);
433 }
434 #endif
435
436 #if PLATFORM(COCOA)
437 CFStringRef ResourceRequest::isUserInitiatedKey()
438 {
439     static CFStringRef key = CFSTR("ResourceRequestIsUserInitiatedKey");
440     return key;
441 }
442 #endif
443
444 } // namespace WebCore