Index: Source/modules/serviceworkers/FetchManager.cpp |
diff --git a/Source/modules/serviceworkers/FetchManager.cpp b/Source/modules/serviceworkers/FetchManager.cpp |
deleted file mode 100644 |
index 42d7ab5b54a9c169c422a8aac818cea8313958a3..0000000000000000000000000000000000000000 |
--- a/Source/modules/serviceworkers/FetchManager.cpp |
+++ /dev/null |
@@ -1,386 +0,0 @@ |
-// Copyright 2014 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "config.h" |
-#include "FetchManager.h" |
- |
-#include "bindings/core/v8/ExceptionState.h" |
-#include "bindings/core/v8/ScriptPromiseResolver.h" |
-#include "bindings/core/v8/ScriptState.h" |
-#include "bindings/core/v8/V8ThrowException.h" |
-#include "core/dom/ExceptionCode.h" |
-#include "core/fetch/FetchUtils.h" |
-#include "core/fileapi/Blob.h" |
-#include "core/frame/csp/ContentSecurityPolicy.h" |
-#include "core/loader/ThreadableLoader.h" |
-#include "core/loader/ThreadableLoaderClient.h" |
-#include "modules/serviceworkers/Body.h" |
-#include "modules/serviceworkers/BodyStreamBuffer.h" |
-#include "modules/serviceworkers/FetchRequestData.h" |
-#include "modules/serviceworkers/Response.h" |
-#include "modules/serviceworkers/ResponseInit.h" |
-#include "platform/network/ResourceRequest.h" |
-#include "platform/weborigin/SecurityOrigin.h" |
-#include "public/platform/WebURLRequest.h" |
-#include "wtf/HashSet.h" |
- |
-namespace blink { |
- |
-class FetchManager::Loader : public ThreadableLoaderClient { |
-public: |
- Loader(ExecutionContext*, FetchManager*, PassRefPtr<ScriptPromiseResolver>, const FetchRequestData*); |
- ~Loader() override; |
- void didReceiveResponse(unsigned long, const ResourceResponse&, PassOwnPtr<WebDataConsumerHandle>) override; |
- void didReceiveData(const char*, unsigned) override; |
- void didFinishLoading(unsigned long, double) override; |
- void didFail(const ResourceError&) override; |
- void didFailAccessControlCheck(const ResourceError&) override; |
- void didFailRedirectCheck() override; |
- |
- void start(); |
- void cleanup(); |
- |
-private: |
- void performBasicFetch(); |
- void performNetworkError(const String& message); |
- void performHTTPFetch(); |
- void failed(const String& message); |
- void notifyFinished(); |
- |
- ExecutionContext* m_executionContext; |
- FetchManager* m_fetchManager; |
- RefPtr<ScriptPromiseResolver> m_resolver; |
- Persistent<FetchRequestData> m_request; |
- Persistent<BodyStreamBuffer> m_responseBuffer; |
- RefPtr<ThreadableLoader> m_loader; |
- bool m_corsFlag; |
- bool m_corsPreflightFlag; |
- bool m_failed; |
-}; |
- |
-FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* fetchManager, PassRefPtr<ScriptPromiseResolver> resolver, const FetchRequestData* request) |
- : m_executionContext(executionContext) |
- , m_fetchManager(fetchManager) |
- , m_resolver(resolver) |
- , m_request(request->createCopy()) |
- , m_corsFlag(false) |
- , m_corsPreflightFlag(false) |
- , m_failed(false) |
-{ |
-} |
- |
-FetchManager::Loader::~Loader() |
-{ |
- if (m_loader) |
- m_loader->cancel(); |
-} |
- |
-void FetchManager::Loader::didReceiveResponse(unsigned long, const ResourceResponse& response, PassOwnPtr<WebDataConsumerHandle> handle) |
-{ |
- // FIXME: Use |handle|. |
- ASSERT_UNUSED(handle, !handle); |
- m_responseBuffer = new BodyStreamBuffer(); |
- FetchResponseData* responseData = FetchResponseData::createWithBuffer(m_responseBuffer); |
- responseData->setStatus(response.httpStatusCode()); |
- responseData->setStatusMessage(response.httpStatusText()); |
- for (auto& it : response.httpHeaderFields()) |
- responseData->headerList()->append(it.key, it.value); |
- responseData->setURL(m_request->url()); |
- responseData->setContentTypeForBuffer(response.mimeType()); |
- |
- FetchResponseData* taintedResponse = responseData; |
- switch (m_request->tainting()) { |
- case FetchRequestData::BasicTainting: |
- taintedResponse = responseData->createBasicFilteredResponse(); |
- break; |
- case FetchRequestData::CORSTainting: |
- taintedResponse = responseData->createCORSFilteredResponse(); |
- break; |
- case FetchRequestData::OpaqueTainting: |
- taintedResponse = responseData->createOpaqueFilteredResponse(); |
- break; |
- } |
- m_resolver->resolve(Response::create(m_resolver->executionContext(), taintedResponse)); |
- m_resolver.clear(); |
-} |
- |
-void FetchManager::Loader::didReceiveData(const char* data, unsigned size) |
-{ |
- m_responseBuffer->write(DOMArrayBuffer::create(data, size)); |
-} |
- |
-void FetchManager::Loader::didFinishLoading(unsigned long, double) |
-{ |
- ASSERT(m_responseBuffer); |
- m_responseBuffer->close(); |
- m_responseBuffer.clear(); |
- notifyFinished(); |
-} |
- |
-void FetchManager::Loader::didFail(const ResourceError& error) |
-{ |
- failed("Fetch API cannot load " + error.failingURL() + ". " + error.localizedDescription()); |
-} |
- |
-void FetchManager::Loader::didFailAccessControlCheck(const ResourceError& error) |
-{ |
- failed("Fetch API cannot load " + error.failingURL() + ". " + error.localizedDescription()); |
-} |
- |
-void FetchManager::Loader::didFailRedirectCheck() |
-{ |
- failed("Fetch API cannot load " + m_request->url().string() + ". Redirects are not yet supported."); |
-} |
- |
-void FetchManager::Loader::start() |
-{ |
- // "1. If |request|'s url contains a Known HSTS Host, modify it per the |
- // requirements of the 'URI [sic] Loading and Port Mapping' chapter of HTTP |
- // Strict Transport Security." |
- // FIXME: Implement this. |
- |
- // "2. If |request|'s referrer is not none, set |request|'s referrer to the |
- // result of invoking determine |request|'s referrer." |
- // We set the referrer using workerGlobalScope's URL in |
- // WorkerThreadableLoader. |
- |
- // "3. If |request|'s synchronous flag is unset and fetch is not invoked |
- // recursively, run the remaining steps asynchronously." |
- // We don't support synchronous flag. |
- |
- // "4. Let response be the value corresponding to the first matching |
- // statement:" |
- |
- // "- should fetching |request| be blocked as mixed content returns blocked" |
- // We do mixed content checking in ResourceFetcher. |
- |
- // "- should fetching |request| be blocked as content security returns |
- // blocked" |
- if (!ContentSecurityPolicy::shouldBypassMainWorld(m_executionContext) && !m_executionContext->contentSecurityPolicy()->allowConnectToSource(m_request->url())) { |
- // "A network error." |
- performNetworkError("Refused to connect to '" + m_request->url().elidedString() + "' because it violates the document's Content Security Policy."); |
- return; |
- } |
- |
- // "- |request|'s url's origin is |request|'s origin and the |CORS flag| is |
- // unset" |
- // "- |request|'s url's scheme is 'data' and |request|'s same-origin data |
- // URL flag is set" |
- // "- |request|'s url's scheme is 'about'" |
- if ((SecurityOrigin::create(m_request->url())->isSameSchemeHostPort(m_request->origin().get()) && !m_corsFlag) |
- || (m_request->url().protocolIsData() && m_request->sameOriginDataURLFlag()) |
- || (m_request->url().protocolIsAbout())) { |
- // "The result of performing a basic fetch using request." |
- performBasicFetch(); |
- return; |
- } |
- |
- // "- |request|'s mode is |same-origin|" |
- if (m_request->mode() == WebURLRequest::FetchRequestModeSameOrigin) { |
- // "A network error." |
- performNetworkError("Fetch API cannot load " + m_request->url().string() + ". Request mode is \"same-origin\" but the URL\'s origin is not same as the request origin " + m_request->origin()->toString() + "."); |
- return; |
- } |
- |
- // "- |request|'s mode is |no CORS|" |
- if (m_request->mode() == WebURLRequest::FetchRequestModeNoCORS) { |
- // "Set |request|'s response tainting to |opaque|." |
- m_request->setResponseTainting(FetchRequestData::OpaqueTainting); |
- // "The result of performing a basic fetch using |request|." |
- performBasicFetch(); |
- return; |
- } |
- |
- // "- |request|'s url's scheme is not one of 'http' and 'https'" |
- if (!m_request->url().protocolIsInHTTPFamily()) { |
- // "A network error." |
- performNetworkError("Fetch API cannot load " + m_request->url().string() + ". URL scheme must be \"http\" or \"https\" for CORS request."); |
- return; |
- } |
- |
- // "- |request|'s mode is |CORS-with-forced-preflight|. |
- // "- |request|'s unsafe request flag is set and either |request|'s method |
- // is not a simple method or a header in |request|'s header list is not a |
- // simple header" |
- if (m_request->mode() == WebURLRequest::FetchRequestModeCORSWithForcedPreflight |
- || (m_request->unsafeRequestFlag() |
- && (!FetchUtils::isSimpleMethod(m_request->method()) |
- || m_request->headerList()->containsNonSimpleHeader()))) { |
- // "Set |request|'s response tainting to |CORS|." |
- m_request->setResponseTainting(FetchRequestData::CORSTainting); |
- // "The result of performing an HTTP fetch using |request| with the |
- // |CORS flag| and |CORS preflight flag| set." |
- m_corsFlag = true; |
- m_corsPreflightFlag = true; |
- performHTTPFetch(); |
- return; |
- } |
- |
- // "- Otherwise |
- // Set |request|'s response tainting to |CORS|." |
- m_request->setResponseTainting(FetchRequestData::CORSTainting); |
- // "The result of performing an HTTP fetch using |request| with the |
- // |CORS flag| set." |
- m_corsFlag = true; |
- m_corsPreflightFlag = false; |
- performHTTPFetch(); |
-} |
- |
-void FetchManager::Loader::cleanup() |
-{ |
- // Prevent notification |
- m_fetchManager = 0; |
- |
- if (m_loader) { |
- m_loader->cancel(); |
- m_loader.clear(); |
- } |
-} |
- |
-void FetchManager::Loader::performBasicFetch() |
-{ |
- // "To perform a basic fetch using |request|, switch on |request|'s url's |
- // scheme, and run the associated steps:" |
- if (m_request->url().protocolIsInHTTPFamily()) { |
- // "Return the result of performing an HTTP fetch using |request|." |
- m_corsFlag = false; |
- m_corsPreflightFlag = false; |
- performHTTPFetch(); |
- } else { |
- // FIXME: implement other protocols. |
- performNetworkError("Fetch API cannot load " + m_request->url().string() + ". URL scheme \"" + m_request->url().protocol() + "\" is not supported."); |
- } |
-} |
- |
-void FetchManager::Loader::performNetworkError(const String& message) |
-{ |
- failed(message); |
-} |
- |
-void FetchManager::Loader::performHTTPFetch() |
-{ |
- ASSERT(m_request->url().protocolIsInHTTPFamily()); |
- // CORS preflight fetch procedure is implemented inside DocumentThreadableLoader. |
- |
- // "1. Let |HTTPRequest| be a copy of |request|, except that |HTTPRequest|'s |
- // body is a tee of |request|'s body." |
- // We use ResourceRequest class for HTTPRequest. |
- // FIXME: Support body. |
- ResourceRequest request(m_request->url()); |
- request.setRequestContext(WebURLRequest::RequestContextFetch); |
- request.setHTTPMethod(m_request->method()); |
- const Vector<OwnPtr<FetchHeaderList::Header> >& list = m_request->headerList()->list(); |
- for (size_t i = 0; i < list.size(); ++i) { |
- request.addHTTPHeaderField(AtomicString(list[i]->first), AtomicString(list[i]->second)); |
- } |
- |
- if (m_request->method() != "GET" && m_request->method() != "HEAD") { |
- RefPtr<BlobDataHandle> blobDataHandle = m_request->blobDataHandle(); |
- if (blobDataHandle.get()) { |
- RefPtr<FormData> httpBody(FormData::create()); |
- httpBody->appendBlob(blobDataHandle->uuid(), blobDataHandle); |
- request.setHTTPBody(httpBody); |
- } |
- } |
- |
- // "2. Append `Referer`/empty byte sequence, if |HTTPRequest|'s |referrer| |
- // is none, and `Referer`/|HTTPRequest|'s referrer, serialized and utf-8 |
- // encoded, otherwise, to HTTPRequest's header list. |
- // We set the referrer using workerGlobalScope's URL in |
- // WorkerThreadableLoader. |
- |
- // "3. Append `Host`, ..." |
- // FIXME: Implement this when the spec is fixed. |
- |
- // "4.If |HTTPRequest|'s force Origin header flag is set, append `Origin`/ |
- // |HTTPRequest|'s origin, serialized and utf-8 encoded, to |HTTPRequest|'s |
- // header list." |
- // We set Origin header in updateRequestForAccessControl() called from |
- // DocumentThreadableLoader::makeCrossOriginAccessRequest |
- |
- // "5. Let |credentials flag| be set if either |HTTPRequest|'s credentials |
- // mode is |include|, or |HTTPRequest|'s credentials mode is |same-origin| |
- // and the |CORS flag| is unset, and unset otherwise. |
- ResourceLoaderOptions resourceLoaderOptions; |
- resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData; |
- if (m_request->credentials() == WebURLRequest::FetchCredentialsModeInclude |
- || (m_request->credentials() == WebURLRequest::FetchCredentialsModeSameOrigin && !m_corsFlag)) { |
- resourceLoaderOptions.allowCredentials = AllowStoredCredentials; |
- } |
- |
- ThreadableLoaderOptions threadableLoaderOptions; |
- threadableLoaderOptions.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(m_executionContext) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective; |
- if (m_corsPreflightFlag) |
- threadableLoaderOptions.preflightPolicy = ForcePreflight; |
- if (m_corsFlag) |
- threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl; |
- else |
- threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginRequests; |
- |
- m_loader = ThreadableLoader::create(*m_executionContext, this, request, threadableLoaderOptions, resourceLoaderOptions); |
-} |
- |
-void FetchManager::Loader::failed(const String& message) |
-{ |
- if (m_failed) |
- return; |
- m_failed = true; |
- if (m_responseBuffer) { |
- m_responseBuffer->error(DOMException::create(NetworkError, message)); |
- m_responseBuffer.clear(); |
- } else if (m_resolver) { |
- if (!m_resolver->executionContext() || m_resolver->executionContext()->activeDOMObjectsAreStopped()) |
- return; |
- ScriptState* state = m_resolver->scriptState(); |
- ScriptState::Scope scope(state); |
- m_resolver->reject(V8ThrowException::createTypeError(state->isolate(), message)); |
- } |
- notifyFinished(); |
-} |
- |
-void FetchManager::Loader::notifyFinished() |
-{ |
- if (m_fetchManager) |
- m_fetchManager->onLoaderFinished(this); |
-} |
- |
-FetchManager::FetchManager(ExecutionContext* executionContext) |
- : m_executionContext(executionContext) |
- , m_isStopped(false) |
-{ |
-} |
- |
-FetchManager::~FetchManager() |
-{ |
- if (!m_isStopped) |
- stop(); |
-} |
- |
-ScriptPromise FetchManager::fetch(ScriptState* scriptState, const FetchRequestData* request) |
-{ |
- RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState); |
- ScriptPromise promise = resolver->promise(); |
- |
- OwnPtr<Loader> ownLoader(adoptPtr(new Loader(m_executionContext, this, resolver.release(), request))); |
- Loader* loader = m_loaders.add(ownLoader.release()).storedValue->get(); |
- loader->start(); |
- return promise; |
-} |
- |
-void FetchManager::stop() |
-{ |
- ASSERT(!m_isStopped); |
- m_isStopped = true; |
- for (auto& loader : m_loaders) { |
- loader->cleanup(); |
- } |
-} |
- |
-void FetchManager::onLoaderFinished(Loader* loader) |
-{ |
- // We don't use remove here, becuase it may cause recursive deletion. |
- OwnPtr<Loader> p = m_loaders.take(loader); |
-} |
- |
-} // namespace blink |