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