Add the CFNetwork implementation of the asynchronous ResourceHandle
[WebKit-https.git] / Source / WebCore / platform / network / cf / ResourceHandleCFURLConnectionDelegate.cpp
1 /*
2  * Copyright (C) 2004-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 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 "ResourceHandleCFURLConnectionDelegate.h"
28
29 #if USE(CFNETWORK)
30
31 #include "FormDataStreamCFNet.h"
32 #include "NetworkingContext.h"
33 #include "ResourceHandle.h"
34
35 #if PLATFORM(MAC)
36 #include "WebCoreSystemInterface.h"
37 #endif
38
39 #if PLATFORM(WIN)
40 #include <WebKitSystemInterface/WebKitSystemInterface.h>
41 #endif
42
43 namespace WebCore {
44
45 ResourceHandleCFURLConnectionDelegate::ResourceHandleCFURLConnectionDelegate(ResourceHandle* handle)
46     : m_handle(handle)
47 {
48 }
49
50 ResourceHandleCFURLConnectionDelegate::~ResourceHandleCFURLConnectionDelegate()
51 {
52 }
53
54 void ResourceHandleCFURLConnectionDelegate::releaseHandle()
55 {
56     m_handle = nullptr;
57 }
58
59 CFURLRequestRef ResourceHandleCFURLConnectionDelegate::willSendRequestCallback(CFURLConnectionRef, CFURLRequestRef cfRequest, CFURLResponseRef originalRedirectResponse, const void* clientInfo)
60 {
61     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->willSendRequest(cfRequest, originalRedirectResponse);
62 }
63
64 void ResourceHandleCFURLConnectionDelegate::didReceiveResponseCallback(CFURLConnectionRef, CFURLResponseRef cfResponse, const void* clientInfo)
65 {
66     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveResponse(cfResponse);
67 }
68
69 void ResourceHandleCFURLConnectionDelegate::didReceiveDataCallback(CFURLConnectionRef, CFDataRef data, CFIndex originalLength, const void* clientInfo)
70 {
71     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveData(data, originalLength);
72 }
73
74 void ResourceHandleCFURLConnectionDelegate::didFinishLoadingCallback(CFURLConnectionRef, const void* clientInfo)
75 {
76     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didFinishLoading();
77 }
78
79 void ResourceHandleCFURLConnectionDelegate::didFailCallback(CFURLConnectionRef, CFErrorRef error, const void* clientInfo)
80 {
81     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didFail(error);
82 }
83
84 CFCachedURLResponseRef ResourceHandleCFURLConnectionDelegate::willCacheResponseCallback(CFURLConnectionRef, CFCachedURLResponseRef cachedResponse, const void* clientInfo)
85 {
86     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->willCacheResponse(cachedResponse);
87 }
88
89 void ResourceHandleCFURLConnectionDelegate::didReceiveChallengeCallback(CFURLConnectionRef, CFURLAuthChallengeRef challenge, const void* clientInfo)
90 {
91     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveChallenge(challenge);
92 }
93
94 void ResourceHandleCFURLConnectionDelegate::didSendBodyDataCallback(CFURLConnectionRef, CFIndex, CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite, const void *clientInfo)
95 {
96     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didSendBodyData(totalBytesWritten, totalBytesExpectedToWrite);
97 }
98
99 Boolean ResourceHandleCFURLConnectionDelegate::shouldUseCredentialStorageCallback(CFURLConnectionRef, const void* clientInfo)
100 {
101     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->shouldUseCredentialStorage();
102
103 }
104
105 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
106 Boolean ResourceHandleCFURLConnectionDelegate::canRespondToProtectionSpaceCallback(CFURLConnectionRef, CFURLProtectionSpaceRef protectionSpace, const void* clientInfo)
107 {
108     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->canRespondToProtectionSpace(protectionSpace);
109 }
110 #endif // USE(PROTECTION_SPACE_AUTH_CALLBACK)
111
112 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
113 void ResourceHandleCFURLConnectionDelegate::didReceiveDataArrayCallback(CFURLConnectionRef, CFArrayRef dataArray, const void* clientInfo)
114 {
115     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveDataArray(dataArray);
116 }
117 #endif // USE(NETWORK_CFDATA_ARRAY_CALLBACK)
118
119 RetainPtr<CFURLResponseRef> ResourceHandleCFURLConnectionDelegate::synthesizeRedirectResponseIfNecessary(CFURLRequestRef newRequest, CFURLResponseRef cfRedirectResponse)
120 {
121     if (cfRedirectResponse)
122         return cfRedirectResponse;
123
124     CFURLRef newURL = CFURLRequestGetURL(newRequest);
125     RetainPtr<CFStringRef> newScheme = adoptCF(CFURLCopyScheme(newURL));
126
127     // If the protocols of the new request and the current request match, this is not an HSTS redirect and we shouldn't synthesize a redirect response.
128     const ResourceRequest& currentRequest = m_handle->currentRequest();
129     if (currentRequest.url().protocol() == String(newScheme.get()))
130         return nullptr;
131
132     RetainPtr<CFURLRef> currentURL = currentRequest.url().createCFURL();
133     RetainPtr<CFHTTPMessageRef> responseMessage = adoptCF(CFHTTPMessageCreateResponse(0, 302, 0, kCFHTTPVersion1_1));
134     RetainPtr<CFURLRef> newAbsoluteURL = adoptCF(CFURLCopyAbsoluteURL(newURL));
135     CFHTTPMessageSetHeaderFieldValue(responseMessage.get(), CFSTR("Location"), CFURLGetString(newAbsoluteURL.get()));
136     CFHTTPMessageSetHeaderFieldValue(responseMessage.get(), CFSTR("Cache-Control"), CFSTR("no-store"));
137
138     RetainPtr<CFURLResponseRef> newResponse = adoptCF(CFURLResponseCreateWithHTTPResponse(0, currentURL.get(), responseMessage.get(), kCFURLCacheStorageNotAllowed));
139     return newResponse;
140 }
141
142 ResourceRequest ResourceHandleCFURLConnectionDelegate::createResourceRequest(CFURLRequestRef cfRequest, CFURLResponseRef redirectResponse)
143 {
144     ResourceRequest request;
145     CFHTTPMessageRef httpMessage = CFURLResponseGetHTTPResponse(redirectResponse);
146     if (httpMessage && CFHTTPMessageGetResponseStatusCode(httpMessage) == 307) {
147         RetainPtr<CFStringRef> lastHTTPMethod = m_handle->lastHTTPMethod().createCFString();
148         RetainPtr<CFStringRef> newMethod = adoptCF(CFURLRequestCopyHTTPRequestMethod(cfRequest));
149         if (CFStringCompareWithOptions(lastHTTPMethod.get(), newMethod.get(), CFRangeMake(0, CFStringGetLength(lastHTTPMethod.get())), kCFCompareCaseInsensitive)) {
150             RetainPtr<CFMutableURLRequestRef> mutableRequest = adoptCF(CFURLRequestCreateMutableCopy(0, cfRequest));
151             wkSetRequestStorageSession(m_handle->storageSession(), mutableRequest.get());
152             CFURLRequestSetHTTPRequestMethod(mutableRequest.get(), lastHTTPMethod.get());
153
154             FormData* body = m_handle->firstRequest().httpBody();
155             if (!equalIgnoringCase(m_handle->firstRequest().httpMethod(), "GET") && body && !body->isEmpty())
156                 WebCore::setHTTPBody(mutableRequest.get(), body);
157
158             String originalContentType = m_handle->firstRequest().httpContentType();
159             if (!originalContentType.isEmpty())
160                 CFURLRequestSetHTTPHeaderFieldValue(mutableRequest.get(), CFSTR("Content-Type"), originalContentType.createCFString().get());
161
162             request = mutableRequest.get();
163         }
164     }
165
166     if (request.isNull())
167         request = cfRequest;
168
169     if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https") && m_handle->context()->shouldClearReferrerOnHTTPSToHTTPRedirect())
170         request.clearHTTPReferrer();
171     return request;
172 }
173
174 CFURLConnectionClient_V6 ResourceHandleCFURLConnectionDelegate::makeConnectionClient() const
175 {
176     CFURLConnectionClient_V6 client = { 6, this, 0, 0, 0,
177         &ResourceHandleCFURLConnectionDelegate::willSendRequestCallback,
178         &ResourceHandleCFURLConnectionDelegate::didReceiveResponseCallback,
179         &ResourceHandleCFURLConnectionDelegate::didReceiveDataCallback,
180         0,
181         &ResourceHandleCFURLConnectionDelegate::didFinishLoadingCallback,
182         &ResourceHandleCFURLConnectionDelegate::didFailCallback,
183         &ResourceHandleCFURLConnectionDelegate::willCacheResponseCallback,
184         &ResourceHandleCFURLConnectionDelegate::didReceiveChallengeCallback,
185         &ResourceHandleCFURLConnectionDelegate::didSendBodyDataCallback,
186         &ResourceHandleCFURLConnectionDelegate::shouldUseCredentialStorageCallback,
187         0,
188 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
189         &ResourceHandleCFURLConnectionDelegate::canRespondToProtectionSpaceCallback,
190 #else
191         0,
192 #endif
193         0,
194 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
195         &ResourceHandleCFURLConnectionDelegate::didReceiveDataArrayCallback
196 #else
197         0
198 #endif
199     };
200     return client;
201 }
202
203 } // namespace WebCore.
204
205 #endif // USE(CFNETWORK)