OLD | NEW |
1 // Copyright 2014 The Chromium Authors. All rights reserved. | 1 // Copyright 2014 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "config.h" | 5 #include "config.h" |
6 #include "modules/fetch/FetchManager.h" | 6 #include "modules/fetch/FetchManager.h" |
7 | 7 |
8 #include "bindings/core/v8/ExceptionState.h" | 8 #include "bindings/core/v8/ExceptionState.h" |
9 #include "bindings/core/v8/ScriptPromiseResolver.h" | 9 #include "bindings/core/v8/ScriptPromiseResolver.h" |
10 #include "bindings/core/v8/ScriptState.h" | 10 #include "bindings/core/v8/ScriptState.h" |
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
148 Vector<char> m_buffer; | 148 Vector<char> m_buffer; |
149 bool m_finished; | 149 bool m_finished; |
150 }; | 150 }; |
151 | 151 |
152 private: | 152 private: |
153 Loader(ExecutionContext*, FetchManager*, ScriptPromiseResolver*, FetchReques
tData*); | 153 Loader(ExecutionContext*, FetchManager*, ScriptPromiseResolver*, FetchReques
tData*); |
154 | 154 |
155 void performBasicFetch(); | 155 void performBasicFetch(); |
156 void performNetworkError(const String& message); | 156 void performNetworkError(const String& message); |
157 void performHTTPFetch(bool corsFlag, bool corsPreflightFlag); | 157 void performHTTPFetch(bool corsFlag, bool corsPreflightFlag); |
| 158 void performDataFetch(); |
158 void failed(const String& message); | 159 void failed(const String& message); |
159 void notifyFinished(); | 160 void notifyFinished(); |
160 Document* document() const; | 161 Document* document() const; |
161 void loadSucceeded(); | 162 void loadSucceeded(); |
162 | 163 |
163 RawPtrWillBeMember<FetchManager> m_fetchManager; | 164 RawPtrWillBeMember<FetchManager> m_fetchManager; |
164 PersistentWillBeMember<ScriptPromiseResolver> m_resolver; | 165 PersistentWillBeMember<ScriptPromiseResolver> m_resolver; |
165 PersistentWillBeMember<FetchRequestData> m_request; | 166 PersistentWillBeMember<FetchRequestData> m_request; |
166 RefPtr<ThreadableLoader> m_loader; | 167 RefPtr<ThreadableLoader> m_loader; |
167 bool m_failed; | 168 bool m_failed; |
(...skipping 27 matching lines...) Expand all Loading... |
195 visitor->trace(m_resolver); | 196 visitor->trace(m_resolver); |
196 visitor->trace(m_request); | 197 visitor->trace(m_request); |
197 visitor->trace(m_integrityVerifier); | 198 visitor->trace(m_integrityVerifier); |
198 ContextLifecycleObserver::trace(visitor); | 199 ContextLifecycleObserver::trace(visitor); |
199 } | 200 } |
200 | 201 |
201 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo
nse& response, PassOwnPtr<WebDataConsumerHandle> handle) | 202 void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo
nse& response, PassOwnPtr<WebDataConsumerHandle> handle) |
202 { | 203 { |
203 ASSERT(handle); | 204 ASSERT(handle); |
204 | 205 |
| 206 if (response.url().protocolIs("blob") && response.httpStatusCode() == 404) { |
| 207 // "If |blob| is null, return a network error." |
| 208 // https://fetch.spec.whatwg.org/#concept-basic-fetch |
| 209 performNetworkError("Blob not found."); |
| 210 return; |
| 211 } |
| 212 |
205 m_responseHttpStatusCode = response.httpStatusCode(); | 213 m_responseHttpStatusCode = response.httpStatusCode(); |
206 | 214 |
207 // Recompute the tainting if the request was redirected to a different | 215 if (response.url().protocolIsData()) { |
208 // origin. | 216 if (m_request->url().protocolIsData()) { |
209 if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request-
>origin().get())) { | 217 // A direct request to data. |
| 218 m_request->setResponseTainting(FetchRequestData::BasicTainting); |
| 219 } else { |
| 220 // A redirect to data: scheme occured. |
| 221 switch (m_request->mode()) { |
| 222 case WebURLRequest::FetchRequestModeSameOrigin: |
| 223 ASSERT_NOT_REACHED(); |
| 224 break; |
| 225 case WebURLRequest::FetchRequestModeNoCORS: |
| 226 m_request->setResponseTainting(FetchRequestData::OpaqueTainting)
; |
| 227 break; |
| 228 case WebURLRequest::FetchRequestModeCORS: |
| 229 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: |
| 230 performNetworkError("Fetch API cannot load " + m_request->url().
string() + ". Redirects to data: URL are allowed only when mode is \"no-cors\"."
); |
| 231 return; |
| 232 break; |
| 233 } |
| 234 } |
| 235 } else if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_r
equest->origin().get())) { |
| 236 // Recompute the tainting if the request was redirected to a different |
| 237 // origin. |
210 switch (m_request->mode()) { | 238 switch (m_request->mode()) { |
211 case WebURLRequest::FetchRequestModeSameOrigin: | 239 case WebURLRequest::FetchRequestModeSameOrigin: |
212 ASSERT_NOT_REACHED(); | 240 ASSERT_NOT_REACHED(); |
213 break; | 241 break; |
214 case WebURLRequest::FetchRequestModeNoCORS: | 242 case WebURLRequest::FetchRequestModeNoCORS: |
215 m_request->setResponseTainting(FetchRequestData::OpaqueTainting); | 243 m_request->setResponseTainting(FetchRequestData::OpaqueTainting); |
216 break; | 244 break; |
217 case WebURLRequest::FetchRequestModeCORS: | 245 case WebURLRequest::FetchRequestModeCORS: |
218 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: | 246 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: |
219 m_request->setResponseTainting(FetchRequestData::CORSTainting); | 247 m_request->setResponseTainting(FetchRequestData::CORSTainting); |
(...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
263 case FetchRequestData::CORSTainting: | 291 case FetchRequestData::CORSTainting: |
264 taintedResponse = responseData->createCORSFilteredResponse(); | 292 taintedResponse = responseData->createCORSFilteredResponse(); |
265 break; | 293 break; |
266 case FetchRequestData::OpaqueTainting: | 294 case FetchRequestData::OpaqueTainting: |
267 taintedResponse = responseData->createOpaqueFilteredResponse(); | 295 taintedResponse = responseData->createOpaqueFilteredResponse(); |
268 break; | 296 break; |
269 } | 297 } |
270 } | 298 } |
271 | 299 |
272 Response* r = Response::create(m_resolver->executionContext(), taintedRespon
se); | 300 Response* r = Response::create(m_resolver->executionContext(), taintedRespon
se); |
| 301 if (response.url().protocolIsData()) { |
| 302 // An "Access-Control-Allow-Origin" header is added for data: URLs |
| 303 // but no headers except for "Content-Type" should exist, |
| 304 // according to the spec: |
| 305 // https://fetch.spec.whatwg.org/#concept-basic-fetch |
| 306 r->headers()->headerList()->remove("Access-Control-Allow-Origin"); |
| 307 } |
273 r->headers()->setGuard(Headers::ImmutableGuard); | 308 r->headers()->setGuard(Headers::ImmutableGuard); |
274 | 309 |
275 if (m_request->integrity().isEmpty()) { | 310 if (m_request->integrity().isEmpty()) { |
276 m_resolver->resolve(r); | 311 m_resolver->resolve(r); |
277 m_resolver.clear(); | 312 m_resolver.clear(); |
278 } else { | 313 } else { |
279 ASSERT(!m_integrityVerifier); | 314 ASSERT(!m_integrityVerifier); |
280 m_integrityVerifier = new SRIVerifier(handle, updater, r, this, m_reques
t->integrity(), response.url()); | 315 m_integrityVerifier = new SRIVerifier(handle, updater, r, this, m_reques
t->integrity(), response.url()); |
281 } | 316 } |
282 } | 317 } |
(...skipping 156 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
439 } | 474 } |
440 } | 475 } |
441 | 476 |
442 void FetchManager::Loader::performBasicFetch() | 477 void FetchManager::Loader::performBasicFetch() |
443 { | 478 { |
444 // "To perform a basic fetch using |request|, switch on |request|'s url's | 479 // "To perform a basic fetch using |request|, switch on |request|'s url's |
445 // scheme, and run the associated steps:" | 480 // scheme, and run the associated steps:" |
446 if (SchemeRegistry::shouldTreatURLSchemeAsSupportingFetchAPI(m_request->url(
).protocol())) { | 481 if (SchemeRegistry::shouldTreatURLSchemeAsSupportingFetchAPI(m_request->url(
).protocol())) { |
447 // "Return the result of performing an HTTP fetch using |request|." | 482 // "Return the result of performing an HTTP fetch using |request|." |
448 performHTTPFetch(false, false); | 483 performHTTPFetch(false, false); |
| 484 } else if (m_request->url().protocolIsData()) { |
| 485 performDataFetch(); |
| 486 } else if (m_request->url().protocolIs("blob")) { |
| 487 performHTTPFetch(false, false); |
449 } else { | 488 } else { |
450 // FIXME: implement other protocols. | 489 // FIXME: implement other protocols. |
451 performNetworkError("Fetch API cannot load " + m_request->url().string()
+ ". URL scheme \"" + m_request->url().protocol() + "\" is not supported."); | 490 performNetworkError("Fetch API cannot load " + m_request->url().string()
+ ". URL scheme \"" + m_request->url().protocol() + "\" is not supported."); |
452 } | 491 } |
453 } | 492 } |
454 | 493 |
455 void FetchManager::Loader::performNetworkError(const String& message) | 494 void FetchManager::Loader::performNetworkError(const String& message) |
456 { | 495 { |
457 failed(message); | 496 failed(message); |
458 } | 497 } |
(...skipping 66 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
525 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: | 564 case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: |
526 threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl; | 565 threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl; |
527 break; | 566 break; |
528 } | 567 } |
529 InspectorInstrumentation::willStartFetch(executionContext(), this); | 568 InspectorInstrumentation::willStartFetch(executionContext(), this); |
530 m_loader = ThreadableLoader::create(*executionContext(), this, request, thre
adableLoaderOptions, resourceLoaderOptions); | 569 m_loader = ThreadableLoader::create(*executionContext(), this, request, thre
adableLoaderOptions, resourceLoaderOptions); |
531 if (!m_loader) | 570 if (!m_loader) |
532 performNetworkError("Can't create ThreadableLoader"); | 571 performNetworkError("Can't create ThreadableLoader"); |
533 } | 572 } |
534 | 573 |
| 574 void FetchManager::Loader::performDataFetch() |
| 575 { |
| 576 ASSERT(m_request->url().protocolIsData()); |
| 577 |
| 578 ResourceRequest request(m_request->url()); |
| 579 request.setRequestContext(m_request->context()); |
| 580 request.setUseStreamOnResponse(true); |
| 581 request.setHTTPMethod("GET"); |
| 582 request.setFetchRedirectMode(WebURLRequest::FetchRedirectModeError); |
| 583 |
| 584 ResourceLoaderOptions resourceLoaderOptions; |
| 585 resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; |
| 586 resourceLoaderOptions.securityOrigin = m_request->origin().get(); |
| 587 |
| 588 ThreadableLoaderOptions threadableLoaderOptions; |
| 589 threadableLoaderOptions.contentSecurityPolicyEnforcement = ContentSecurityPo
licy::shouldBypassMainWorld(executionContext()) ? DoNotEnforceContentSecurityPol
icy : EnforceConnectSrcDirective; |
| 590 // We set AllowCrossOriginRequests to allow requests to data: URLs (which |
| 591 // are considered as cross-origin) in 'same-origin' mode. |
| 592 threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginRequests; |
| 593 |
| 594 InspectorInstrumentation::willStartFetch(executionContext(), this); |
| 595 m_loader = ThreadableLoader::create(*executionContext(), this, request, thre
adableLoaderOptions, resourceLoaderOptions); |
| 596 if (!m_loader) |
| 597 performNetworkError("Can't create ThreadableLoader"); |
| 598 } |
| 599 |
535 void FetchManager::Loader::failed(const String& message) | 600 void FetchManager::Loader::failed(const String& message) |
536 { | 601 { |
537 if (m_failed || m_finished) | 602 if (m_failed || m_finished) |
538 return; | 603 return; |
539 m_failed = true; | 604 m_failed = true; |
540 if (!message.isEmpty()) | 605 if (!message.isEmpty()) |
541 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSo
urce, ErrorMessageLevel, message)); | 606 executionContext()->addConsoleMessage(ConsoleMessage::create(JSMessageSo
urce, ErrorMessageLevel, message)); |
542 if (m_resolver) { | 607 if (m_resolver) { |
543 if (!m_resolver->executionContext() || m_resolver->executionContext()->a
ctiveDOMObjectsAreStopped()) | 608 if (!m_resolver->executionContext() || m_resolver->executionContext()->a
ctiveDOMObjectsAreStopped()) |
544 return; | 609 return; |
(...skipping 56 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
601 | 666 |
602 DEFINE_TRACE(FetchManager) | 667 DEFINE_TRACE(FetchManager) |
603 { | 668 { |
604 #if ENABLE(OILPAN) | 669 #if ENABLE(OILPAN) |
605 visitor->trace(m_executionContext); | 670 visitor->trace(m_executionContext); |
606 visitor->trace(m_loaders); | 671 visitor->trace(m_loaders); |
607 #endif | 672 #endif |
608 } | 673 } |
609 | 674 |
610 } // namespace blink | 675 } // namespace blink |
OLD | NEW |