[CF] Replace CFNetwork-related WebKitSystemInterface calls with SPI
[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 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 "ResourceHandleCFURLConnectionDelegate.h"
28
29 #if USE(CFNETWORK)
30
31 #include "FormDataStreamCFNet.h"
32 #include "NetworkingContext.h"
33 #include "ResourceHandle.h"
34
35 #if PLATFORM(COCOA)
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 const void* ResourceHandleCFURLConnectionDelegate::retain(const void* clientInfo)
60 {
61     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->ref();
62     return clientInfo;
63 }
64
65 void ResourceHandleCFURLConnectionDelegate::release(const void* clientInfo)
66 {
67     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->deref();
68 }
69
70 CFURLRequestRef ResourceHandleCFURLConnectionDelegate::willSendRequestCallback(CFURLConnectionRef, CFURLRequestRef cfRequest, CFURLResponseRef originalRedirectResponse, const void* clientInfo)
71 {
72     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->willSendRequest(cfRequest, originalRedirectResponse);
73 }
74
75 void ResourceHandleCFURLConnectionDelegate::didReceiveResponseCallback(CFURLConnectionRef connection, CFURLResponseRef cfResponse, const void* clientInfo)
76 {
77     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveResponse(connection, cfResponse);
78 }
79
80 void ResourceHandleCFURLConnectionDelegate::didReceiveDataCallback(CFURLConnectionRef, CFDataRef data, CFIndex originalLength, const void* clientInfo)
81 {
82     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveData(data, originalLength);
83 }
84
85 void ResourceHandleCFURLConnectionDelegate::didFinishLoadingCallback(CFURLConnectionRef, const void* clientInfo)
86 {
87     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didFinishLoading();
88 }
89
90 void ResourceHandleCFURLConnectionDelegate::didFailCallback(CFURLConnectionRef, CFErrorRef error, const void* clientInfo)
91 {
92     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didFail(error);
93 }
94
95 CFCachedURLResponseRef ResourceHandleCFURLConnectionDelegate::willCacheResponseCallback(CFURLConnectionRef, CFCachedURLResponseRef cachedResponse, const void* clientInfo)
96 {
97     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->willCacheResponse(cachedResponse);
98 }
99
100 void ResourceHandleCFURLConnectionDelegate::didReceiveChallengeCallback(CFURLConnectionRef, CFURLAuthChallengeRef challenge, const void* clientInfo)
101 {
102     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveChallenge(challenge);
103 }
104
105 void ResourceHandleCFURLConnectionDelegate::didSendBodyDataCallback(CFURLConnectionRef, CFIndex, CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite, const void *clientInfo)
106 {
107     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didSendBodyData(totalBytesWritten, totalBytesExpectedToWrite);
108 }
109
110 Boolean ResourceHandleCFURLConnectionDelegate::shouldUseCredentialStorageCallback(CFURLConnectionRef, const void* clientInfo)
111 {
112     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->shouldUseCredentialStorage();
113
114 }
115
116 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
117 Boolean ResourceHandleCFURLConnectionDelegate::canRespondToProtectionSpaceCallback(CFURLConnectionRef, CFURLProtectionSpaceRef protectionSpace, const void* clientInfo)
118 {
119     return static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->canRespondToProtectionSpace(protectionSpace);
120 }
121 #endif // USE(PROTECTION_SPACE_AUTH_CALLBACK)
122
123 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
124 void ResourceHandleCFURLConnectionDelegate::didReceiveDataArrayCallback(CFURLConnectionRef, CFArrayRef dataArray, const void* clientInfo)
125 {
126     static_cast<ResourceHandleCFURLConnectionDelegate*>(const_cast<void*>(clientInfo))->didReceiveDataArray(dataArray);
127 }
128 #endif // USE(NETWORK_CFDATA_ARRAY_CALLBACK)
129
130 RetainPtr<CFURLResponseRef> ResourceHandleCFURLConnectionDelegate::synthesizeRedirectResponseIfNecessary(CFURLRequestRef newRequest, CFURLResponseRef cfRedirectResponse)
131 {
132     if (cfRedirectResponse)
133         return cfRedirectResponse;
134
135     CFURLRef newURL = CFURLRequestGetURL(newRequest);
136     RetainPtr<CFStringRef> newScheme = adoptCF(CFURLCopyScheme(newURL));
137
138     // 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.
139     const ResourceRequest& currentRequest = m_handle->currentRequest();
140     if (currentRequest.url().protocol() == String(newScheme.get()))
141         return nullptr;
142
143     RetainPtr<CFURLRef> currentURL = currentRequest.url().createCFURL();
144     RetainPtr<CFHTTPMessageRef> responseMessage = adoptCF(CFHTTPMessageCreateResponse(0, 302, 0, kCFHTTPVersion1_1));
145     RetainPtr<CFURLRef> newAbsoluteURL = adoptCF(CFURLCopyAbsoluteURL(newURL));
146     CFHTTPMessageSetHeaderFieldValue(responseMessage.get(), CFSTR("Location"), CFURLGetString(newAbsoluteURL.get()));
147     CFHTTPMessageSetHeaderFieldValue(responseMessage.get(), CFSTR("Cache-Control"), CFSTR("no-store"));
148
149     RetainPtr<CFURLResponseRef> newResponse = adoptCF(CFURLResponseCreateWithHTTPResponse(0, currentURL.get(), responseMessage.get(), kCFURLCacheStorageNotAllowed));
150     return newResponse;
151 }
152
153 ResourceRequest ResourceHandleCFURLConnectionDelegate::createResourceRequest(CFURLRequestRef cfRequest, CFURLResponseRef redirectResponse)
154 {
155     ResourceRequest request;
156     CFHTTPMessageRef httpMessage = CFURLResponseGetHTTPResponse(redirectResponse);
157     if (httpMessage && CFHTTPMessageGetResponseStatusCode(httpMessage) == 307) {
158         RetainPtr<CFStringRef> lastHTTPMethod = m_handle->lastHTTPMethod().createCFString();
159         RetainPtr<CFStringRef> newMethod = adoptCF(CFURLRequestCopyHTTPRequestMethod(cfRequest));
160         if (CFStringCompareWithOptions(lastHTTPMethod.get(), newMethod.get(), CFRangeMake(0, CFStringGetLength(lastHTTPMethod.get())), kCFCompareCaseInsensitive)) {
161             auto mutableRequest = adoptCF(CFURLRequestCreateMutableCopy(kCFAllocatorDefault, cfRequest));
162             if (auto storageSession = m_handle->storageSession())
163                 _CFURLRequestSetStorageSession(mutableRequest.get(), storageSession);
164             CFURLRequestSetHTTPRequestMethod(mutableRequest.get(), lastHTTPMethod.get());
165
166             FormData* body = m_handle->firstRequest().httpBody();
167             if (!equalIgnoringCase(m_handle->firstRequest().httpMethod(), "GET") && body && !body->isEmpty())
168                 WebCore::setHTTPBody(mutableRequest.get(), body);
169
170             String originalContentType = m_handle->firstRequest().httpContentType();
171             if (!originalContentType.isEmpty())
172                 CFURLRequestSetHTTPHeaderFieldValue(mutableRequest.get(), CFSTR("Content-Type"), originalContentType.createCFString().get());
173
174             request = mutableRequest.get();
175         }
176     }
177
178     if (request.isNull())
179         request = cfRequest;
180
181     if (!request.url().protocolIs("https") && protocolIs(request.httpReferrer(), "https") && m_handle->context()->shouldClearReferrerOnHTTPSToHTTPRedirect())
182         request.clearHTTPReferrer();
183     return request;
184 }
185
186 CFURLConnectionClient_V6 ResourceHandleCFURLConnectionDelegate::makeConnectionClient() const
187 {
188     CFURLConnectionClient_V6 client = { 6, this,
189         &ResourceHandleCFURLConnectionDelegate::retain,
190         &ResourceHandleCFURLConnectionDelegate::release,
191         0, // copyDescription
192         &ResourceHandleCFURLConnectionDelegate::willSendRequestCallback,
193         &ResourceHandleCFURLConnectionDelegate::didReceiveResponseCallback,
194         &ResourceHandleCFURLConnectionDelegate::didReceiveDataCallback,
195         0,
196         &ResourceHandleCFURLConnectionDelegate::didFinishLoadingCallback,
197         &ResourceHandleCFURLConnectionDelegate::didFailCallback,
198         &ResourceHandleCFURLConnectionDelegate::willCacheResponseCallback,
199         &ResourceHandleCFURLConnectionDelegate::didReceiveChallengeCallback,
200         &ResourceHandleCFURLConnectionDelegate::didSendBodyDataCallback,
201         &ResourceHandleCFURLConnectionDelegate::shouldUseCredentialStorageCallback,
202         0,
203 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
204         &ResourceHandleCFURLConnectionDelegate::canRespondToProtectionSpaceCallback,
205 #else
206         0,
207 #endif
208         0,
209 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
210         &ResourceHandleCFURLConnectionDelegate::didReceiveDataArrayCallback
211 #else
212         0
213 #endif
214     };
215     return client;
216 }
217
218 } // namespace WebCore.
219
220 #endif // USE(CFNETWORK)