OLD | NEW |
1 /* | 1 /* |
2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. | 2 * Copyright (C) 2011, 2012 Google Inc. All rights reserved. |
3 * Copyright (C) 2013, Intel Corporation | 3 * Copyright (C) 2013, Intel Corporation |
4 * | 4 * |
5 * Redistribution and use in source and binary forms, with or without | 5 * Redistribution and use in source and binary forms, with or without |
6 * modification, are permitted provided that the following conditions are | 6 * modification, are permitted provided that the following conditions are |
7 * met: | 7 * met: |
8 * | 8 * |
9 * * Redistributions of source code must retain the above copyright | 9 * * Redistributions of source code must retain the above copyright |
10 * notice, this list of conditions and the following disclaimer. | 10 * notice, this list of conditions and the following disclaimer. |
(...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
85 , m_options(options) | 85 , m_options(options) |
86 , m_resourceLoaderOptions(resourceLoaderOptions) | 86 , m_resourceLoaderOptions(resourceLoaderOptions) |
87 , m_forceDoNotAllowStoredCredentials(false) | 87 , m_forceDoNotAllowStoredCredentials(false) |
88 , m_securityOrigin(m_resourceLoaderOptions.securityOrigin) | 88 , m_securityOrigin(m_resourceLoaderOptions.securityOrigin) |
89 , m_sameOriginRequest(securityOrigin()->canRequest(request.url())) | 89 , m_sameOriginRequest(securityOrigin()->canRequest(request.url())) |
90 , m_simpleRequest(true) | 90 , m_simpleRequest(true) |
91 , m_async(blockingBehavior == LoadAsynchronously) | 91 , m_async(blockingBehavior == LoadAsynchronously) |
92 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) | 92 , m_timeoutTimer(this, &DocumentThreadableLoader::didTimeout) |
93 , m_requestStartedSeconds(0.0) | 93 , m_requestStartedSeconds(0.0) |
94 , m_corsRedirectLimit(kMaxCORSRedirects) | 94 , m_corsRedirectLimit(kMaxCORSRedirects) |
95 , m_accessControlCheckFailed(false) | |
96 { | 95 { |
97 ASSERT(client); | 96 ASSERT(client); |
98 // Setting an outgoing referer is only supported in the async code path. | 97 // Setting an outgoing referer is only supported in the async code path. |
99 ASSERT(m_async || request.httpReferrer().isEmpty()); | 98 ASSERT(m_async || request.httpReferrer().isEmpty()); |
100 | 99 |
101 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossO
riginRequests) { | 100 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == DenyCrossO
riginRequests) { |
102 m_client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url
().string(), "Cross origin requests are not supported.")); | 101 m_client->didFail(ResourceError(errorDomainBlinkInternal, 0, request.url
().string(), "Cross origin requests are not supported.")); |
103 return; | 102 return; |
104 } | 103 } |
105 | 104 |
(...skipping 50 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
156 | 155 |
157 void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceReques
t& request) | 156 void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceReques
t& request) |
158 { | 157 { |
159 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); | 158 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); |
160 | 159 |
161 // Cross-origin requests are only allowed certain registered schemes. | 160 // Cross-origin requests are only allowed certain registered schemes. |
162 // We would catch this when checking response headers later, but there | 161 // We would catch this when checking response headers later, but there |
163 // is no reason to send a request, preflighted or not, that's guaranteed | 162 // is no reason to send a request, preflighted or not, that's guaranteed |
164 // to be denied. | 163 // to be denied. |
165 if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protoco
l())) { | 164 if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protoco
l())) { |
166 handleAccessControlCheckFailure(request.url().string(), "Cross origin re
quests are only supported for protocol schemes: " + SchemeRegistry::listOfCORSEn
abledURLSchemes() + "."); | 165 m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkIntern
al, 0, request.url().string(), "Cross origin requests are only supported for pro
tocol schemes: " + SchemeRegistry::listOfCORSEnabledURLSchemes() + ".")); |
167 return; | 166 return; |
168 } | 167 } |
169 | 168 |
170 // We use isSimpleOrForbiddenRequest() here since |request| may have been | 169 // We use isSimpleOrForbiddenRequest() here since |request| may have been |
171 // modified in the process of loading (not from the user's input). For | 170 // modified in the process of loading (not from the user's input). For |
172 // example, referrer. We need to accept them. For security, we must reject | 171 // example, referrer. We need to accept them. For security, we must reject |
173 // forbidden headers/methods at the point we accept user's input. Not here. | 172 // forbidden headers/methods at the point we accept user's input. Not here. |
174 if ((m_options.preflightPolicy == ConsiderPreflight && FetchUtils::isSimpleO
rForbiddenRequest(request.httpMethod(), request.httpHeaderFields())) || m_option
s.preflightPolicy == PreventPreflight) { | 173 if ((m_options.preflightPolicy == ConsiderPreflight && FetchUtils::isSimpleO
rForbiddenRequest(request.httpMethod(), request.httpHeaderFields())) || m_option
s.preflightPolicy == PreventPreflight) { |
175 ResourceRequest crossOriginRequest(request); | 174 ResourceRequest crossOriginRequest(request); |
176 ResourceLoaderOptions crossOriginOptions(m_resourceLoaderOptions); | 175 ResourceLoaderOptions crossOriginOptions(m_resourceLoaderOptions); |
(...skipping 152 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
329 request.clearHTTPReferrer(); | 328 request.clearHTTPReferrer(); |
330 request.clearHTTPOrigin(); | 329 request.clearHTTPOrigin(); |
331 request.clearHTTPUserAgent(); | 330 request.clearHTTPUserAgent(); |
332 // Add any CORS simple request headers which we previously saved fro
m the original request. | 331 // Add any CORS simple request headers which we previously saved fro
m the original request. |
333 for (const auto& header : m_simpleRequestHeaders) | 332 for (const auto& header : m_simpleRequestHeaders) |
334 request.setHTTPHeaderField(header.key, header.value); | 333 request.setHTTPHeaderField(header.key, header.value); |
335 makeCrossOriginAccessRequest(request); | 334 makeCrossOriginAccessRequest(request); |
336 return; | 335 return; |
337 } | 336 } |
338 | 337 |
339 handleAccessControlCheckFailure(redirectResponse.url().string(), accessC
ontrolErrorDescription); | 338 ResourceError error(errorDomainBlinkInternal, 0, redirectResponse.url().
string(), accessControlErrorDescription); |
| 339 m_client->didFailAccessControlCheck(error); |
340 } else { | 340 } else { |
341 m_client->didFailRedirectCheck(); | 341 m_client->didFailRedirectCheck(); |
342 } | 342 } |
343 | 343 |
344 clearResource(); | 344 clearResource(); |
345 request = ResourceRequest(); | 345 request = ResourceRequest(); |
346 | 346 |
347 m_requestStartedSeconds = 0.0; | 347 m_requestStartedSeconds = 0.0; |
348 } | 348 } |
349 | 349 |
(...skipping 22 matching lines...) Expand all Loading... |
372 ASSERT(m_async); | 372 ASSERT(m_async); |
373 | 373 |
374 handleResponse(resource->identifier(), response, handle); | 374 handleResponse(resource->identifier(), response, handle); |
375 } | 375 } |
376 | 376 |
377 void DocumentThreadableLoader::handlePreflightResponse(const ResourceResponse& r
esponse) | 377 void DocumentThreadableLoader::handlePreflightResponse(const ResourceResponse& r
esponse) |
378 { | 378 { |
379 String accessControlErrorDescription; | 379 String accessControlErrorDescription; |
380 | 380 |
381 if (!passesAccessControlCheck(&m_document, response, effectiveAllowCredentia
ls(), securityOrigin(), accessControlErrorDescription)) { | 381 if (!passesAccessControlCheck(&m_document, response, effectiveAllowCredentia
ls(), securityOrigin(), accessControlErrorDescription)) { |
382 handleAccessControlCheckFailure(response.url().string(), accessControlEr
rorDescription); | 382 handlePreflightFailure(response.url().string(), accessControlErrorDescri
ption); |
383 return; | 383 return; |
384 } | 384 } |
385 | 385 |
386 if (!passesPreflightStatusCheck(response, accessControlErrorDescription)) { | 386 if (!passesPreflightStatusCheck(response, accessControlErrorDescription)) { |
387 handleAccessControlCheckFailure(response.url().string(), accessControlEr
rorDescription); | 387 handlePreflightFailure(response.url().string(), accessControlErrorDescri
ption); |
388 return; | 388 return; |
389 } | 389 } |
390 | 390 |
391 OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new C
rossOriginPreflightResultCacheItem(effectiveAllowCredentials())); | 391 OwnPtr<CrossOriginPreflightResultCacheItem> preflightResult = adoptPtr(new C
rossOriginPreflightResultCacheItem(effectiveAllowCredentials())); |
392 if (!preflightResult->parse(response, accessControlErrorDescription) | 392 if (!preflightResult->parse(response, accessControlErrorDescription) |
393 || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod
(), accessControlErrorDescription) | 393 || !preflightResult->allowsCrossOriginMethod(m_actualRequest->httpMethod
(), accessControlErrorDescription) |
394 || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeade
rFields(), accessControlErrorDescription)) { | 394 || !preflightResult->allowsCrossOriginHeaders(m_actualRequest->httpHeade
rFields(), accessControlErrorDescription)) { |
395 handleAccessControlCheckFailure(response.url().string(), accessControlEr
rorDescription); | 395 handlePreflightFailure(response.url().string(), accessControlErrorDescri
ption); |
396 return; | 396 return; |
397 } | 397 } |
398 | 398 |
399 CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toSt
ring(), m_actualRequest->url(), preflightResult.release()); | 399 CrossOriginPreflightResultCache::shared().appendEntry(securityOrigin()->toSt
ring(), m_actualRequest->url(), preflightResult.release()); |
400 } | 400 } |
401 | 401 |
402 void DocumentThreadableLoader::reportResponseReceived(unsigned long identifier,
const ResourceResponse& response) | 402 void DocumentThreadableLoader::reportResponseReceived(unsigned long identifier,
const ResourceResponse& response) |
403 { | 403 { |
404 DocumentLoader* loader = m_document.frame()->loader().documentLoader(); | 404 DocumentLoader* loader = m_document.frame()->loader().documentLoader(); |
405 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Resour
ceReceiveResponse", "data", InspectorReceiveResponseEvent::data(identifier, m_do
cument.frame(), response)); | 405 TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("devtools.timeline"), "Resour
ceReceiveResponse", "data", InspectorReceiveResponseEvent::data(identifier, m_do
cument.frame(), response)); |
(...skipping 23 matching lines...) Expand all Loading... |
429 m_client->didReceiveResponse(identifier, response, handle); | 429 m_client->didReceiveResponse(identifier, response, handle); |
430 return; | 430 return; |
431 } | 431 } |
432 | 432 |
433 ASSERT(!m_fallbackRequestForServiceWorker); | 433 ASSERT(!m_fallbackRequestForServiceWorker); |
434 | 434 |
435 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessC
ontrol) { | 435 if (!m_sameOriginRequest && m_options.crossOriginRequestPolicy == UseAccessC
ontrol) { |
436 String accessControlErrorDescription; | 436 String accessControlErrorDescription; |
437 if (!passesAccessControlCheck(&m_document, response, effectiveAllowCrede
ntials(), securityOrigin(), accessControlErrorDescription)) { | 437 if (!passesAccessControlCheck(&m_document, response, effectiveAllowCrede
ntials(), securityOrigin(), accessControlErrorDescription)) { |
438 reportResponseReceived(identifier, response); | 438 reportResponseReceived(identifier, response); |
439 handleAccessControlCheckFailure(response.url().string(), accessContr
olErrorDescription); | 439 m_client->didFailAccessControlCheck(ResourceError(errorDomainBlinkIn
ternal, 0, response.url().string(), accessControlErrorDescription)); |
440 return; | 440 return; |
441 } | 441 } |
442 } | 442 } |
443 | 443 |
444 m_client->didReceiveResponse(identifier, response, handle); | 444 m_client->didReceiveResponse(identifier, response, handle); |
445 } | 445 } |
446 | 446 |
447 void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data
, unsigned dataLength) | 447 void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data
, unsigned dataLength) |
448 { | 448 { |
449 ASSERT_UNUSED(resource, resource == this->resource()); | 449 ASSERT_UNUSED(resource, resource == this->resource()); |
450 ASSERT(m_async); | 450 ASSERT(m_async); |
451 | 451 |
452 handleReceivedData(data, dataLength); | 452 handleReceivedData(data, dataLength); |
453 } | 453 } |
454 | 454 |
455 void DocumentThreadableLoader::handleReceivedData(const char* data, unsigned dat
aLength) | 455 void DocumentThreadableLoader::handleReceivedData(const char* data, unsigned dat
aLength) |
456 { | 456 { |
457 ASSERT(m_client); | 457 ASSERT(m_client); |
458 | 458 |
459 // Preflight data should be invisible to clients. | 459 // Preflight data should be invisible to clients. |
460 if (m_actualRequest) | 460 if (m_actualRequest) |
461 return; | 461 return; |
462 | 462 |
463 ASSERT(!m_fallbackRequestForServiceWorker); | 463 ASSERT(!m_fallbackRequestForServiceWorker); |
464 | 464 |
465 if (!m_accessControlCheckFailed) | 465 m_client->didReceiveData(data, dataLength); |
466 m_client->didReceiveData(data, dataLength); | |
467 } | 466 } |
468 | 467 |
469 void DocumentThreadableLoader::notifyFinished(Resource* resource) | 468 void DocumentThreadableLoader::notifyFinished(Resource* resource) |
470 { | 469 { |
471 ASSERT(m_client); | 470 ASSERT(m_client); |
472 ASSERT(resource == this->resource()); | 471 ASSERT(resource == this->resource()); |
473 ASSERT(m_async); | 472 ASSERT(m_async); |
474 | 473 |
475 m_timeoutTimer.stop(); | 474 m_timeoutTimer.stop(); |
476 | 475 |
477 if (resource->errorOccurred()) | 476 if (resource->errorOccurred()) |
478 m_client->didFail(resource->resourceError()); | 477 m_client->didFail(resource->resourceError()); |
479 else | 478 else |
480 handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime(
)); | 479 handleSuccessfulFinish(resource->identifier(), resource->loadFinishTime(
)); |
481 } | 480 } |
482 | 481 |
483 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier,
double finishTime) | 482 void DocumentThreadableLoader::handleSuccessfulFinish(unsigned long identifier,
double finishTime) |
484 { | 483 { |
485 ASSERT(!m_fallbackRequestForServiceWorker); | 484 ASSERT(!m_fallbackRequestForServiceWorker); |
486 | 485 |
487 if (m_actualRequest) { | 486 if (m_actualRequest) { |
488 ASSERT(!m_sameOriginRequest); | 487 ASSERT(!m_sameOriginRequest); |
489 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); | 488 ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); |
490 loadActualRequest(); | 489 loadActualRequest(); |
491 } else { | 490 } else { |
492 // FIXME: Should prevent timeout from being overridden after finished lo
ading, without | 491 // FIXME: Should prevent timeout from being overridden after finished lo
ading, without |
493 // resetting m_requestStartedSeconds to 0.0 | 492 // resetting m_requestStartedSeconds to 0.0 |
494 if (!m_accessControlCheckFailed) | 493 m_client->didFinishLoading(identifier, finishTime); |
495 m_client->didFinishLoading(identifier, finishTime); | |
496 } | 494 } |
497 } | 495 } |
498 | 496 |
499 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer
) | 497 void DocumentThreadableLoader::didTimeout(Timer<DocumentThreadableLoader>* timer
) |
500 { | 498 { |
501 ASSERT_UNUSED(timer, timer == &m_timeoutTimer); | 499 ASSERT_UNUSED(timer, timer == &m_timeoutTimer); |
502 | 500 |
503 // Using values from net/base/net_error_list.h ERR_TIMED_OUT, | 501 // Using values from net/base/net_error_list.h ERR_TIMED_OUT, |
504 // Same as existing FIXME above - this error should be coming from FrameLoad
erClient to be identifiable. | 502 // Same as existing FIXME above - this error should be coming from FrameLoad
erClient to be identifiable. |
505 static const int timeoutError = -7; | 503 static const int timeoutError = -7; |
(...skipping 16 matching lines...) Expand all Loading... |
522 OwnPtr<ResourceLoaderOptions> actualOptions; | 520 OwnPtr<ResourceLoaderOptions> actualOptions; |
523 actualOptions.swap(m_actualOptions); | 521 actualOptions.swap(m_actualOptions); |
524 | 522 |
525 actualRequest->setHTTPOrigin(securityOrigin()->toAtomicString()); | 523 actualRequest->setHTTPOrigin(securityOrigin()->toAtomicString()); |
526 | 524 |
527 clearResource(); | 525 clearResource(); |
528 | 526 |
529 loadRequest(*actualRequest, *actualOptions); | 527 loadRequest(*actualRequest, *actualOptions); |
530 } | 528 } |
531 | 529 |
532 void DocumentThreadableLoader::handleAccessControlCheckFailure(const String& url
, const String& errorDescription) | 530 void DocumentThreadableLoader::handlePreflightFailure(const String& url, const S
tring& errorDescription) |
533 { | 531 { |
534 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription); | 532 ResourceError error(errorDomainBlinkInternal, 0, url, errorDescription); |
535 | 533 |
536 // Prevent handleSuccessfulFinish() from bypassing access check. | 534 // Prevent handleSuccessfulFinish() from bypassing access check. |
537 m_actualRequest = nullptr; | 535 m_actualRequest = nullptr; |
538 | 536 |
539 // Prevent m_client->didReceiveData()/didFinishLoading() from being called | |
540 // after m_client->didFailAccessControlCheck() is called here. | |
541 // FIXME: It is cleaner to call clearResource() etc. where we should not | |
542 // proceed any more. | |
543 m_accessControlCheckFailed = true; | |
544 | |
545 // FIXME: Should prevent timeout from being overridden after preflight failu
re, without | 537 // FIXME: Should prevent timeout from being overridden after preflight failu
re, without |
546 // resetting m_requestStartedSeconds to 0.0 | 538 // resetting m_requestStartedSeconds to 0.0 |
547 m_client->didFailAccessControlCheck(error); | 539 m_client->didFailAccessControlCheck(error); |
548 } | 540 } |
549 | 541 |
550 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou
rceLoaderOptions resourceLoaderOptions) | 542 void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, Resou
rceLoaderOptions resourceLoaderOptions) |
551 { | 543 { |
552 // Any credential should have been removed from the cross-site requests. | 544 // Any credential should have been removed from the cross-site requests. |
553 const KURL& requestURL = request.url(); | 545 const KURL& requestURL = request.url(); |
554 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); | 546 ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); |
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
640 return DoNotAllowStoredCredentials; | 632 return DoNotAllowStoredCredentials; |
641 return m_resourceLoaderOptions.allowCredentials; | 633 return m_resourceLoaderOptions.allowCredentials; |
642 } | 634 } |
643 | 635 |
644 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const | 636 SecurityOrigin* DocumentThreadableLoader::securityOrigin() const |
645 { | 637 { |
646 return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin
(); | 638 return m_securityOrigin ? m_securityOrigin.get() : m_document.securityOrigin
(); |
647 } | 639 } |
648 | 640 |
649 } // namespace blink | 641 } // namespace blink |
OLD | NEW |