2 * Copyright (C) 2004-2017 Apple Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
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.
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.
27 #include "ResourceHandle.h"
28 #include "ResourceHandleInternal.h"
31 #include "NetworkingContext.h"
32 #include "NotImplemented.h"
33 #include "ResourceHandleClient.h"
36 #include <wtf/MainThread.h>
37 #include <wtf/NeverDestroyed.h>
38 #include <wtf/text/AtomicStringHash.h>
39 #include <wtf/text/CString.h>
43 static bool shouldForceContentSniffing;
45 typedef HashMap<AtomicString, ResourceHandle::BuiltinConstructor> BuiltinResourceHandleConstructorMap;
46 static BuiltinResourceHandleConstructorMap& builtinResourceHandleConstructorMap()
49 ASSERT(WebThreadIsLockedOrDisabled());
51 ASSERT(isMainThread());
53 static NeverDestroyed<BuiltinResourceHandleConstructorMap> map;
57 void ResourceHandle::registerBuiltinConstructor(const AtomicString& protocol, ResourceHandle::BuiltinConstructor constructor)
59 builtinResourceHandleConstructorMap().add(protocol, constructor);
62 typedef HashMap<AtomicString, ResourceHandle::BuiltinSynchronousLoader> BuiltinResourceHandleSynchronousLoaderMap;
63 static BuiltinResourceHandleSynchronousLoaderMap& builtinResourceHandleSynchronousLoaderMap()
65 ASSERT(isMainThread());
66 static NeverDestroyed<BuiltinResourceHandleSynchronousLoaderMap> map;
70 void ResourceHandle::registerBuiltinSynchronousLoader(const AtomicString& protocol, ResourceHandle::BuiltinSynchronousLoader loader)
72 builtinResourceHandleSynchronousLoaderMap().add(protocol, loader);
75 ResourceHandle::ResourceHandle(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff)
76 : d(std::make_unique<ResourceHandleInternal>(this, context, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url()), shouldContentEncodingSniff))
78 if (!request.url().isValid()) {
79 scheduleFailure(InvalidURLFailure);
83 if (!portAllowed(request.url())) {
84 scheduleFailure(BlockedFailure);
89 RefPtr<ResourceHandle> ResourceHandle::create(NetworkingContext* context, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff)
91 if (auto constructor = builtinResourceHandleConstructorMap().get(request.url().protocol().toStringWithoutCopying()))
92 return constructor(request, client);
94 auto newHandle = adoptRef(*new ResourceHandle(context, request, client, defersLoading, shouldContentSniff, shouldContentEncodingSniff));
96 if (newHandle->d->m_scheduledFailureType != NoFailure)
97 return WTFMove(newHandle);
99 if (newHandle->start())
100 return WTFMove(newHandle);
105 void ResourceHandle::scheduleFailure(FailureType type)
107 d->m_scheduledFailureType = type;
108 d->m_failureTimer.startOneShot(0_s);
111 void ResourceHandle::failureTimerFired()
116 switch (d->m_scheduledFailureType) {
118 ASSERT_NOT_REACHED();
121 d->m_scheduledFailureType = NoFailure;
122 client()->wasBlocked(this);
124 case InvalidURLFailure:
125 d->m_scheduledFailureType = NoFailure;
126 client()->cannotShowURL(this);
130 ASSERT_NOT_REACHED();
133 void ResourceHandle::loadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentialsPolicy storedCredentialsPolicy, ResourceError& error, ResourceResponse& response, Vector<char>& data)
135 if (auto constructor = builtinResourceHandleSynchronousLoaderMap().get(request.url().protocol().toStringWithoutCopying())) {
136 constructor(context, request, storedCredentialsPolicy, error, response, data);
140 platformLoadResourceSynchronously(context, request, storedCredentialsPolicy, error, response, data);
143 ResourceHandleClient* ResourceHandle::client() const
148 void ResourceHandle::clearClient()
150 d->m_client = nullptr;
153 void ResourceHandle::didReceiveResponse(ResourceResponse&& response)
155 if (response.isHTTP09()) {
156 auto url = response.url();
157 std::optional<uint16_t> port = url.port();
158 if (port && !isDefaultPortForProtocol(port.value(), url.protocol())) {
160 String message = "Cancelled load from '" + url.stringCenterEllipsizedToLength() + "' because it is using HTTP/0.9.";
161 d->m_client->didFail(this, { String(), 0, url, message });
162 continueDidReceiveResponse();
166 client()->didReceiveResponseAsync(this, WTFMove(response));
169 #if !USE(SOUP) && !USE(CURL)
170 void ResourceHandle::platformContinueSynchronousDidReceiveResponse()
176 ResourceRequest& ResourceHandle::firstRequest()
178 return d->m_firstRequest;
181 NetworkingContext* ResourceHandle::context() const
183 return d->m_context.get();
186 const String& ResourceHandle::lastHTTPMethod() const
188 return d->m_lastHTTPMethod;
191 bool ResourceHandle::hasAuthenticationChallenge() const
193 return !d->m_currentWebChallenge.isNull();
196 void ResourceHandle::clearAuthentication()
199 d->m_currentMacChallenge = nil;
201 d->m_currentWebChallenge.nullify();
204 bool ResourceHandle::shouldContentSniff() const
206 return d->m_shouldContentSniff;
209 bool ResourceHandle::shouldContentEncodingSniff() const
211 return d->m_shouldContentEncodingSniff;
214 bool ResourceHandle::shouldContentSniffURL(const URL& url)
217 if (shouldForceContentSniffing)
220 // We shouldn't content sniff file URLs as their MIME type should be established via their extension.
221 return !url.protocolIs("file");
224 void ResourceHandle::forceContentSniffing()
226 shouldForceContentSniffing = true;
229 void ResourceHandle::setDefersLoading(bool defers)
231 LOG(Network, "Handle %p setDefersLoading(%s)", this, defers ? "true" : "false");
233 ASSERT(d->m_defersLoading != defers); // Deferring is not counted, so calling setDefersLoading() repeatedly is likely to be in error.
234 d->m_defersLoading = defers;
237 ASSERT(d->m_failureTimer.isActive() == (d->m_scheduledFailureType != NoFailure));
238 if (d->m_failureTimer.isActive())
239 d->m_failureTimer.stop();
240 } else if (d->m_scheduledFailureType != NoFailure) {
241 ASSERT(!d->m_failureTimer.isActive());
242 d->m_failureTimer.startOneShot(0_s);
245 platformSetDefersLoading(defers);
248 } // namespace WebCore