Move loading responsibility out of WebResourceLoadScheduler into a new WebResourceLoader
[WebKit-https.git] / Source / WebKit2 / NetworkProcess / NetworkResourceLoader.cpp
1 /*
2  * Copyright (C) 2012 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. AND ITS CONTRIBUTORS ``AS IS''
14  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
15  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
16  * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
17  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
18  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
19  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
20  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
21  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
22  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
23  * THE POSSIBILITY OF SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #include "NetworkResourceLoader.h"
28
29 #if ENABLE(NETWORK_PROCESS)
30
31 #include "BlockingResponseMap.h"
32 #include "DataReference.h"
33 #include "Logging.h"
34 #include "NetworkConnectionToWebProcess.h"
35 #include "NetworkProcess.h"
36 #include "NetworkResourceLoadParameters.h"
37 #include "RemoteNetworkingContext.h"
38 #include "SharedMemory.h"
39 #include "WebCoreArgumentCoders.h"
40 #include "WebResourceLoaderMessages.h"
41 #include <WebCore/NotImplemented.h>
42 #include <WebCore/ResourceBuffer.h>
43 #include <WebCore/ResourceHandle.h>
44 #include <wtf/MainThread.h>
45
46 using namespace WebCore;
47
48 namespace WebKit {
49
50 NetworkResourceLoader::NetworkResourceLoader(const NetworkResourceLoadParameters& requestParameters, ResourceLoadIdentifier identifier, NetworkConnectionToWebProcess* connection)
51     : m_requestParameters(requestParameters)
52     , m_identifier(identifier)
53     , m_connection(connection)
54 {
55     ASSERT(isMainThread());
56     connection->registerObserver(this);
57 }
58
59 NetworkResourceLoader::~NetworkResourceLoader()
60 {
61     ASSERT(isMainThread());
62
63     if (m_connection)
64         m_connection->unregisterObserver(this);
65 }
66
67 CoreIPC::Connection* NetworkResourceLoader::connection() const
68 {
69     return m_connection->connection();
70 }
71
72 ResourceLoadPriority NetworkResourceLoader::priority() const
73 {
74     return m_requestParameters.priority();
75 }
76
77 void NetworkResourceLoader::start()
78 {
79     ASSERT(isMainThread());
80
81     // Explicit ref() balanced by a deref() in NetworkResourceLoader::stop()
82     ref();
83     
84     // FIXME (NetworkProcess): Create RemoteNetworkingContext with actual settings.
85     m_networkingContext = RemoteNetworkingContext::create(false, false);
86
87     // FIXME (NetworkProcess): Pass an actual value for defersLoading
88     m_handle = ResourceHandle::create(m_networkingContext.get(), m_requestParameters.request(), this, false /* defersLoading */, m_requestParameters.contentSniffingPolicy() == SniffContent);
89 }
90
91 static bool stopRequestsCalled = false;
92
93 static Mutex& requestsToStopMutex()
94 {
95     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
96     return mutex;
97 }
98
99 static HashSet<NetworkResourceLoader*>& requestsToStop()
100 {
101     DEFINE_STATIC_LOCAL(HashSet<NetworkResourceLoader*>, requests, ());
102     return requests;
103 }
104
105 void NetworkResourceLoader::scheduleStopOnMainThread()
106 {
107     MutexLocker locker(requestsToStopMutex());
108
109     requestsToStop().add(this);
110     if (!stopRequestsCalled) {
111         stopRequestsCalled = true;
112         callOnMainThread(NetworkResourceLoader::performStops, 0);
113     }
114 }
115
116 void NetworkResourceLoader::performStops(void*)
117 {
118     ASSERT(stopRequestsCalled);
119
120     Vector<NetworkResourceLoader*> requests;
121     {
122         MutexLocker locker(requestsToStopMutex());
123         copyToVector(requestsToStop(), requests);
124         requestsToStop().clear();
125         stopRequestsCalled = false;
126     }
127     
128     for (size_t i = 0; i < requests.size(); ++i)
129         requests[i]->stop();
130 }
131
132 void NetworkResourceLoader::stop()
133 {
134     ASSERT(isMainThread());
135
136     // Remove this load identifier soon so we can start more network requests.
137     NetworkProcess::shared().networkResourceLoadScheduler().scheduleRemoveLoadIdentifier(m_identifier);
138     
139     // Explicit deref() balanced by a ref() in NetworkResourceLoader::stop()
140     // This might cause the NetworkResourceLoader to be destroyed and therefore we do it last.
141     deref();
142 }
143
144 void NetworkResourceLoader::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
145 {
146     ASSERT_ARG(connection, connection == m_connection.get());
147     m_connection->unregisterObserver(this);
148     m_connection = 0;
149 }
150
151 void NetworkResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
152 {
153     // FIXME (NetworkProcess): Cache the response.
154     send(Messages::WebResourceLoader::DidReceiveResponse(response));
155 }
156
157 void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int encodedDataLength)
158 {
159     // FIXME (NetworkProcess): For the memory cache we'll also need to cache the response data here.
160     // Such buffering will need to be thread safe, as this callback is happening on a background thread.
161     
162     CoreIPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(data), length);
163     send(Messages::WebResourceLoader::DidReceiveData(dataReference, encodedDataLength, false));
164 }
165
166 void NetworkResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
167 {
168     // FIXME (NetworkProcess): For the memory cache we'll need to update the finished status of the cached resource here.
169     // Such bookkeeping will need to be thread safe, as this callback is happening on a background thread.
170     send(Messages::WebResourceLoader::DidFinishResourceLoad(finishTime));
171     scheduleStopOnMainThread();
172 }
173
174 void NetworkResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
175 {
176     // FIXME (NetworkProcess): For the memory cache we'll need to update the finished status of the cached resource here.
177     // Such bookkeeping will need to be thread safe, as this callback is happening on a background thread.
178     send(Messages::WebResourceLoader::DidFailResourceLoad(error));
179     scheduleStopOnMainThread();
180 }
181
182 static BlockingResponseMap<ResourceRequest*>& responseMap()
183 {
184     AtomicallyInitializedStatic(BlockingResponseMap<ResourceRequest*>&, responseMap = *new BlockingResponseMap<ResourceRequest*>);
185     return responseMap;
186 }
187
188 static uint64_t generateWillSendRequestID()
189 {
190     static int64_t uniqueWillSendRequestID;
191     return OSAtomicIncrement64Barrier(&uniqueWillSendRequestID);
192 }
193
194 void didReceiveWillSendRequestHandled(uint64_t requestID, const ResourceRequest& request)
195 {
196     responseMap().didReceiveResponse(requestID, adoptPtr(new ResourceRequest(request)));
197 }
198
199 void NetworkResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
200 {
201     // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect
202     ASSERT(!redirectResponse.isNull());
203
204     uint64_t requestID = generateWillSendRequestID();
205
206     send(Messages::WebResourceLoader::WillSendRequest(requestID, request, redirectResponse));
207     
208     OwnPtr<ResourceRequest> newRequest = responseMap().waitForResponse(requestID);
209     request = *newRequest;
210
211     RunLoop::main()->dispatch(WTF::bind(&NetworkResourceLoadScheduler::receivedRedirect, &NetworkProcess::shared().networkResourceLoadScheduler(), m_identifier, request.url()));
212 }
213
214 // FIXME (NetworkProcess): Many of the following ResourceHandleClient methods definitely need implementations. A few will not.
215 // Once we know what they are they can be removed.
216
217 void NetworkResourceLoader::didSendData(WebCore::ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/)
218 {
219     notImplemented();
220 }
221
222 void NetworkResourceLoader::didReceiveCachedMetadata(WebCore::ResourceHandle*, const char*, int)
223 {
224     notImplemented();
225 }
226
227 void NetworkResourceLoader::wasBlocked(WebCore::ResourceHandle*)
228 {
229     notImplemented();
230 }
231
232 void NetworkResourceLoader::cannotShowURL(WebCore::ResourceHandle*)
233 {
234     notImplemented();
235 }
236
237 void NetworkResourceLoader::willCacheResponse(WebCore::ResourceHandle*, WebCore::CacheStoragePolicy&)
238 {
239     notImplemented();
240 }
241
242 bool NetworkResourceLoader::shouldUseCredentialStorage(WebCore::ResourceHandle*)
243 {
244     notImplemented();
245     return false;
246 }
247
248 void NetworkResourceLoader::didReceiveAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
249 {
250     notImplemented();
251 }
252
253 void NetworkResourceLoader::didCancelAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
254 {
255     notImplemented();
256 }
257
258 void NetworkResourceLoader::receivedCancellation(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
259 {
260     notImplemented();
261 }
262
263 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
264 bool NetworkResourceLoader::canAuthenticateAgainstProtectionSpace(WebCore::ResourceHandle*, const WebCore::ProtectionSpace&)
265 {
266     notImplemented();
267     return false;
268 }
269 #endif
270
271 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
272 bool NetworkResourceLoader::supportsDataArray()
273 {
274     notImplemented();
275     return false;
276 }
277
278 void NetworkResourceLoader::didReceiveDataArray(WebCore::ResourceHandle*, CFArrayRef)
279 {
280     notImplemented();
281 }
282 #endif
283
284 #if PLATFORM(MAC)
285 #if USE(CFNETWORK)
286 CFCachedURLResponseRef NetworkResourceLoader::willCacheResponse(WebCore::ResourceHandle*, CFCachedURLResponseRef response)
287 {
288     notImplemented();
289     return response;
290 }
291 #else
292 NSCachedURLResponse* NetworkResourceLoader::willCacheResponse(WebCore::ResourceHandle*, NSCachedURLResponse* response)
293 {
294     notImplemented();
295     return response;
296 }
297 #endif
298
299 void NetworkResourceLoader::willStopBufferingData(WebCore::ResourceHandle*, const char*, int)
300 {
301     notImplemented();
302 }
303 #endif // PLATFORM(MAC)
304
305 #if ENABLE(BLOB)
306 WebCore::AsyncFileStream* NetworkResourceLoader::createAsyncFileStream(WebCore::FileStreamClient*)
307 {
308     notImplemented();
309     return 0;
310 }
311 #endif
312
313 } // namespace WebKit
314
315 #endif // ENABLE(NETWORK_PROCESS)