Remove dead networking code
[WebKit-https.git] / Source / WebCore / platform / network / cf / ResourceHandleCFURLConnectionDelegateWithOperationQueue.cpp
1 /*
2  * Copyright (C) 2013 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 "ResourceHandleCFURLConnectionDelegateWithOperationQueue.h"
28
29 #if USE(CFURLCONNECTION)
30
31 #include "AuthenticationCF.h"
32 #include "AuthenticationChallenge.h"
33 #include "CFNetworkSPI.h"
34 #include "Logging.h"
35 #include "ResourceHandle.h"
36 #include "ResourceHandleClient.h"
37 #include "ResourceResponse.h"
38 #include "SharedBuffer.h"
39 #include "WebCoreSystemInterface.h"
40 #include "WebCoreURLResponse.h"
41 #include <wtf/MainThread.h>
42 #include <wtf/text/CString.h>
43 #include <wtf/text/WTFString.h>
44
45 namespace WebCore {
46
47 ResourceHandleCFURLConnectionDelegateWithOperationQueue::ResourceHandleCFURLConnectionDelegateWithOperationQueue(ResourceHandle* handle)
48     : ResourceHandleCFURLConnectionDelegate(handle)
49     , m_queue(dispatch_queue_create("com.apple.WebCore/CFNetwork", DISPATCH_QUEUE_SERIAL))
50     , m_semaphore(dispatch_semaphore_create(0))
51 {
52     dispatch_queue_t backgroundQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0);
53     dispatch_set_target_queue(m_queue, backgroundQueue);
54 }
55
56 ResourceHandleCFURLConnectionDelegateWithOperationQueue::~ResourceHandleCFURLConnectionDelegateWithOperationQueue()
57 {
58     dispatch_release(m_semaphore);
59     dispatch_release(m_queue);
60 }
61
62 bool ResourceHandleCFURLConnectionDelegateWithOperationQueue::hasHandle() const
63 {
64     return !!m_handle;
65 }
66
67 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::releaseHandle()
68 {
69     ResourceHandleCFURLConnectionDelegate::releaseHandle();
70     m_requestResult = nullptr;
71     m_cachedResponseResult = nullptr;
72     m_boolResult = false;
73     dispatch_semaphore_signal(m_semaphore);
74 }
75
76 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::setupRequest(CFMutableURLRequestRef request)
77 {
78     CFURLRef requestURL = CFURLRequestGetURL(request);
79     if (!requestURL)
80         return;
81     m_originalScheme = adoptCF(CFURLCopyScheme(requestURL));
82 }
83
84 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::setupConnectionScheduling(CFURLConnectionRef connection)
85 {
86     CFURLConnectionSetDelegateDispatchQueue(connection, m_queue);
87 }
88
89 CFURLRequestRef ResourceHandleCFURLConnectionDelegateWithOperationQueue::willSendRequest(CFURLRequestRef cfRequest, CFURLResponseRef originalRedirectResponse)
90 {
91     // If the protocols of the new request and the current request match, this is not an HSTS redirect and we don't need to synthesize a redirect response.
92     if (!originalRedirectResponse) {
93         RetainPtr<CFStringRef> newScheme = adoptCF(CFURLCopyScheme(CFURLRequestGetURL(cfRequest)));
94         if (CFStringCompare(newScheme.get(), m_originalScheme.get(), kCFCompareCaseInsensitive) == kCFCompareEqualTo) {
95             CFRetain(cfRequest);
96             return cfRequest;
97         }
98     }
99
100     ASSERT(!isMainThread());
101
102     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
103     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
104     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
105
106     dispatch_async(dispatch_get_main_queue(), ^{
107         if (!protectedThis->hasHandle()) {
108             continueWillSendRequest(nullptr);
109             return;
110         }
111
112         LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::willSendRequest(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
113
114         RetainPtr<CFURLResponseRef> redirectResponse = synthesizeRedirectResponseIfNecessary(cfRequest, originalRedirectResponse);
115         ASSERT(redirectResponse);
116
117         ResourceRequest request = createResourceRequest(cfRequest, redirectResponse.get());
118         m_handle->willSendRequest(WTFMove(request), redirectResponse.get());
119     });
120
121     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
122
123     return m_requestResult.leakRef();
124 }
125
126 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveResponse(CFURLConnectionRef connection, CFURLResponseRef cfResponse)
127 {
128     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
129     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
130     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
131
132     dispatch_async(dispatch_get_main_queue(), ^{
133         if (!protectedThis->hasHandle() || !m_handle->client()) {
134             continueDidReceiveResponse();
135             return;
136         }
137
138         LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveResponse(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
139
140         // Avoid MIME type sniffing if the response comes back as 304 Not Modified.
141         auto msg = CFURLResponseGetHTTPResponse(cfResponse);
142         int statusCode = msg ? CFHTTPMessageGetResponseStatusCode(msg) : 0;
143
144         if (statusCode != 304) {
145             bool isMainResourceLoad = m_handle->firstRequest().requester() == ResourceRequest::Requester::Main;
146             adjustMIMETypeIfNecessary(cfResponse, isMainResourceLoad);
147         }
148
149         if (_CFURLRequestCopyProtocolPropertyForKey(m_handle->firstRequest().cfURLRequest(DoNotUpdateHTTPBody), CFSTR("ForceHTMLMIMEType")))
150             CFURLResponseSetMIMEType(cfResponse, CFSTR("text/html"));
151         
152         ResourceResponse resourceResponse(cfResponse);
153 #if ENABLE(WEB_TIMING)
154         ResourceHandle::getConnectionTimingData(connection, resourceResponse.networkLoadTiming());
155 #else
156         UNUSED_PARAM(connection);
157 #endif
158         
159         m_handle->client()->didReceiveResponseAsync(m_handle, WTFMove(resourceResponse));
160     });
161     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
162 }
163
164 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveData(CFDataRef data, CFIndex originalLength)
165 {
166     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
167     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
168     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
169     CFRetain(data);
170
171     dispatch_async(dispatch_get_main_queue(), ^{
172         if (protectedThis->hasHandle() && m_handle->client()) {
173             LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveData(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
174
175             m_handle->client()->didReceiveBuffer(m_handle, SharedBuffer::wrapCFData(data), originalLength);
176         }
177
178         CFRelease(data);
179     });
180 }
181
182 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didFinishLoading()
183 {
184     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
185     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
186     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
187     dispatch_async(dispatch_get_main_queue(), ^{
188         if (!protectedThis->hasHandle() || !m_handle->client())
189             return;
190
191         LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didFinishLoading(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
192
193         m_handle->client()->didFinishLoading(m_handle, 0);
194     });
195 }
196
197 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didFail(CFErrorRef error)
198 {
199     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
200     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
201     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
202     CFRetain(error);
203     dispatch_async(dispatch_get_main_queue(), ^{
204         if (protectedThis->hasHandle() && m_handle->client()) {
205             LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didFail(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
206
207             m_handle->client()->didFail(m_handle, ResourceError(error));
208         }
209
210         CFRelease(error);
211     });
212 }
213
214 CFCachedURLResponseRef ResourceHandleCFURLConnectionDelegateWithOperationQueue::willCacheResponse(CFCachedURLResponseRef cachedResponse)
215 {
216     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
217     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
218     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
219
220     dispatch_async(dispatch_get_main_queue(), ^{
221         if (!protectedThis->hasHandle() || !m_handle->client()) {
222             continueWillCacheResponse(nullptr);
223             return;
224         }
225
226         LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::willCacheResponse(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
227
228         m_handle->client()->willCacheResponseAsync(m_handle, cachedResponse);
229     });
230     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
231     return m_cachedResponseResult.leakRef();
232 }
233
234 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveChallenge(CFURLAuthChallengeRef challenge)
235 {
236     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
237     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
238     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
239     CFRetain(challenge);
240     dispatch_async(dispatch_get_main_queue(), ^{
241         if (protectedThis->hasHandle()) {
242             LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveChallenge(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
243
244             m_handle->didReceiveAuthenticationChallenge(AuthenticationChallenge(challenge, m_handle));
245         }
246
247         CFRelease(challenge);
248     });
249 }
250
251 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didSendBodyData(CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite)
252 {
253     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
254     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
255     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
256     dispatch_async(dispatch_get_main_queue(), ^{
257         if (!protectedThis->hasHandle() || !m_handle->client())
258             return;
259
260         LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didSendBodyData(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
261
262         m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite);
263     });
264 }
265
266 Boolean ResourceHandleCFURLConnectionDelegateWithOperationQueue::shouldUseCredentialStorage()
267 {
268     return NO;
269 }
270
271 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
272 Boolean ResourceHandleCFURLConnectionDelegateWithOperationQueue::canRespondToProtectionSpace(CFURLProtectionSpaceRef protectionSpace)
273 {
274     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
275     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
276     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
277
278     dispatch_async(dispatch_get_main_queue(), ^{
279         if (!protectedThis->hasHandle()) {
280             continueCanAuthenticateAgainstProtectionSpace(false);
281             return;
282         }
283
284         LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::canRespondToProtectionSpace(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
285
286         m_handle->canAuthenticateAgainstProtectionSpace(ProtectionSpace(protectionSpace));
287     });
288     dispatch_semaphore_wait(m_semaphore, DISPATCH_TIME_FOREVER);
289     return m_boolResult;
290 }
291 #endif // USE(PROTECTION_SPACE_AUTH_CALLBACK)
292
293 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
294 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::didReceiveDataArray(CFArrayRef dataArray)
295 {
296     // FIXME: The block implicitly copies protector object, which is wasteful. We should just call ref(),
297     // capture "this" by pointer value, and use a C++ lambda to prevent other unintentional capturing.
298     RefPtr<ResourceHandleCFURLConnectionDelegateWithOperationQueue> protectedThis(this);
299     CFRetain(dataArray);
300     dispatch_async(dispatch_get_main_queue(), ^{
301         if (protectedThis->hasHandle() && m_handle->client()) {
302             LOG(Network, "CFNet - ResourceHandleCFURLConnectionDelegateWithOperationQueue::didSendBodyData(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
303
304             m_handle->client()->didReceiveBuffer(m_handle, SharedBuffer::wrapCFDataArray(dataArray), -1);
305         }
306         CFRelease(dataArray);
307     });
308 }
309 #endif // USE(NETWORK_CFDATA_ARRAY_CALLBACK)
310
311 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::continueWillSendRequest(CFURLRequestRef request)
312 {
313     m_requestResult = request;
314     dispatch_semaphore_signal(m_semaphore);
315 }
316
317 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::continueDidReceiveResponse()
318 {
319     dispatch_semaphore_signal(m_semaphore);
320 }
321
322 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::continueWillCacheResponse(CFCachedURLResponseRef response)
323 {
324     m_cachedResponseResult = response;
325     dispatch_semaphore_signal(m_semaphore);
326 }
327
328 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
329 void ResourceHandleCFURLConnectionDelegateWithOperationQueue::continueCanAuthenticateAgainstProtectionSpace(bool canAuthenticate)
330 {
331     m_boolResult = canAuthenticate;
332     dispatch_semaphore_signal(m_semaphore);
333 }
334 #endif // USE(PROTECTION_SPACE_AUTH_CALLBACK)
335 } // namespace WebCore
336
337 #endif // USE(CFURLCONNECTION)