Update To 11.40.268.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / loader / DocumentThreadableLoader.cpp
1 /*
2  * Copyright (C) 2011, 2012 Google Inc. All rights reserved.
3  * Copyright (C) 2013, Intel Corporation
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are
7  * met:
8  *
9  *     * Redistributions of source code must retain the above copyright
10  * notice, this list of conditions and the following disclaimer.
11  *     * Redistributions in binary form must reproduce the above
12  * copyright notice, this list of conditions and the following disclaimer
13  * in the documentation and/or other materials provided with the
14  * distribution.
15  *     * Neither the name of Google Inc. nor the names of its
16  * contributors may be used to endorse or promote products derived from
17  * this software without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30  */
31
32 #include "config.h"
33 #include "core/loader/DocumentThreadableLoader.h"
34
35 #include "core/dom/Document.h"
36 #include "core/fetch/CrossOriginAccessControl.h"
37 #include "core/fetch/FetchRequest.h"
38 #include "core/fetch/FetchUtils.h"
39 #include "core/fetch/Resource.h"
40 #include "core/fetch/ResourceFetcher.h"
41 #include "core/frame/FrameConsole.h"
42 #include "core/frame/LocalFrame.h"
43 #include "core/frame/csp/ContentSecurityPolicy.h"
44 #include "core/inspector/InspectorInstrumentation.h"
45 #include "core/inspector/InspectorTraceEvents.h"
46 #include "core/loader/CrossOriginPreflightResultCache.h"
47 #include "core/loader/DocumentThreadableLoaderClient.h"
48 #include "core/loader/FrameLoader.h"
49 #include "core/loader/FrameLoaderClient.h"
50 #include "core/loader/ThreadableLoaderClient.h"
51 #include "platform/SharedBuffer.h"
52 #include "platform/network/ResourceRequest.h"
53 #include "platform/weborigin/SchemeRegistry.h"
54 #include "platform/weborigin/SecurityOrigin.h"
55 #include "public/platform/WebURLRequest.h"
56 #include "wtf/Assertions.h"
57
58 namespace blink {
59
60 void DocumentThreadableLoader::loadResourceSynchronously(Document& document, const ResourceRequest& request, ThreadableLoaderClient& client, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
61 {
62     // The loader will be deleted as soon as this function exits.
63     RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, &client, LoadSynchronously, request, options, resourceLoaderOptions));
64     ASSERT(loader->hasOneRef());
65 }
66
67 PassRefPtr<DocumentThreadableLoader> DocumentThreadableLoader::create(Document& document, ThreadableLoaderClient* client, const ResourceRequest& request, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
68 {
69     RefPtr<DocumentThreadableLoader> loader = adoptRef(new DocumentThreadableLoader(document, client, LoadAsynchronously, request, options, resourceLoaderOptions));
70     if (!loader->resource())
71         loader = nullptr;
72     return loader.release();
73 }
74
75 DocumentThreadableLoader::DocumentThreadableLoader(Document& document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options, const ResourceLoaderOptions& resourceLoaderOptions)
76     : m_client(client)
77     , m_document(document)
78     , m_options(options)
79     , m_resourceLoaderOptions(resourceLoaderOptions)
80     , m_forceDoNotAllowStoredCredentials(false)
81     , m_securityOrigin(m_resourceLoaderOptions.securityOrigin)
82     , m_sameOriginRequest(securityOrigin()->canRequest(request.url()))
83     , m_simpleRequest(true)
84     , m_async(blockingBehavior == LoadAsynchronously)
85     , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout)
86     , m_requestStartedSeconds(0.0)
87 {
88     ASSERT(client);
89     // Setting an outgoing referer is only supported in the async code path.
90     ASSERT(m_async || request.httpReferrer().isEmpty());
91
92     if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) {
93         m_client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are not supported."));
94         return;
95     }
96
97     m_requestStartedSeconds = monotonicallyIncreasingTime();
98
99     // Save any CORS simple headers on the request here. If this request redirects cross-origin, we cancel the old request
100     // create a new one, and copy these headers.
101     const HTTPHeaderMap& headerMap = request.httpHeaderFields();
102     HTTPHeaderMap::const_iterator end = headerMap.end();
103     for (HTTPHeaderMap::const_iterator it = headerMap.begin(); it != end; ++it) {
104         if (FetchUtils::isSimpleHeader(it->key, it->value))
105             m_simpleRequestHeaders.add(it->key, it->value);
106     }
107
108     // If the fetch request will be handled by the ServiceWorker, the
109     // FetchRequestMode of the request must be FetchRequestModeCORS or
110     // FetchRequestModeCORSWithForcedPreflight. Otherwise the ServiceWorker can
111     // return a opaque response which is from the other origin site and the
112     // script in the page can read the content.
113     //
114     // We assume that ServiceWorker is skipped for sync requests by content/
115     // code.
116     if (m_async && !request.skipServiceWorker() && m_document.fetcher()->isControlledByServiceWorker()) {
117         ResourceRequest newRequest(request);
118         // FetchRequestMode should be set by the caller. But the expected value
119         // of FetchRequestMode is not speced yet except for XHR. So we set here.
120         // FIXME: When we support fetch API in document, this value should not
121         // be overridden here.
122         if (options.preflightPolicy == ForcePreflight)
123             newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORSWithForcedPreflight);
124         else
125             newRequest.setFetchRequestMode(WebURLRequest::FetchRequestModeCORS);
126
127         m_fallbackRequestForServiceWorker = adoptPtr(new ResourceRequest(request));
128         m_fallbackRequestForServiceWorker->setSkipServiceWorker(true);
129
130         loadRequest(newRequest, m_resourceLoaderOptions);
131         return;
132     }
133
134     dispatchInitialRequest(request);
135 }
136
137 void DocumentThreadableLoader::dispatchInitialRequest(const ResourceRequest& request)
138 {
139     if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) {
140         loadRequest(request, m_resourceLoaderOptions);
141         return;
142     }
143
144     ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
145
146     makeCrossOriginAccessRequest(request);
147 }
148
149 void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceRequest& request)
150 {
151     ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
152
153     // Cross-origin requests are only allowed certain registered schemes.
154     // We would catch this when checking response headers later, but there
155     // is no reason to send a request, preflighted or not, that's guaranteed
156     // to be denied.
157     if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())) {
158         m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, request.url().string(), "Cross origin requests are only supported for protocol schemes: " + SchemeRegistry::listOfCORSEnabledURLSchemes() + "."));
159         return;
160     }
161
162     // We use isSimpleOrForbiddenRequest() here since |request| may have been
163     // modified in the process of loading (not from the user's input). For
164     // example, referrer. We need to accept them. For security, we must reject
165     // forbidden headers/methods at the point we accept user's input. Not here.
166     if ((m_options.preflightPolicy == ConsiderPreflight && FetchUtils::isSimpleOrForbiddenRequest(request.httpMethod(), request.httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight) {
167         ResourceRequest crossOriginRequest(request);
168         ResourceLoaderOptions crossOriginOptions(m_resourceLoaderOptions);
169         updateRequestForAccessControl(crossOriginRequest, securityOrigin(), effectiveAllowCredentials());
170         loadRequest(crossOriginRequest, crossOriginOptions);
171     } else {
172         m_simpleRequest = false;
173
174         OwnPtr<ResourceRequest> crossOriginRequest = adoptPtr(new ResourceRequest(request));
175         OwnPtr<ResourceLoaderOptions> crossOriginOptions = adoptPtr(new ResourceLoaderOptions(m_resourceLoaderOptions));
176         // Do not set the Origin header for preflight requests.
177         updateRequestForAccessControl(*crossOriginRequest, 0, effectiveAllowCredentials());
178         m_actualRequest = crossOriginRequest.release();
179         m_actualOptions = crossOriginOptions.release();
180
181         bool shouldForcePreflight = InspectorInstrumentation::shouldForceCORSPreflight(&m_document);
182         bool canSkipPreflight = CrossOriginPreflightResultCache::shared().canSkipPreflight(securityOrigin()->toString(), m_actualRequest->url(), effectiveAllowCredentials(), m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields());
183         if (canSkipPreflight && !shouldForcePreflight) {
184             loadActualRequest();
185         } else {
186             ResourceRequest preflightRequest = createAccessControlPreflightRequest(*m_actualRequest, securityOrigin());
187             // Create a ResourceLoaderOptions for preflight.
188             ResourceLoaderOptions preflightOptions = *m_actualOptions;
189             preflightOptions.allowCredentials = DoNotAllowStoredCredentials;
190             loadRequest(preflightRequest, preflightOptions);
191         }
192     }
193 }
194
195 DocumentThreadableLoader::~DocumentThreadableLoader()
196 {
197 }
198
199 void DocumentThreadableLoader::overrideTimeout(unsigned long timeoutMilliseconds)
200 {
201     ASSERT(m_async);
202     ASSERT(m_requestStartedSeconds > 0.0);
203     m_timeoutTimer.stop();
204     // At the time of this method's implementation, it is only ever called by
205     // XMLHttpRequest, when the timeout attribute is set after sending the
206     // request.
207     //
208     // The XHR request says to resolve the time relative to when the request
209     // was initially sent, however other uses of this method may need to
210     // behave differently, in which case this should be re-arranged somehow.
211     if (timeoutMilliseconds) {
212         double elapsedTime = monotonicallyIncreasingTime() - m_requestStartedSeconds;
213         double nextFire = timeoutMilliseconds / 1000.0;
214         double resolvedTime = std::max(nextFire - elapsedTime, 0.0);
215         m_timeoutTimer.startOneShot(resolvedTime, FROM_HERE);
216     }
217 }
218
219 void DocumentThreadableLoader::cancel()
220 {
221     cancelWithError(ResourceError());
222 }
223
224 void DocumentThreadableLoader::cancelWithError(const ResourceError& error)
225 {
226     RefPtr<DocumentThreadableLoader> protect(this);
227
228     // Cancel can re-enter and m_resource might be null here as a result.
229     if (m_client && resource()) {
230         ResourceError errorForCallback = error;
231         if (errorForCallback.isNull()) {
232             // FIXME: This error is sent to the client in didFail(), so it should not be an internal one. Use FrameLoaderClient::cancelledError() instead.
233             errorForCallback = ResourceError(errorDomainBlinkInternal, 0, resource()->url().string(), "Load cancelled");
234             errorForCallback.setIsCancellation(true);
235         }
236         m_client->didFail(errorForCallback);
237     }
238     clearResource();
239     m_client = 0;
240     m_requestStartedSeconds = 0.0;
241 }
242
243 void DocumentThreadableLoader::setDefersLoading(bool value)
244 {
245     if (resource())
246         resource()->setDefersLoading(value);
247 }
248
249 void DocumentThreadableLoader::redirectReceived(Resource* resource, ResourceRequest& request, const ResourceResponse& redirectResponse)
250 {
251     ASSERT(m_client);
252     ASSERT_UNUSED(resource, resource == this->resource());
253     ASSERT(m_async);
254
255     RefPtr<DocumentThreadableLoader> protect(this);
256
257     // FIXME: Support redirect in Fetch API.
258     if (resource->resourceRequest().requestContext() == blink::WebURLRequest::RequestContextFetch) {
259         m_client->didFailRedirectCheck();
260         request = ResourceRequest();
261         return;
262     }
263
264     if (!isAllowedByContentSecurityPolicy(request.url())) {
265         m_client->didFailRedirectCheck();
266         request = ResourceRequest();
267         m_requestStartedSeconds = 0.0;
268         return;
269     }
270
271     // Allow same origin requests to continue after allowing clients to audit the redirect.
272     if (isAllowedRedirect(request.url())) {
273         if (m_client->isDocumentThreadableLoaderClient())
274             static_cast<DocumentThreadableLoaderClient*>(m_client)->willFollowRedirect(request, redirectResponse);
275         return;
276     }
277
278     // When using access control, only simple cross origin requests are allowed to redirect. The new request URL must have a supported
279     // scheme and not contain the userinfo production. In addition, the redirect response must pass the access control check if the
280     // original request was not same-origin.
281     if (m_options.crossOriginRequestPolicy == UseAccessControl) {
282
283         InspectorInstrumentation::didReceiveCORSRedirectResponse(m_document.frame(), resource->identifier(), m_document.frame()->loader().documentLoader(), redirectResponse, 0);
284
285         bool allowRedirect = false;
286         String accessControlErrorDescription;
287
288         if (m_simpleRequest) {
289             allowRedirect = CrossOriginAccessControl::isLegalRedirectLocation(request.url(), accessControlErrorDescription)
290                 && (m_sameOriginRequest || passesAccessControlCheck(redirectResponse, effectiveAllowCredentials(), securityOrigin(), accessControlErrorDescription));
291         } else {
292             accessControlErrorDescription = "The request was redirected to '"+ request.url().string() + "', which is disallowed for cross-origin requests that require preflight.";
293         }
294
295         if (allowRedirect) {
296             // FIXME: consider combining this with CORS redirect handling performed by
297             // CrossOriginAccessControl::handleRedirect().
298             clearResource();
299
300             RefPtr<SecurityOrigin> originalOrigin = SecurityOrigin::create(redirectResponse.url());
301             RefPtr<SecurityOrigin> requestOrigin = SecurityOrigin::create(request.url());
302             // If the original request wasn't same-origin, then if the request URL origin is not same origin with the original URL origin,
303             // set the source origin to a globally unique identifier. (If the original request was same-origin, the origin of the new request
304             // should be the original URL origin.)
305             if (!m_sameOriginRequest && !originalOrigin->isSameSchemeHostPort(requestOrigin.get()))
306                 m_securityOrigin = SecurityOrigin::createUnique();
307             // Force any subsequent requests to use these checks.
308             m_sameOriginRequest = false;
309
310             // Since the request is no longer same-origin, if the user didn't request credentials in
311             // the first place, update our state so we neither request them nor expect they must be allowed.
312             if (m_resourceLoaderOptions.credentialsRequested == ClientDidNotRequestCredentials)
313                 m_forceDoNotAllowStoredCredentials = true;
314
315             // Remove any headers that may have been added by the network layer that cause access control to fail.
316             request.clearHTTPReferrer();
317             request.clearHTTPOrigin();
318             request.clearHTTPUserAgent();
319             // Add any CORS simple request headers which we previously saved from the original request.
320             HTTPHeaderMap::const_iterator end = m_simpleRequestHeaders.end();
321             for (HTTPHeaderMap::const_iterator it = m_simpleRequestHeaders.begin(); it != end; ++it) {
322                 request.setHTTPHeaderField(it->key, it->value);
323             }
324             makeCrossOriginAccessRequest(request);
325             return;
326         }
327
328         ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url().string(), accessControlErrorDescription);
329         m_client->didFailAccessControlCheck(error);
330     } else {
331         m_client->didFailRedirectCheck();
332     }
333     request = ResourceRequest();
334     m_requestStartedSeconds = 0.0;
335 }
336
337 void DocumentThreadableLoader::dataSent(Resource* resource, unsigned long long bytesSent, unsigned long long totalBytesToBeSent)
338 {
339     ASSERT(m_client);
340     ASSERT_UNUSED(resource, resource == this->resource());
341     ASSERT(m_async);
342
343     m_client->didSendData(bytesSent, totalBytesToBeSent);
344 }
345
346 void DocumentThreadableLoader::dataDownloaded(Resource* resource, int dataLength)
347 {
348     ASSERT(m_client);
349     ASSERT_UNUSED(resource, resource == this->resource());
350     ASSERT(!m_actualRequest);
351     ASSERT(m_async);
352
353     m_client->didDownloadData(dataLength);
354 }
355
356 void DocumentThreadableLoader::responseReceived(Resource* resource, const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
357 {
358     ASSERT_UNUSED(resource, resource == this->resource());
359     ASSERT(m_async);
360
361     handleResponse(resource->identifier(), response, handle);
362 }
363
364 void DocumentThreadableLoader::handlePreflightResponse(const ResourceResponse& response)
365 {
366     String accessControlErrorDescription;
367
368     if (!passesAccessControlCheck(response, effectiveAllowCredentials(), securityOrigin(), accessControlErrorDescription)) {
369         handlePreflightFailure(response.url().string(), accessControlErrorDescription);
370         return;
371     }
372
373     if (!passesPreflightStatusCheck(response, accessControlErrorDescription)) {
374         handlePreflightFailure(response.url().string(), accessControlErrorDescription);
375         return;
376     }
377
378     OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new CrossOriginPreflightResultCacheItem(effectiveAllowCredentials()));
379     if (!preflightResult->parse(response, accessControlErrorDescription)
380         || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod(), accessControlErrorDescription)
381         || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeaderFields(), accessControlErrorDescription)) {
382         handlePreflightFailure(response.url().string(), accessControlErrorDescription);
383         return;
384     }
385
386     CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toString(), m_actualRequest->url(), preflightResult.release());
387 }
388
389 void DocumentThreadableLoader::reportResponseReceived(unsigned long identifier, const ResourceResponse& response)
390 {
391     DocumentLoader* loader = m_document.frame()->loader().documentLoader();
392     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "ResourceReceiveResponse", "data", InspectorReceiveResponseEvent::data(identifier, m_document.frame(), response));
393     LocalFrame* frame = m_document.frame();
394     InspectorInstrumentation::didReceiveResourceResponse(frame, identifier, loader, response, resource() ? resource()->loader() : 0);
395     // It is essential that inspector gets resource response BEFORE console.
396     frame->console().reportResourceResponseReceived(loader, identifier, response);
397 }
398
399 void DocumentThreadableLoader::handleResponse(unsigned long identifier, const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle)
400 {
401     ASSERT(m_client);
402
403     if (m_actualRequest) {
404         reportResponseReceived(identifier, response);
405         handlePreflightResponse(response);
406         return;
407     }
408
409     if (response.wasFetchedViaServiceWorker()) {
410         ASSERT(m_fallbackRequestForServiceWorker);
411         if (response.wasFallbackRequiredByServiceWorker()) {
412             loadFallbackRequestForServiceWorker();
413             return;
414         }
415         m_fallbackRequestForServiceWorker = nullptr;
416         m_client->didReceiveResponse(identifier, response, handle);
417         return;
418     }
419
420     ASSERT(!m_fallbackRequestForServiceWorker);
421
422     if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessControl) {
423         String accessControlErrorDescription;
424         if (!passesAccessControlCheck(response, effectiveAllowCredentials(), securityOrigin(), accessControlErrorDescription)) {
425             reportResponseReceived(identifier, response);
426             m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkInternal, 0, response.url().string(), accessControlErrorDescription));
427             return;
428         }
429     }
430
431     m_client->didReceiveResponse(identifier, response, handle);
432 }
433
434 void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data, unsigned dataLength)
435 {
436     ASSERT_UNUSED(resource, resource == this->resource());
437     ASSERT(m_async);
438
439     handleReceivedData(data, dataLength);
440 }
441
442 void DocumentThreadableLoader::handleReceivedData(const char* data, unsigned dataLength)
443 {
444     ASSERT(m_client);
445
446     // Preflight data should be invisible to clients.
447     if (m_actualRequest)
448         return;
449
450     ASSERT(!m_fallbackRequestForServiceWorker);
451
452     m_client->didReceiveData(data, dataLength);
453 }
454
455 void DocumentThreadableLoader::notifyFinished(Resource* resource)
456 {
457     ASSERT(m_client);
458     ASSERT(resource == this->resource());
459     ASSERT(m_async);
460
461     m_timeoutTimer.stop();
462
463     if (resource->errorOccurred())
464         m_client->didFail(resource->resourceError());
465     else
466         handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime());
467 }
468
469 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier, double finishTime)
470 {
471     ASSERT(!m_fallbackRequestForServiceWorker);
472
473     if (m_actualRequest) {
474         ASSERT(!m_sameOriginRequest);
475         ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl);
476         loadActualRequest();
477     } else {
478         // FIXME: Should prevent timeout from being overridden after finished loading, without
479         // resetting m_requestStartedSeconds to 0.0
480         m_client->didFinishLoading(identifier, finishTime);
481     }
482 }
483
484 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer)
485 {
486     ASSERT_UNUSED(timer, timer == &m_timeoutTimer);
487
488     // Using values from net/base/net_error_list.h ERR_TIMED_OUT,
489     // Same as existing FIXME above - this error should be coming from FrameLoaderClient to be identifiable.
490     static const int timeoutError = -7;
491     ResourceError error("net", timeoutError, resource()->url(), String());
492     error.setIsTimeout(true);
493     cancelWithError(error);
494 }
495
496 void DocumentThreadableLoader::loadFallbackRequestForServiceWorker()
497 {
498     clearResource();
499     OwnPtr<ResourceRequest> fallbackRequest(m_fallbackRequestForServiceWorker.release());
500     dispatchInitialRequest(*fallbackRequest);
501 }
502
503 void DocumentThreadableLoader::loadActualRequest()
504 {
505     OwnPtr<ResourceRequest> actualRequest;
506     actualRequest.swap(m_actualRequest);
507     OwnPtr<ResourceLoaderOptions> actualOptions;
508     actualOptions.swap(m_actualOptions);
509
510     actualRequest->setHTTPOrigin(securityOrigin()->toAtomicString());
511
512     clearResource();
513
514     loadRequest(*actualRequest, *actualOptions);
515 }
516
517 void DocumentThreadableLoader::handlePreflightFailure(const String& url, const String& errorDescription)
518 {
519     ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription);
520
521     // Prevent handleSuccessfulFinish() from bypassing access check.
522     m_actualRequest = nullptr;
523
524     // FIXME: Should prevent timeout from being overridden after preflight failure, without
525     // resetting m_requestStartedSeconds to 0.0
526     m_client->didFailAccessControlCheck(error);
527 }
528
529 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, ResourceLoaderOptions resourceLoaderOptions)
530 {
531     // Any credential should have been removed from the cross-site requests.
532     const KURL& requestURL = request.url();
533     ASSERT(m_sameOriginRequest || requestURL.user().isEmpty());
534     ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty());
535
536     // Update resourceLoaderOptions with enforced values.
537     if (m_forceDoNotAllowStoredCredentials)
538         resourceLoaderOptions.allowCredentials = DoNotAllowStoredCredentials;
539     resourceLoaderOptions.securityOrigin = m_securityOrigin;
540     if (m_async) {
541         if (m_actualRequest)
542             resourceLoaderOptions.dataBufferingPolicy = BufferData;
543
544         if (m_options.timeoutMilliseconds > 0)
545             m_timeoutTimer.startOneShot(m_options.timeoutMilliseconds / 1000.0, FROM_HERE);
546
547         FetchRequest newRequest(request, m_options.initiator, resourceLoaderOptions);
548         if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests)
549             newRequest.setOriginRestriction(FetchRequest::NoOriginRestriction);
550         ASSERT(!resource());
551         if (request.requestContext() == blink::WebURLRequest::RequestContextVideo || request.requestContext() == blink::WebURLRequest::RequestContextAudio)
552             setResource(m_document.fetcher()->fetchMedia(newRequest));
553         else
554             setResource(m_document.fetcher()->fetchRawResource(newRequest));
555         if (resource() && resource()->loader()) {
556             unsigned long identifier = resource()->identifier();
557             InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(&m_document, identifier, m_client);
558         }
559         return;
560     }
561
562     FetchRequest fetchRequest(request, m_options.initiator, resourceLoaderOptions);
563     if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests)
564         fetchRequest.setOriginRestriction(FetchRequest::NoOriginRestriction);
565     ResourcePtr<Resource> resource = m_document.fetcher()->fetchSynchronously(fetchRequest);
566     ResourceResponse response = resource ? resource->response() : ResourceResponse();
567     unsigned long identifier = resource ? resource->identifier() : std::numeric_limits<unsigned long>::max();
568     ResourceError error = resource ? resource->resourceError() : ResourceError();
569
570     InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(&m_document, identifier, m_client);
571
572     if (!resource) {
573         m_client->didFail(error);
574         return;
575     }
576
577     // No exception for file:/// resources, see <rdar://problem/4962298>.
578     // Also, if we have an HTTP response, then it wasn't a network error in fact.
579     if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode() <= 0) {
580         m_client->didFail(error);
581         return;
582     }
583
584     // FIXME: A synchronous request does not tell us whether a redirect happened or not, so we guess by comparing the
585     // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was
586     // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials.
587     if (requestURL != response.url() && (!isAllowedByContentSecurityPolicy(response.url()) || !isAllowedRedirect(response.url()))) {
588         m_client->didFailRedirectCheck();
589         return;
590     }
591
592     handleResponse(identifier, response, nullptr);
593
594     SharedBuffer* data = resource->resourceBuffer();
595     if (data)
596         handleReceivedData(data->data(), data->size());
597
598     handleSuccessfulFinish(identifier, 0.0);
599 }
600
601 bool DocumentThreadableLoader::isAllowedRedirect(const KURL& url) const
602 {
603     if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests)
604         return true;
605
606     return m_sameOriginRequest && securityOrigin()->canRequest(url);
607 }
608
609 bool DocumentThreadableLoader::isAllowedByContentSecurityPolicy(const KURL& url) const
610 {
611     if (m_options.contentSecurityPolicyEnforcement != EnforceConnectSrcDirective)
612         return true;
613     return m_document.contentSecurityPolicy()->allowConnectToSource(url);
614 }
615
616 StoredCredentials DocumentThreadableLoader::effectiveAllowCredentials() const
617 {
618     if (m_forceDoNotAllowStoredCredentials)
619         return DoNotAllowStoredCredentials;
620     return m_resourceLoaderOptions.allowCredentials;
621 }
622
623 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const
624 {
625     return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin();
626 }
627
628 } // namespace blink