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