[WIN] Enable WEB_TIMING API
[WebKit-https.git] / Source / WebCore / platform / network / cf / SynchronousResourceHandleCFURLConnectionDelegate.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 "SynchronousResourceHandleCFURLConnectionDelegate.h"
28
29 #if USE(CFNETWORK)
30
31 #include "AuthenticationCF.h"
32 #include "AuthenticationChallenge.h"
33 #include "LoaderRunLoopCF.h"
34 #include "Logging.h"
35 #include "ResourceHandle.h"
36 #include "ResourceHandleClient.h"
37 #include "ResourceResponse.h"
38 #include "SharedBuffer.h"
39 #include <wtf/RetainPtr.h>
40 #include <wtf/text/CString.h>
41 #include <wtf/text/WTFString.h>
42
43 #if PLATFORM(COCOA)
44 #include "WebCoreSystemInterface.h"
45 #include "WebCoreURLResponse.h"
46 #endif // PLATFORM(COCOA)
47
48 #if PLATFORM(IOS)
49 #include "WebCoreThread.h"
50 #endif // PLATFORM(IOS)
51
52 #if PLATFORM(WIN)
53 #include "MIMETypeRegistry.h"
54 #endif // PLATFORM(WIN)
55
56 namespace WebCore {
57
58 SynchronousResourceHandleCFURLConnectionDelegate::SynchronousResourceHandleCFURLConnectionDelegate(ResourceHandle* handle)
59     : ResourceHandleCFURLConnectionDelegate(handle)
60 {
61 }
62
63 void SynchronousResourceHandleCFURLConnectionDelegate::setupRequest(CFMutableURLRequestRef request)
64 {
65 #if PLATFORM(IOS)
66     CFURLRequestSetShouldStartSynchronously(request, 1);
67 #endif
68 }
69
70 void SynchronousResourceHandleCFURLConnectionDelegate::setupConnectionScheduling(CFURLConnectionRef connection)
71 {
72 #if PLATFORM(WIN)
73     CFURLConnectionScheduleWithCurrentMessageQueue(connection);
74 #elif PLATFORM(IOS)
75     CFURLConnectionScheduleWithRunLoop(connection, WebThreadRunLoop(), kCFRunLoopDefaultMode);
76 #else
77     CFURLConnectionScheduleWithRunLoop(connection, CFRunLoopGetCurrent(), kCFRunLoopDefaultMode);
78 #endif
79     CFURLConnectionScheduleDownloadWithRunLoop(connection, loaderRunLoop(), kCFRunLoopDefaultMode);
80 }
81
82 CFURLRequestRef SynchronousResourceHandleCFURLConnectionDelegate::willSendRequest(CFURLRequestRef cfRequest, CFURLResponseRef originalRedirectResponse)
83 {
84     RetainPtr<CFURLResponseRef> redirectResponse = synthesizeRedirectResponseIfNecessary(cfRequest, originalRedirectResponse);
85
86     if (!redirectResponse) {
87         CFRetain(cfRequest);
88         return cfRequest;
89     }
90
91     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::willSendRequest(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
92
93     ResourceRequest request = createResourceRequest(cfRequest, redirectResponse.get());
94     m_handle->willSendRequest(request, redirectResponse.get());
95
96     if (request.isNull())
97         return 0;
98
99     cfRequest = request.cfURLRequest(UpdateHTTPBody);
100
101     CFRetain(cfRequest);
102     return cfRequest;
103 }
104
105 #if !PLATFORM(COCOA)
106 static void setDefaultMIMEType(CFURLResponseRef response)
107 {
108     static CFStringRef defaultMIMETypeString = defaultMIMEType().createCFString().leakRef();
109     
110     CFURLResponseSetMIMEType(response, defaultMIMETypeString);
111 }
112 #endif // !PLATFORM(COCOA)
113
114 void SynchronousResourceHandleCFURLConnectionDelegate::didReceiveResponse(CFURLConnectionRef connection, CFURLResponseRef cfResponse)
115 {
116     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::didReceiveResponse(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
117
118     if (!m_handle->client())
119         return;
120
121 #if PLATFORM(COCOA)
122     // Avoid MIME type sniffing if the response comes back as 304 Not Modified.
123     CFHTTPMessageRef msg = wkGetCFURLResponseHTTPResponse(cfResponse);
124     int statusCode = msg ? CFHTTPMessageGetResponseStatusCode(msg) : 0;
125
126     if (statusCode != 304)
127         adjustMIMETypeIfNecessary(cfResponse);
128
129 #if !PLATFORM(IOS)
130     if (_CFURLRequestCopyProtocolPropertyForKey(m_handle->firstRequest().cfURLRequest(DoNotUpdateHTTPBody), CFSTR("ForceHTMLMIMEType")))
131         wkSetCFURLResponseMIMEType(cfResponse, CFSTR("text/html"));
132 #endif // !PLATFORM(IOS)
133 #else
134     if (!CFURLResponseGetMIMEType(cfResponse)) {
135         // We should never be applying the default MIMEType if we told the networking layer to do content sniffing for handle.
136         ASSERT(!m_handle->shouldContentSniff());
137         setDefaultMIMEType(cfResponse);
138     }
139 #endif
140
141 #if USE(QUICK_LOOK)
142     m_handle->setQuickLookHandle(QuickLookHandle::create(m_handle, this, cfResponse));
143     if (m_handle->quickLookHandle())
144         cfResponse = m_handle->quickLookHandle()->cfResponse();
145 #endif
146     
147     ResourceResponse resourceResponse(cfResponse);
148 #if PLATFORM(COCOA) && ENABLE(WEB_TIMING)
149     ResourceHandle::getConnectionTimingData(connection, resourceResponse.resourceLoadTiming());
150 #else
151     UNUSED_PARAM(connection);
152 #endif
153     
154     m_handle->client()->didReceiveResponse(m_handle, resourceResponse);
155 }
156
157 void SynchronousResourceHandleCFURLConnectionDelegate::didReceiveData(CFDataRef data, CFIndex originalLength)
158 {
159     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::didReceiveData(handle=%p, bytes=%ld) (%s)", m_handle, CFDataGetLength(data), m_handle->firstRequest().url().string().utf8().data());
160
161 #if USE(QUICK_LOOK)
162     if (m_handle->quickLookHandle() && m_handle->quickLookHandle()->didReceiveData(data))
163         return;
164 #endif
165
166     if (ResourceHandleClient* client = m_handle->client())
167         client->didReceiveBuffer(m_handle, SharedBuffer::wrapCFData(data), originalLength);
168 }
169
170 void SynchronousResourceHandleCFURLConnectionDelegate::didFinishLoading()
171 {
172     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::didFinishLoading(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
173
174 #if USE(QUICK_LOOK)
175     if (m_handle->quickLookHandle() && m_handle->quickLookHandle()->didFinishLoading())
176         return;
177 #endif
178
179     if (ResourceHandleClient* client = m_handle->client())
180         client->didFinishLoading(m_handle, 0);
181 }
182
183 void SynchronousResourceHandleCFURLConnectionDelegate::didFail(CFErrorRef error)
184 {
185     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::didFail(handle=%p, error = %p) (%s)", m_handle, error, m_handle->firstRequest().url().string().utf8().data());
186
187 #if USE(QUICK_LOOK)
188     if (QuickLookHandle* quickLookHandle = m_handle->quickLookHandle())
189         quickLookHandle->didFail();
190 #endif
191
192     if (ResourceHandleClient* client = m_handle->client())
193         client->didFail(m_handle, ResourceError(error));
194 }
195
196 CFCachedURLResponseRef SynchronousResourceHandleCFURLConnectionDelegate::willCacheResponse(CFCachedURLResponseRef cachedResponse)
197 {
198 #if PLATFORM(WIN)
199     // Workaround for <rdar://problem/6300990> Caching does not respect Vary HTTP header.
200     // FIXME: WebCore cache has issues with Vary, too (bug 58797, bug 71509).
201     CFURLResponseRef wrappedResponse = CFCachedURLResponseGetWrappedResponse(cachedResponse);
202     if (CFHTTPMessageRef httpResponse = CFURLResponseGetHTTPResponse(wrappedResponse)) {
203         ASSERT(CFHTTPMessageIsHeaderComplete(httpResponse));
204         RetainPtr<CFStringRef> varyValue = adoptCF(CFHTTPMessageCopyHeaderFieldValue(httpResponse, CFSTR("Vary")));
205         if (varyValue)
206             return 0;
207     }
208 #endif // PLATFORM(WIN)
209
210 #if PLATFORM(WIN)
211     if (m_handle->client() && !m_handle->client()->shouldCacheResponse(m_handle, cachedResponse))
212         return 0;
213 #else
214     CFCachedURLResponseRef newResponse = m_handle->client()->willCacheResponse(m_handle, cachedResponse);
215     if (newResponse != cachedResponse)
216         return newResponse;
217 #endif
218
219     CFRetain(cachedResponse);
220     return cachedResponse;
221 }
222
223 void SynchronousResourceHandleCFURLConnectionDelegate::didReceiveChallenge(CFURLAuthChallengeRef challenge)
224 {
225     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::didReceiveChallenge(handle=%p (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
226
227     m_handle->didReceiveAuthenticationChallenge(AuthenticationChallenge(challenge, m_handle));
228 }
229
230 void SynchronousResourceHandleCFURLConnectionDelegate::didSendBodyData(CFIndex totalBytesWritten, CFIndex totalBytesExpectedToWrite)
231 {
232     if (!m_handle || !m_handle->client())
233         return;
234     m_handle->client()->didSendData(m_handle, totalBytesWritten, totalBytesExpectedToWrite);
235 }
236
237 Boolean SynchronousResourceHandleCFURLConnectionDelegate::shouldUseCredentialStorage()
238 {
239     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::shouldUseCredentialStorage(handle=%p) (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
240
241     if (!m_handle)
242         return false;
243
244     return m_handle->shouldUseCredentialStorage();
245 }
246
247 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
248 Boolean SynchronousResourceHandleCFURLConnectionDelegate::canRespondToProtectionSpace(CFURLProtectionSpaceRef protectionSpace)
249 {
250     ASSERT(m_handle);
251
252     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::canRespondToProtectionSpace(handle=%p (%s)", m_handle, m_handle->firstRequest().url().string().utf8().data());
253
254 #if PLATFORM(IOS)
255     ProtectionSpace coreProtectionSpace = ProtectionSpace(protectionSpace);
256     if (coreProtectionSpace.authenticationScheme() == ProtectionSpaceAuthenticationSchemeUnknown)
257         return false;
258     return m_handle->canAuthenticateAgainstProtectionSpace(coreProtectionSpace);
259 #else
260     return m_handle->canAuthenticateAgainstProtectionSpace(core(protectionSpace));
261 #endif
262 }
263 #endif // USE(PROTECTION_SPACE_AUTH_CALLBACK)
264
265 #if USE(NETWORK_CFDATA_ARRAY_CALLBACK)
266 void SynchronousResourceHandleCFURLConnectionDelegate::didReceiveDataArray(CFArrayRef dataArray)
267 {
268     if (!m_handle->client())
269         return;
270
271     LOG(Network, "CFNet - SynchronousResourceHandleCFURLConnectionDelegate::didReceiveDataArray(handle=%p, arrayLength=%ld) (%s)", m_handle, CFArrayGetCount(dataArray), m_handle->firstRequest().url().string().utf8().data());
272
273 #if USE(QUICK_LOOK)
274     if (m_handle->quickLookHandle() && m_handle->quickLookHandle()->didReceiveDataArray(dataArray))
275         return;
276 #endif
277
278     if (ResourceHandleClient* client = m_handle->client())
279         client->didReceiveBuffer(m_handle, SharedBuffer::wrapCFDataArray(dataArray), -1);
280 }
281 #endif // USE(NETWORK_CFDATA_ARRAY_CALLBACK)
282
283 void SynchronousResourceHandleCFURLConnectionDelegate::continueWillSendRequest(CFURLRequestRef)
284 {
285     ASSERT_NOT_REACHED();
286 }
287
288 void SynchronousResourceHandleCFURLConnectionDelegate::continueDidReceiveResponse()
289 {
290     ASSERT_NOT_REACHED();
291 }
292
293 void SynchronousResourceHandleCFURLConnectionDelegate::continueWillCacheResponse(CFCachedURLResponseRef)
294 {
295     ASSERT_NOT_REACHED();
296 }
297
298 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
299 void SynchronousResourceHandleCFURLConnectionDelegate::continueCanAuthenticateAgainstProtectionSpace(bool)
300 {
301     ASSERT_NOT_REACHED();
302 }
303 #endif // USE(PROTECTION_SPACE_AUTH_CALLBACK)
304
305 } // namespace WebCore.
306
307 #endif