| 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)
|
|
|