aaa5acac37afd5b61525c68d87c80b08d6fdd2f3
[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 "NetworkProcessConnectionMessages.h"
37 #include "NetworkResourceLoadParameters.h"
38 #include "RemoteNetworkingContext.h"
39 #include "SharedMemory.h"
40 #include "WebCoreArgumentCoders.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 ResourceLoadPriority NetworkResourceLoader::priority() const
68 {
69     return m_requestParameters.priority();
70 }
71
72 void NetworkResourceLoader::start()
73 {
74     ASSERT(isMainThread());
75
76     // Explicit ref() balanced by a deref() in NetworkResourceLoader::stop()
77     ref();
78     
79     // FIXME (NetworkProcess): Create RemoteNetworkingContext with actual settings.
80     m_networkingContext = RemoteNetworkingContext::create(false, false);
81
82     // FIXME (NetworkProcess): Pass an actual value for defersLoading
83     m_handle = ResourceHandle::create(m_networkingContext.get(), m_requestParameters.request(), this, false /* defersLoading */, m_requestParameters.contentSniffingPolicy() == SniffContent);
84 }
85
86 static bool stopRequestsCalled = false;
87
88 static Mutex& requestsToStopMutex()
89 {
90     DEFINE_STATIC_LOCAL(Mutex, mutex, ());
91     return mutex;
92 }
93
94 static HashSet<NetworkResourceLoader*>& requestsToStop()
95 {
96     DEFINE_STATIC_LOCAL(HashSet<NetworkResourceLoader*>, requests, ());
97     return requests;
98 }
99
100 void NetworkResourceLoader::scheduleStopOnMainThread()
101 {
102     MutexLocker locker(requestsToStopMutex());
103
104     requestsToStop().add(this);
105     if (!stopRequestsCalled) {
106         stopRequestsCalled = true;
107         callOnMainThread(NetworkResourceLoader::performStops, 0);
108     }
109 }
110
111 void NetworkResourceLoader::performStops(void*)
112 {
113     ASSERT(stopRequestsCalled);
114
115     Vector<NetworkResourceLoader*> requests;
116     {
117         MutexLocker locker(requestsToStopMutex());
118         copyToVector(requestsToStop(), requests);
119         requestsToStop().clear();
120         stopRequestsCalled = false;
121     }
122     
123     for (size_t i = 0; i < requests.size(); ++i)
124         requests[i]->stop();
125 }
126
127 void NetworkResourceLoader::stop()
128 {
129     ASSERT(isMainThread());
130
131     // Remove this load identifier soon so we can start more network requests.
132     NetworkProcess::shared().networkResourceLoadScheduler().scheduleRemoveLoadIdentifier(m_identifier);
133     
134     // Explicit deref() balanced by a ref() in NetworkResourceLoader::stop()
135     // This might cause the NetworkResourceLoader to be destroyed and therefore we do it last.
136     deref();
137 }
138
139 void NetworkResourceLoader::connectionToWebProcessDidClose(NetworkConnectionToWebProcess* connection)
140 {
141     ASSERT_ARG(connection, connection == m_connection.get());
142     m_connection->unregisterObserver(this);
143     m_connection = 0;
144 }
145
146 void NetworkResourceLoader::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
147 {
148     // FIXME (NetworkProcess): Cache the response.
149     connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidReceiveResponse(m_identifier, response), 0);
150 }
151
152 void NetworkResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int encodedDataLength)
153 {
154     // FIXME (NetworkProcess): For the memory cache we'll also need to cache the response data here.
155     // Such buffering will need to be thread safe, as this callback is happening on a background thread.
156     
157     CoreIPC::DataReference dataReference(reinterpret_cast<const uint8_t*>(data), length);
158     connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidReceiveData(m_identifier, dataReference, encodedDataLength, false), 0);
159 }
160
161 void NetworkResourceLoader::didFinishLoading(ResourceHandle*, double finishTime)
162 {
163     // FIXME (NetworkProcess): For the memory cache we'll need to update the finished status of the cached resource here.
164     // Such bookkeeping will need to be thread safe, as this callback is happening on a background thread.
165     connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidFinishResourceLoad(m_identifier, finishTime), 0);
166     scheduleStopOnMainThread();
167 }
168
169 void NetworkResourceLoader::didFail(ResourceHandle*, const ResourceError& error)
170 {
171     // FIXME (NetworkProcess): For the memory cache we'll need to update the finished status of the cached resource here.
172     // Such bookkeeping will need to be thread safe, as this callback is happening on a background thread.
173     connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::DidFailResourceLoad(m_identifier, error), 0);
174     scheduleStopOnMainThread();
175 }
176
177 static BlockingResponseMap<ResourceRequest*>& responseMap()
178 {
179     AtomicallyInitializedStatic(BlockingResponseMap<ResourceRequest*>&, responseMap = *new BlockingResponseMap<ResourceRequest*>);
180     return responseMap;
181 }
182
183 static uint64_t generateWillSendRequestID()
184 {
185     static int64_t uniqueWillSendRequestID;
186     return OSAtomicIncrement64Barrier(&uniqueWillSendRequestID);
187 }
188
189 void didReceiveWillSendRequestHandled(uint64_t requestID, const ResourceRequest& request)
190 {
191     responseMap().didReceiveResponse(requestID, adoptPtr(new ResourceRequest(request)));
192 }
193
194 void NetworkResourceLoader::willSendRequest(ResourceHandle*, ResourceRequest& request, const ResourceResponse& redirectResponse)
195 {
196     // We only expect to get the willSendRequest callback from ResourceHandle as the result of a redirect
197     ASSERT(!redirectResponse.isNull());
198
199     uint64_t requestID = generateWillSendRequestID();
200
201     if (!connectionToWebProcess()->connection()->send(Messages::NetworkProcessConnection::WillSendRequest(requestID, m_identifier, request, redirectResponse), 0)) {
202         // FIXME (NetworkProcess): What should we do if we can't send the message?
203         return;
204     }
205     
206     OwnPtr<ResourceRequest> newRequest = responseMap().waitForResponse(requestID);
207     request = *newRequest;
208
209     RunLoop::main()->dispatch(WTF::bind(&NetworkResourceLoadScheduler::receivedRedirect, &NetworkProcess::shared().networkResourceLoadScheduler(), m_identifier, request.url()));
210 }
211
212 // FIXME (NetworkProcess): Many of the following ResourceHandleClient methods definitely need implementations. A few will not.
213 // Once we know what they are they can be removed.
214
215 void NetworkResourceLoader::didSendData(WebCore::ResourceHandle*, unsigned long long /*bytesSent*/, unsigned long long /*totalBytesToBeSent*/)
216 {
217     notImplemented();
218 }
219
220 void NetworkResourceLoader::didReceiveCachedMetadata(WebCore::ResourceHandle*, const char*, int)
221 {
222     notImplemented();
223 }
224
225 void NetworkResourceLoader::wasBlocked(WebCore::ResourceHandle*)
226 {
227     notImplemented();
228 }
229
230 void NetworkResourceLoader::cannotShowURL(WebCore::ResourceHandle*)
231 {
232     notImplemented();
233 }
234
235 void NetworkResourceLoader::willCacheResponse(WebCore::ResourceHandle*, WebCore::CacheStoragePolicy&)
236 {
237     notImplemented();
238 }
239
240 bool NetworkResourceLoader::shouldUseCredentialStorage(WebCore::ResourceHandle*)
241 {
242     notImplemented();
243     return false;
244 }
245
246 void NetworkResourceLoader::didReceiveAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
247 {
248     notImplemented();
249 }
250
251 void NetworkResourceLoader::didCancelAuthenticationChallenge(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
252 {
253     notImplemented();
254 }
255
256 void NetworkResourceLoader::receivedCancellation(WebCore::ResourceHandle*, const WebCore::AuthenticationChallenge&)
257 {
258     notImplemented();
259 }
260
261 #if USE(PROTECTION_SPACE_AUTH_CALLBACK)
262 bool NetworkResourceLoader::canAuthenticateAgainstProtectionSpace(WebCore::ResourceHandle*, const WebCore::ProtectionSpace&)
263 {
264     notImplemented();
265     return false;
266 }
267 #endif
268
269 #if HAVE(NETWORK_CFDATA_ARRAY_CALLBACK)
270 bool NetworkResourceLoader::supportsDataArray()
271 {
272     notImplemented();
273     return false;
274 }
275
276 void NetworkResourceLoader::didReceiveDataArray(WebCore::ResourceHandle*, CFArrayRef)
277 {
278     notImplemented();
279 }
280 #endif
281
282 #if PLATFORM(MAC)
283 #if USE(CFNETWORK)
284 CFCachedURLResponseRef NetworkResourceLoader::willCacheResponse(WebCore::ResourceHandle*, CFCachedURLResponseRef response)
285 {
286     notImplemented();
287     return response;
288 }
289 #else
290 NSCachedURLResponse* NetworkResourceLoader::willCacheResponse(WebCore::ResourceHandle*, NSCachedURLResponse* response)
291 {
292     notImplemented();
293     return response;
294 }
295 #endif
296
297 void NetworkResourceLoader::willStopBufferingData(WebCore::ResourceHandle*, const char*, int)
298 {
299     notImplemented();
300 }
301 #endif // PLATFORM(MAC)
302
303 #if ENABLE(BLOB)
304 WebCore::AsyncFileStream* NetworkResourceLoader::createAsyncFileStream(WebCore::FileStreamClient*)
305 {
306     notImplemented();
307     return 0;
308 }
309 #endif
310
311 } // namespace WebKit
312
313 #endif // ENABLE(NETWORK_PROCESS)