Use CompletionHandlers for ResourceHandleClient::didReceiveResponseAsync
[WebKit-https.git] / Source / WebCore / platform / network / ResourceHandle.cpp
1 /*
2  * Copyright (C) 2004-2017 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 "ResourceHandle.h"
28 #include "ResourceHandleInternal.h"
29
30 #include "Logging.h"
31 #include "NetworkingContext.h"
32 #include "NotImplemented.h"
33 #include "ResourceHandleClient.h"
34 #include "Timer.h"
35 #include <algorithm>
36 #include <wtf/CompletionHandler.h>
37 #include <wtf/MainThread.h>
38 #include <wtf/NeverDestroyed.h>
39 #include <wtf/text/AtomicStringHash.h>
40 #include <wtf/text/CString.h>
41
42 namespace WebCore {
43
44 static bool shouldForceContentSniffing;
45
46 typedef HashMap<AtomicString, ResourceHandle::BuiltinConstructor> BuiltinResourceHandleConstructorMap;
47 static BuiltinResourceHandleConstructorMap& builtinResourceHandleConstructorMap()
48 {
49 #if PLATFORM(IOS)
50     ASSERT(WebThreadIsLockedOrDisabled());
51 #else
52     ASSERT(isMainThread());
53 #endif
54     static NeverDestroyed<BuiltinResourceHandleConstructorMap> map;
55     return map;
56 }
57
58 void ResourceHandle::registerBuiltinConstructor(const AtomicString& protocol, ResourceHandle::BuiltinConstructor constructor)
59 {
60     builtinResourceHandleConstructorMap().add(protocol, constructor);
61 }
62
63 typedef HashMap<AtomicString, ResourceHandle::BuiltinSynchronousLoader> BuiltinResourceHandleSynchronousLoaderMap;
64 static BuiltinResourceHandleSynchronousLoaderMap& builtinResourceHandleSynchronousLoaderMap()
65 {
66     ASSERT(isMainThread());
67     static NeverDestroyed<BuiltinResourceHandleSynchronousLoaderMap> map;
68     return map;
69 }
70
71 void ResourceHandle::registerBuiltinSynchronousLoader(const AtomicString& protocol, ResourceHandle::BuiltinSynchronousLoader loader)
72 {
73     builtinResourceHandleSynchronousLoaderMap().add(protocol, loader);
74 }
75
76 ResourceHandle::ResourceHandle(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff)
77     : d(std::make_unique<ResourceHandleInternal>(this, context, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url()), shouldContentEncodingSniff))
78 {
79     if (!request.url().isValid()) {
80         scheduleFailure(InvalidURLFailure);
81         return;
82     }
83
84     if (!portAllowed(request.url())) {
85         scheduleFailure(BlockedFailure);
86         return;
87     }
88 }
89
90 RefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff)
91 {
92     if (auto constructor = builtinResourceHandleConstructorMap().get(request.url().protocol().toStringWithoutCopying()))
93         return constructor(request, client);
94
95     auto newHandle = adoptRef(*new ResourceHandle(context, request, client, defersLoading, shouldContentSniff, shouldContentEncodingSniff));
96
97     if (newHandle->d->m_scheduledFailureType != NoFailure)
98         return WTFMove(newHandle);
99
100     if (newHandle->start())
101         return WTFMove(newHandle);
102
103     return nullptr;
104 }
105
106 void ResourceHandle::scheduleFailure(FailureType type)
107 {
108     d->m_scheduledFailureType = type;
109     d->m_failureTimer.startOneShot(0_s);
110 }
111
112 void ResourceHandle::failureTimerFired()
113 {
114     if (!client())
115         return;
116
117     switch (d->m_scheduledFailureType) {
118         case NoFailure:
119             ASSERT_NOT_REACHED();
120             return;
121         case BlockedFailure:
122             d->m_scheduledFailureType = NoFailure;
123             client()->wasBlocked(this);
124             return;
125         case InvalidURLFailure:
126             d->m_scheduledFailureType = NoFailure;
127             client()->cannotShowURL(this);
128             return;
129     }
130
131     ASSERT_NOT_REACHED();
132 }
133
134 void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentialsPolicy storedCredentialsPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
135 {
136     if (auto constructor = builtinResourceHandleSynchronousLoaderMap().get(request.url().protocol().toStringWithoutCopying())) {
137         constructor(context, request, storedCredentialsPolicy, error, response, data);
138         return;
139     }
140
141     platformLoadResourceSynchronously(context, request, storedCredentialsPolicy, error, response, data);
142 }
143
144 ResourceHandleClient* ResourceHandle::client() const
145 {
146     return d->m_client;
147 }
148
149 void ResourceHandle::clearClient()
150 {
151     d->m_client = nullptr;
152 }
153
154 void ResourceHandle::didReceiveResponse(ResourceResponse&& response, CompletionHandler<void()>&& completionHandler)
155 {
156     if (response.isHTTP09()) {
157         auto url = response.url();
158         std::optional<uint16_t> port = url.port();
159         if (port && !isDefaultPortForProtocol(port.value(), url.protocol())) {
160             cancel();
161             String message = "Cancelled load from '" + url.stringCenterEllipsizedToLength() + "' because it is using HTTP/0.9.";
162             d->m_client->didFail(this, { String(), 0, url, message });
163             completionHandler();
164             return;
165         }
166     }
167     client()->didReceiveResponseAsync(this, WTFMove(response), WTFMove(completionHandler));
168 }
169
170 #if !USE(SOUP) && !USE(CURL)
171 void ResourceHandle::platformContinueSynchronousDidReceiveResponse()
172 {
173     // Do nothing.
174 }
175 #endif
176
177 ResourceRequest& ResourceHandle::firstRequest()
178 {
179     return d->m_firstRequest;
180 }
181
182 NetworkingContext* ResourceHandle::context() const
183 {
184     return d->m_context.get();
185 }
186
187 const String& ResourceHandle::lastHTTPMethod() const
188 {
189     return d->m_lastHTTPMethod;
190 }
191
192 bool ResourceHandle::hasAuthenticationChallenge() const
193 {
194     return !d->m_currentWebChallenge.isNull();
195 }
196
197 void ResourceHandle::clearAuthentication()
198 {
199 #if PLATFORM(COCOA)
200     d->m_currentMacChallenge = nil;
201 #endif
202     d->m_currentWebChallenge.nullify();
203 }
204   
205 bool ResourceHandle::shouldContentSniff() const
206 {
207     return d->m_shouldContentSniff;
208 }
209
210 bool ResourceHandle::shouldContentEncodingSniff() const
211 {
212     return d->m_shouldContentEncodingSniff;
213 }
214
215 bool ResourceHandle::shouldContentSniffURL(const URL& url)
216 {
217 #if PLATFORM(COCOA)
218     if (shouldForceContentSniffing)
219         return true;
220 #endif
221     // We shouldn't content sniff file URLs as their MIME type should be established via their extension.
222     return !url.protocolIs("file");
223 }
224
225 void ResourceHandle::forceContentSniffing()
226 {
227     shouldForceContentSniffing = true;
228 }
229
230 void ResourceHandle::setDefersLoading(bool defers)
231 {
232     LOG(Network, "Handle %p setDefersLoading(%s)", this, defers ? "true" : "false");
233
234     ASSERT(d->m_defersLoading != defers); // Deferring is not counted, so calling setDefersLoading() repeatedly is likely to be in error.
235     d->m_defersLoading = defers;
236
237     if (defers) {
238         ASSERT(d->m_failureTimer.isActive() == (d->m_scheduledFailureType != NoFailure));
239         if (d->m_failureTimer.isActive())
240             d->m_failureTimer.stop();
241     } else if (d->m_scheduledFailureType != NoFailure) {
242         ASSERT(!d->m_failureTimer.isActive());
243         d->m_failureTimer.startOneShot(0_s);
244     }
245
246     platformSetDefersLoading(defers);
247 }
248
249 } // namespace WebCore