Index: Source/modules/fetch/FetchManager.cpp |
diff --git a/Source/modules/fetch/FetchManager.cpp b/Source/modules/fetch/FetchManager.cpp |
index e6739b2eef20b54b1537a0e9ab3f33c0c818acd8..71c21cf4fd30e3ddad8d3a8a4490f756f58af679 100644 |
--- a/Source/modules/fetch/FetchManager.cpp |
+++ b/Source/modules/fetch/FetchManager.cpp |
@@ -155,6 +155,7 @@ private: |
void performBasicFetch(); |
void performNetworkError(const String& message); |
void performHTTPFetch(bool corsFlag, bool corsPreflightFlag); |
+ void performDataFetch(); |
void failed(const String& message); |
void notifyFinished(); |
Document* document() const; |
@@ -202,11 +203,38 @@ void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo |
{ |
ASSERT(handle); |
+ if (response.url().protocolIs("blob") && response.httpStatusCode() == 404) { |
+ // "If |blob| is null, return a network error." |
+ // https://fetch.spec.whatwg.org/#concept-basic-fetch |
+ performNetworkError("Blob not found."); |
+ return; |
+ } |
+ |
m_responseHttpStatusCode = response.httpStatusCode(); |
- // Recompute the tainting if the request was redirected to a different |
- // origin. |
- if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request->origin().get())) { |
+ if (response.url().protocolIsData()) { |
+ if (m_request->url().protocolIsData()) { |
+ // A direct request to data. |
+ m_request->setResponseTainting(FetchRequestData::BasicTainting); |
+ } else { |
+ // A redirect to data: scheme occured. |
+ switch (m_request->mode()) { |
+ case WebURLRequest::FetchRequestModeSameOrigin: |
+ ASSERT_NOT_REACHED(); |
+ break; |
+ case WebURLRequest::FetchRequestModeNoCORS: |
+ m_request->setResponseTainting(FetchRequestData::OpaqueTainting); |
+ break; |
+ case WebURLRequest::FetchRequestModeCORS: |
+ case WebURLRequest::FetchRequestModeCORSWithForcedPreflight: |
+ performNetworkError("Fetch API cannot load " + m_request->url().string() + ". Redirects to data: URL are allowed only when mode is \"no-cors\"."); |
+ return; |
+ break; |
+ } |
+ } |
+ } else if (!SecurityOrigin::create(response.url())->isSameSchemeHostPort(m_request->origin().get())) { |
+ // Recompute the tainting if the request was redirected to a different |
+ // origin. |
switch (m_request->mode()) { |
case WebURLRequest::FetchRequestModeSameOrigin: |
ASSERT_NOT_REACHED(); |
@@ -270,6 +298,13 @@ void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceRespo |
} |
Response* r = Response::create(m_resolver->executionContext(), taintedResponse); |
+ if (response.url().protocolIsData()) { |
+ // An "Access-Control-Allow-Origin" header is added for data: URLs |
+ // but no headers except for "Content-Type" should exist, |
+ // according to the spec: |
+ // https://fetch.spec.whatwg.org/#concept-basic-fetch |
+ r->headers()->headerList()->remove("Access-Control-Allow-Origin"); |
+ } |
r->headers()->setGuard(Headers::ImmutableGuard); |
if (m_request->integrity().isEmpty()) { |
@@ -446,6 +481,10 @@ void FetchManager::Loader::performBasicFetch() |
if (SchemeRegistry::shouldTreatURLSchemeAsSupportingFetchAPI(m_request->url().protocol())) { |
// "Return the result of performing an HTTP fetch using |request|." |
performHTTPFetch(false, false); |
+ } else if (m_request->url().protocolIsData()) { |
+ performDataFetch(); |
+ } else if (m_request->url().protocolIs("blob")) { |
+ performHTTPFetch(false, false); |
} else { |
// FIXME: implement other protocols. |
performNetworkError("Fetch API cannot load " + m_request->url().string() + ". URL scheme \"" + m_request->url().protocol() + "\" is not supported."); |
@@ -532,6 +571,32 @@ void FetchManager::Loader::performHTTPFetch(bool corsFlag, bool corsPreflightFla |
performNetworkError("Can't create ThreadableLoader"); |
} |
+void FetchManager::Loader::performDataFetch() |
+{ |
+ ASSERT(m_request->url().protocolIsData()); |
+ |
+ ResourceRequest request(m_request->url()); |
+ request.setRequestContext(m_request->context()); |
+ request.setUseStreamOnResponse(true); |
+ request.setHTTPMethod("GET"); |
+ request.setFetchRedirectMode(WebURLRequest::FetchRedirectModeError); |
+ |
+ ResourceLoaderOptions resourceLoaderOptions; |
+ resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; |
+ resourceLoaderOptions.securityOrigin = m_request->origin().get(); |
+ |
+ ThreadableLoaderOptions threadableLoaderOptions; |
+ threadableLoaderOptions.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective; |
+ // We set AllowCrossOriginRequests to allow requests to data: URLs (which |
+ // are considered as cross-origin) in 'same-origin' mode. |
+ threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginRequests; |
+ |
+ InspectorInstrumentation::willStartFetch(executionContext(), this); |
+ m_loader = ThreadableLoader::create(*executionContext(), this, request, threadableLoaderOptions, resourceLoaderOptions); |
+ if (!m_loader) |
+ performNetworkError("Can't create ThreadableLoader"); |
+} |
+ |
void FetchManager::Loader::failed(const String& message) |
{ |
if (m_failed || m_finished) |