Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / fetch / ResourceLoader.cpp
1 /*
2  * Copyright (C) 2006, 2007, 2010, 2011 Apple Inc. All rights reserved.
3  *           (C) 2007 Graham Dennis (graham.dennis@gmail.com)
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1.  Redistributions of source code must retain the above copyright
10  *     notice, this list of conditions and the following disclaimer.
11  * 2.  Redistributions in binary form must reproduce the above copyright
12  *     notice, this list of conditions and the following disclaimer in the
13  *     documentation and/or other materials provided with the distribution.
14  * 3.  Neither the name of Apple Computer, Inc. ("Apple") nor the names of
15  *     its contributors may be used to endorse or promote products derived
16  *     from this software without specific prior written permission.
17  *
18  * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
19  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
20  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21  * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
22  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
23  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
24  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
25  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include "config.h"
31 #include "core/fetch/ResourceLoader.h"
32
33 #include "core/fetch/Resource.h"
34 #include "core/fetch/ResourceLoaderHost.h"
35 #include "core/fetch/ResourcePtr.h"
36 #include "platform/Logging.h"
37 #include "platform/SharedBuffer.h"
38 #include "platform/exported/WrappedResourceRequest.h"
39 #include "platform/exported/WrappedResourceResponse.h"
40 #include "platform/network/ResourceError.h"
41 #include "public/platform/Platform.h"
42 #include "public/platform/WebData.h"
43 #include "public/platform/WebThreadedDataReceiver.h"
44 #include "public/platform/WebURLError.h"
45 #include "public/platform/WebURLRequest.h"
46 #include "public/platform/WebURLResponse.h"
47 #include "wtf/Assertions.h"
48 #include "wtf/CurrentTime.h"
49
50 namespace blink {
51
52 ResourceLoader::RequestCountTracker::RequestCountTracker(ResourceLoaderHost* host, Resource* resource)
53     : m_host(host)
54     , m_resource(resource)
55 {
56     m_host->incrementRequestCount(m_resource);
57 }
58
59 ResourceLoader::RequestCountTracker::~RequestCountTracker()
60 {
61     m_host->decrementRequestCount(m_resource);
62 }
63
64 ResourceLoader::RequestCountTracker::RequestCountTracker(const RequestCountTracker& other)
65 {
66     m_host = other.m_host;
67     m_resource = other.m_resource;
68     m_host->incrementRequestCount(m_resource);
69 }
70
71 PassRefPtrWillBeRawPtr<ResourceLoader> ResourceLoader::create(ResourceLoaderHost* host, Resource* resource, const ResourceRequest& request, const ResourceLoaderOptions& options)
72 {
73     RefPtrWillBeRawPtr<ResourceLoader> loader(adoptRefWillBeNoop(new ResourceLoader(host, resource, options)));
74     loader->init(request);
75     return loader.release();
76 }
77
78 ResourceLoader::ResourceLoader(ResourceLoaderHost* host, Resource* resource, const ResourceLoaderOptions& options)
79     : m_host(host)
80     , m_notifiedLoadComplete(false)
81     , m_defersLoading(host->defersLoading())
82     , m_options(options)
83     , m_resource(resource)
84     , m_state(Initialized)
85     , m_connectionState(ConnectionStateNew)
86     , m_requestCountTracker(adoptPtr(new RequestCountTracker(host, resource)))
87 {
88 }
89
90 ResourceLoader::~ResourceLoader()
91 {
92     ASSERT(m_state == Terminated);
93 }
94
95 void ResourceLoader::trace(Visitor* visitor)
96 {
97     visitor->trace(m_host);
98     visitor->trace(m_resource);
99 }
100
101 void ResourceLoader::releaseResources()
102 {
103     ASSERT(m_state != Terminated);
104     ASSERT(m_notifiedLoadComplete);
105     ASSERT(!m_requestCountTracker);
106     m_host->didLoadResource();
107     if (m_state == Terminated)
108         return;
109     m_resource->clearLoader();
110     m_resource->deleteIfPossible();
111     m_resource = nullptr;
112     m_host->willTerminateResourceLoader(this);
113
114     ASSERT(m_state != Terminated);
115
116     // It's possible that when we release the loader, it will be
117     // deallocated and release the last reference to this object.
118     // We need to retain to avoid accessing the object after it
119     // has been deallocated and also to avoid reentering this method.
120     RefPtrWillBeRawPtr<ResourceLoader> protector(this);
121
122     m_host.clear();
123     m_state = Terminated;
124
125     if (m_loader) {
126         m_loader->cancel();
127         m_loader.clear();
128     }
129
130     m_deferredRequest = ResourceRequest();
131 }
132
133 void ResourceLoader::init(const ResourceRequest& passedRequest)
134 {
135     ASSERT(m_state != Terminated);
136     ResourceRequest request(passedRequest);
137     m_host->willSendRequest(m_resource->identifier(), request, ResourceResponse(), m_options.initiatorInfo);
138     ASSERT(m_state != Terminated);
139     ASSERT(!request.isNull());
140     m_originalRequest = m_request = applyOptions(request);
141     m_resource->updateRequest(request);
142     ASSERT(m_state != Terminated);
143     m_host->didInitializeResourceLoader(this);
144 }
145
146 void ResourceLoader::start()
147 {
148     ASSERT(!m_loader);
149     ASSERT(!m_request.isNull());
150     ASSERT(m_deferredRequest.isNull());
151
152     if (responseNeedsAccessControlCheck() && m_host->isControlledByServiceWorker()) {
153         m_fallbackRequestForServiceWorker = adoptPtr(new ResourceRequest(m_request));
154         m_fallbackRequestForServiceWorker->setSkipServiceWorker(true);
155     }
156
157     m_host->willStartLoadingResource(m_resource, m_request);
158
159     if (m_options.synchronousPolicy == RequestSynchronously) {
160         requestSynchronously();
161         return;
162     }
163
164     if (m_defersLoading) {
165         m_deferredRequest = m_request;
166         return;
167     }
168
169     if (m_state == Terminated)
170         return;
171
172     RELEASE_ASSERT(m_connectionState == ConnectionStateNew);
173     m_connectionState = ConnectionStateStarted;
174
175     m_loader = adoptPtr(blink::Platform::current()->createURLLoader());
176     ASSERT(m_loader);
177     blink::WrappedResourceRequest wrappedRequest(m_request);
178     m_loader->loadAsynchronously(wrappedRequest, this);
179 }
180
181 void ResourceLoader::changeToSynchronous()
182 {
183     ASSERT(m_options.synchronousPolicy == RequestAsynchronously);
184     ASSERT(m_loader);
185     m_loader->cancel();
186     m_loader.clear();
187     m_request.setPriority(ResourceLoadPriorityHighest);
188     m_connectionState = ConnectionStateNew;
189     requestSynchronously();
190 }
191
192 void ResourceLoader::setDefersLoading(bool defers)
193 {
194     m_defersLoading = defers;
195     if (m_loader)
196         m_loader->setDefersLoading(defers);
197     if (!defers && !m_deferredRequest.isNull()) {
198         m_request = applyOptions(m_deferredRequest);
199         m_deferredRequest = ResourceRequest();
200         start();
201     }
202 }
203
204 void ResourceLoader::attachThreadedDataReceiver(PassOwnPtr<blink::WebThreadedDataReceiver> threadedDataReceiver)
205 {
206     if (m_loader) {
207         // The implementor of the WebURLLoader assumes ownership of the
208         // threaded data receiver if it signals that it got successfully
209         // attached.
210         blink::WebThreadedDataReceiver* rawThreadedDataReceiver = threadedDataReceiver.leakPtr();
211         if (!m_loader->attachThreadedDataReceiver(rawThreadedDataReceiver))
212             delete rawThreadedDataReceiver;
213     }
214 }
215
216 void ResourceLoader::didDownloadData(blink::WebURLLoader*, int length, int encodedDataLength)
217 {
218     ASSERT(m_state != Terminated);
219     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
220     RELEASE_ASSERT(m_connectionState == ConnectionStateReceivedResponse);
221     m_host->didDownloadData(m_resource, length, encodedDataLength);
222     if (m_state == Terminated)
223         return;
224     m_resource->didDownloadData(length);
225 }
226
227 void ResourceLoader::didFinishLoadingOnePart(double finishTime, int64_t encodedDataLength)
228 {
229     // If load has been cancelled after finishing (which could happen with a
230     // JavaScript that changes the window location), do nothing.
231     if (m_state == Terminated)
232         return;
233
234     if (m_notifiedLoadComplete)
235         return;
236     didComplete();
237     m_host->didFinishLoading(m_resource, finishTime, encodedDataLength);
238 }
239
240 void ResourceLoader::didChangePriority(ResourceLoadPriority loadPriority, int intraPriorityValue)
241 {
242     if (m_loader) {
243         m_host->didChangeLoadingPriority(m_resource, loadPriority, intraPriorityValue);
244         ASSERT(m_state != Terminated);
245         m_loader->didChangePriority(static_cast<blink::WebURLRequest::Priority>(loadPriority), intraPriorityValue);
246     }
247 }
248
249 void ResourceLoader::cancelIfNotFinishing()
250 {
251     if (m_state != Initialized)
252         return;
253     cancel();
254 }
255
256 void ResourceLoader::cancel()
257 {
258     cancel(ResourceError());
259 }
260
261 void ResourceLoader::cancel(const ResourceError& error)
262 {
263     // If the load has already completed - succeeded, failed, or previously cancelled - do nothing.
264     if (m_state == Terminated)
265         return;
266     if (m_state == Finishing) {
267         releaseResources();
268         return;
269     }
270
271     ResourceError nonNullError = error.isNull() ? ResourceError::cancelledError(m_request.url()) : error;
272
273     // This function calls out to clients at several points that might do
274     // something that causes the last reference to this object to go away.
275     RefPtrWillBeRawPtr<ResourceLoader> protector(this);
276
277     WTF_LOG(ResourceLoading, "Cancelled load of '%s'.\n", m_resource->url().string().latin1().data());
278     if (m_state == Initialized)
279         m_state = Finishing;
280     m_resource->setResourceError(nonNullError);
281
282     if (m_loader) {
283         m_connectionState = ConnectionStateCanceled;
284         m_loader->cancel();
285         m_loader.clear();
286     }
287
288     if (!m_notifiedLoadComplete) {
289         didComplete();
290         m_host->didFailLoading(m_resource, nonNullError);
291     }
292
293     if (m_state == Finishing)
294         m_resource->error(Resource::LoadError);
295     if (m_state != Terminated)
296         releaseResources();
297 }
298
299 void ResourceLoader::willSendRequest(blink::WebURLLoader*, blink::WebURLRequest& passedNewRequest, const blink::WebURLResponse& passedRedirectResponse)
300 {
301     ASSERT(m_state != Terminated);
302     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
303
304     ResourceRequest& newRequest(applyOptions(passedNewRequest.toMutableResourceRequest()));
305
306     ASSERT(!newRequest.isNull());
307     const ResourceResponse& redirectResponse(passedRedirectResponse.toResourceResponse());
308     ASSERT(!redirectResponse.isNull());
309     if (!m_host->canAccessRedirect(m_resource, newRequest, redirectResponse, m_options)) {
310         cancel();
311         return;
312     }
313     ASSERT(m_state != Terminated);
314
315     applyOptions(newRequest); // canAccessRedirect() can modify m_options so we should re-apply it.
316     m_host->redirectReceived(m_resource, redirectResponse);
317     ASSERT(m_state != Terminated);
318     m_resource->willFollowRedirect(newRequest, redirectResponse);
319     if (newRequest.isNull() || m_state == Terminated)
320         return;
321
322     m_host->willSendRequest(m_resource->identifier(), newRequest, redirectResponse, m_options.initiatorInfo);
323     ASSERT(m_state != Terminated);
324     ASSERT(!newRequest.isNull());
325     m_resource->updateRequest(newRequest);
326     m_request = newRequest;
327 }
328
329 void ResourceLoader::didReceiveCachedMetadata(blink::WebURLLoader*, const char* data, int length)
330 {
331     RELEASE_ASSERT(m_connectionState == ConnectionStateReceivedResponse || m_connectionState == ConnectionStateReceivingData);
332     ASSERT(m_state == Initialized);
333     m_resource->setSerializedCachedMetadata(data, length);
334 }
335
336 void ResourceLoader::didSendData(blink::WebURLLoader*, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
337 {
338     ASSERT(m_state == Initialized);
339     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
340     m_resource->didSendData(bytesSent, totalBytesToBeSent);
341 }
342
343 bool ResourceLoader::responseNeedsAccessControlCheck() const
344 {
345     // If the fetch was (potentially) CORS enabled, an access control check of the response is required.
346     return m_options.corsEnabled == IsCORSEnabled;
347 }
348
349 void ResourceLoader::didReceiveResponse(blink::WebURLLoader*, const blink::WebURLResponse& response, WebDataConsumerHandle* rawHandle)
350 {
351     ASSERT(!response.isNull());
352     ASSERT(m_state == Initialized);
353     // |rawHandle|'s ownership is transferred to the callee.
354     OwnPtr<WebDataConsumerHandle> handle = adoptPtr(rawHandle);
355
356     bool isMultipartPayload = response.isMultipartPayload();
357     bool isValidStateTransition = (m_connectionState == ConnectionStateStarted || m_connectionState == ConnectionStateReceivedResponse);
358     // In the case of multipart loads, calls to didReceiveData & didReceiveResponse can be interleaved.
359     RELEASE_ASSERT(isMultipartPayload || isValidStateTransition);
360     m_connectionState = ConnectionStateReceivedResponse;
361
362     const ResourceResponse& resourceResponse = response.toResourceResponse();
363
364     if (responseNeedsAccessControlCheck()) {
365         if (response.wasFetchedViaServiceWorker()) {
366             if (response.wasFallbackRequiredByServiceWorker()) {
367                 ASSERT(m_fallbackRequestForServiceWorker);
368                 m_loader->cancel();
369                 m_loader.clear();
370                 m_connectionState = ConnectionStateStarted;
371                 m_request = *m_fallbackRequestForServiceWorker;
372                 m_loader = adoptPtr(blink::Platform::current()->createURLLoader());
373                 ASSERT(m_loader);
374                 blink::WrappedResourceRequest wrappedRequest(m_request);
375                 m_loader->loadAsynchronously(wrappedRequest, this);
376                 return;
377             }
378         } else {
379             // If the response successfully validated a cached resource, perform
380             // the access control with respect to it. Need to do this right here
381             // before the resource switches clients over to that validated resource.
382             Resource* resource = m_resource;
383             if (resource->isCacheValidator() && resourceResponse.httpStatusCode() == 304)
384                 resource = m_resource->resourceToRevalidate();
385             else
386                 m_resource->setResponse(resourceResponse);
387             if (!m_host->canAccessResource(resource, m_options.securityOrigin.get(), response.url())) {
388                 m_host->didReceiveResponse(m_resource, resourceResponse);
389                 cancel();
390                 return;
391             }
392         }
393     }
394
395     // Reference the object in this method since the additional processing can do
396     // anything including removing the last reference to this object.
397     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
398     m_resource->responseReceived(resourceResponse, handle.release());
399     if (m_state == Terminated)
400         return;
401
402     m_host->didReceiveResponse(m_resource, resourceResponse);
403     if (m_state == Terminated)
404         return;
405
406     if (response.toResourceResponse().isMultipart()) {
407         // We don't count multiParts in a ResourceFetcher's request count
408         m_requestCountTracker.clear();
409         if (!m_resource->isImage()) {
410             cancel();
411             return;
412         }
413     } else if (isMultipartPayload) {
414         // Since a subresource loader does not load multipart sections progressively, data was delivered to the loader all at once.
415         // After the first multipart section is complete, signal to delegates that this load is "finished"
416         m_host->subresourceLoaderFinishedLoadingOnePart(this);
417         ASSERT(m_state != Terminated);
418         didFinishLoadingOnePart(0, blink::WebURLLoaderClient::kUnknownEncodedDataLength);
419     }
420     if (m_state == Terminated)
421         return;
422
423     if (m_resource->response().httpStatusCode() < 400 || m_resource->shouldIgnoreHTTPStatusCodeErrors())
424         return;
425     m_state = Finishing;
426
427     if (!m_notifiedLoadComplete) {
428         didComplete();
429         m_host->didFailLoading(m_resource, ResourceError::cancelledError(m_request.url()));
430     }
431
432     ASSERT(m_state != Terminated);
433     m_resource->error(Resource::LoadError);
434     cancel();
435 }
436
437 void ResourceLoader::didReceiveResponse(blink::WebURLLoader* loader, const blink::WebURLResponse& response)
438 {
439     didReceiveResponse(loader, response, nullptr);
440 }
441
442 void ResourceLoader::didReceiveData(blink::WebURLLoader*, const char* data, int length, int encodedDataLength)
443 {
444     ASSERT(m_state != Terminated);
445     RELEASE_ASSERT(m_connectionState == ConnectionStateReceivedResponse || m_connectionState == ConnectionStateReceivingData);
446     m_connectionState = ConnectionStateReceivingData;
447
448     // It is possible to receive data on uninitialized resources if it had an error status code, and we are running a nested message
449     // loop. When this occurs, ignoring the data is the correct action.
450     if (m_resource->response().httpStatusCode() >= 400 && !m_resource->shouldIgnoreHTTPStatusCodeErrors())
451         return;
452     ASSERT(m_state == Initialized);
453
454     // Reference the object in this method since the additional processing can do
455     // anything including removing the last reference to this object.
456     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
457
458     // FIXME: If we get a resource with more than 2B bytes, this code won't do the right thing.
459     // However, with today's computers and networking speeds, this won't happen in practice.
460     // Could be an issue with a giant local file.
461     m_host->didReceiveData(m_resource, data, length, encodedDataLength);
462     if (m_state == Terminated)
463         return;
464     RELEASE_ASSERT(length >= 0);
465     m_resource->appendData(data, length);
466 }
467
468 void ResourceLoader::didFinishLoading(blink::WebURLLoader*, double finishTime, int64_t encodedDataLength)
469 {
470     RELEASE_ASSERT(m_connectionState == ConnectionStateReceivedResponse || m_connectionState == ConnectionStateReceivingData);
471     m_connectionState = ConnectionStateFinishedLoading;
472     if (m_state != Initialized)
473         return;
474     ASSERT(m_state != Terminated);
475     WTF_LOG(ResourceLoading, "Received '%s'.", m_resource->url().string().latin1().data());
476
477     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
478     ResourcePtr<Resource> protectResource(m_resource);
479     m_state = Finishing;
480     m_resource->setLoadFinishTime(finishTime);
481     didFinishLoadingOnePart(finishTime, encodedDataLength);
482     if (m_state == Terminated)
483         return;
484     m_resource->finish();
485
486     // If the load has been cancelled by a delegate in response to didFinishLoad(), do not release
487     // the resources a second time, they have been released by cancel.
488     if (m_state == Terminated)
489         return;
490     releaseResources();
491 }
492
493 void ResourceLoader::didFail(blink::WebURLLoader*, const blink::WebURLError& error)
494 {
495     m_connectionState = ConnectionStateFailed;
496     ASSERT(m_state != Terminated);
497     WTF_LOG(ResourceLoading, "Failed to load '%s'.\n", m_resource->url().string().latin1().data());
498
499     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
500     RefPtrWillBeRawPtr<ResourceLoaderHost> protectHost(m_host.get());
501     ResourcePtr<Resource> protectResource(m_resource);
502     m_state = Finishing;
503     m_resource->setResourceError(error);
504
505     if (!m_notifiedLoadComplete) {
506         didComplete();
507         m_host->didFailLoading(m_resource, error);
508     }
509     if (m_state == Terminated)
510         return;
511
512     m_resource->error(Resource::LoadError);
513
514     if (m_state == Terminated)
515         return;
516
517     releaseResources();
518 }
519
520 bool ResourceLoader::isLoadedBy(ResourceLoaderHost* loader) const
521 {
522     return m_host->isLoadedBy(loader);
523 }
524
525 void ResourceLoader::requestSynchronously()
526 {
527     OwnPtr<blink::WebURLLoader> loader = adoptPtr(blink::Platform::current()->createURLLoader());
528     ASSERT(loader);
529
530     // downloadToFile is not supported for synchronous requests.
531     ASSERT(!m_request.downloadToFile());
532
533     RefPtrWillBeRawPtr<ResourceLoader> protect(this);
534     RefPtrWillBeRawPtr<ResourceLoaderHost> protectHost(m_host.get());
535     ResourcePtr<Resource> protectResource(m_resource);
536
537     RELEASE_ASSERT(m_connectionState == ConnectionStateNew);
538     m_connectionState = ConnectionStateStarted;
539
540     blink::WrappedResourceRequest requestIn(m_request);
541     blink::WebURLResponse responseOut;
542     responseOut.initialize();
543     blink::WebURLError errorOut;
544     blink::WebData dataOut;
545     loader->loadSynchronously(requestIn, responseOut, errorOut, dataOut);
546     if (errorOut.reason) {
547         didFail(0, errorOut);
548         return;
549     }
550     didReceiveResponse(0, responseOut);
551     if (m_state == Terminated)
552         return;
553     RefPtr<ResourceLoadInfo> resourceLoadInfo = responseOut.toResourceResponse().resourceLoadInfo();
554     int64_t encodedDataLength = resourceLoadInfo ? resourceLoadInfo->encodedDataLength : blink::WebURLLoaderClient::kUnknownEncodedDataLength;
555     m_host->didReceiveData(m_resource, dataOut.data(), dataOut.size(), encodedDataLength);
556     m_resource->setResourceBuffer(dataOut);
557     didFinishLoading(0, monotonicallyIncreasingTime(), encodedDataLength);
558 }
559
560 void ResourceLoader::didComplete()
561 {
562     m_notifiedLoadComplete = true;
563     m_requestCountTracker.clear();
564 }
565
566 ResourceRequest& ResourceLoader::applyOptions(ResourceRequest& request) const
567 {
568     request.setAllowStoredCredentials(m_options.allowCredentials == AllowStoredCredentials);
569     return request;
570 }
571
572 }