Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1062)

Unified Diff: Source/modules/serviceworkers/FetchManager.cpp

Issue 399543002: [ServiceWorker] Make fetch() method better conformance with the spec. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: incorporated falken's comment Created 6 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/modules/serviceworkers/FetchManager.h ('k') | Source/modules/serviceworkers/FetchRequestData.h » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/modules/serviceworkers/FetchManager.cpp
diff --git a/Source/modules/serviceworkers/FetchManager.cpp b/Source/modules/serviceworkers/FetchManager.cpp
index b4c32347f02e6f26d0cd7f3198346a5be58d90b0..c79f76f1746473978ab764848fc97b2bd86f8d78 100644
--- a/Source/modules/serviceworkers/FetchManager.cpp
+++ b/Source/modules/serviceworkers/FetchManager.cpp
@@ -14,16 +14,19 @@
#include "core/loader/ThreadableLoader.h"
#include "core/loader/ThreadableLoaderClient.h"
#include "core/xml/XMLHttpRequest.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>, PassOwnPtr<ResourceRequest>);
+ Loader(ExecutionContext*, FetchManager*, PassRefPtr<ScriptPromiseResolver>, PassRefPtr<FetchRequestData>);
~Loader();
virtual void didReceiveResponse(unsigned long, const ResourceResponse&);
virtual void didFinishLoading(unsigned long, double);
@@ -36,25 +39,32 @@ public:
void cleanup();
private:
+ void performBasicFetch();
+ void performNetworkError();
+ void performHTTPFetch();
void failed();
void notifyFinished();
ExecutionContext* m_executionContext;
FetchManager* m_fetchManager;
RefPtr<ScriptPromiseResolver> m_resolver;
- OwnPtr<ResourceRequest> m_request;
+ RefPtr<FetchRequestData> m_request;
RefPtr<ThreadableLoader> m_loader;
ResourceResponse m_response;
long long m_downloadedBlobLength;
+ bool m_corsFlag;
+ bool m_corsPreflightFlag;
bool m_failed;
};
-FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* fetchManager, PassRefPtr<ScriptPromiseResolver> resolver, PassOwnPtr<ResourceRequest> request)
+FetchManager::Loader::Loader(ExecutionContext* executionContext, FetchManager* fetchManager, PassRefPtr<ScriptPromiseResolver> resolver, PassRefPtr<FetchRequestData> request)
: m_executionContext(executionContext)
, m_fetchManager(fetchManager)
, m_resolver(resolver)
- , m_request(request)
+ , m_request(request->createCopy())
, m_downloadedBlobLength(0)
+ , m_corsFlag(false)
+ , m_corsPreflightFlag(false)
, m_failed(false)
{
}
@@ -78,16 +88,28 @@ void FetchManager::Loader::didFinishLoading(unsigned long, double)
blobData->appendFile(filePath);
blobData->setContentType(m_response.mimeType());
}
- ResponseInit responseInit;
- // FIXME: We may have to filter the status when we support CORS.
- // http://fetch.spec.whatwg.org/#concept-filtered-response-opaque
- responseInit.status = m_response.httpStatusCode();
- responseInit.statusText = m_response.httpStatusText();
- // FIXME: fill options.
- RefPtrWillBeRawPtr<Blob> blob = Blob::create(BlobDataHandle::create(blobData.release(), m_downloadedBlobLength));
- // FIXME: Handle response status correctly.
- NonThrowableExceptionState exceptionState;
- m_resolver->resolve(Response::create(blob.get(), responseInit, exceptionState));
+ RefPtr<FetchResponseData> response(FetchResponseData::create());
+ response->setStatus(m_response.httpStatusCode());
+ response->setStatusMessage(m_response.httpStatusText());
+ HTTPHeaderMap::const_iterator end = m_response.httpHeaderFields().end();
+ for (HTTPHeaderMap::const_iterator it = m_response.httpHeaderFields().begin(); it != end; ++it) {
+ response->headerList()->append(it->key, it->value);
+ }
+ response->setBlobDataHandle(BlobDataHandle::create(blobData.release(), m_downloadedBlobLength));
+ response->setURL(m_request->url());
+
+ switch (m_request->tainting()) {
+ case FetchRequestData::BasicTainting:
+ response = response->createBasicFilteredResponse();
+ break;
+ case FetchRequestData::CORSTainting:
+ response = response->createCORSFilteredResponse();
+ break;
+ case FetchRequestData::OpaqueTainting:
+ response = response->createOpaqueFilteredResponse();
+ break;
+ }
+ m_resolver->resolve(Response::create(response.release()));
notifyFinished();
}
@@ -113,13 +135,91 @@ void FetchManager::Loader::didDownloadData(int dataLength)
void FetchManager::Loader::start()
{
- m_request->setDownloadToFile(true);
- ThreadableLoaderOptions options;
- // FIXME: Fill options.
- ResourceLoaderOptions resourceLoaderOptions;
- resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
- // FIXME: Fill resourceLoaderOptions.
- m_loader = ThreadableLoader::create(*m_executionContext, this, *m_request, options, resourceLoaderOptions);
+ // "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
+ // - should fetching |request| be blocked as content security returns
+ // blocked
+ // A network error."
+ // We do mixed content checking and CSP checking in ResourceFetcher.
+
+ // "- |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() == FetchRequestData::SameOriginMode) {
+ // "A network error."
+ performNetworkError();
+ return;
+ }
+
+ // "- |request|'s mode is |no CORS|"
+ if (m_request->mode() == FetchRequestData::NoCORSMode) {
+ // "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();
+ 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() == FetchRequestData::CORSWithForcedPreflight
+ || (m_request->unsafeRequestFlag()
+ && (!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()
@@ -133,6 +233,80 @@ void FetchManager::Loader::cleanup()
}
}
+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();
+ }
+}
+
+void FetchManager::Loader::performNetworkError()
+{
+ failed();
+}
+
+void FetchManager::Loader::performHTTPFetch()
+{
+ // 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(blink::WebURLRequest::RequestContextFetch);
+ request.setDownloadToFile(true);
+ 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));
+ }
+
+ // "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() == FetchRequestData::IncludeCredentials
+ || (m_request->credentials() == FetchRequestData::SameOriginCredentials && !m_corsFlag)) {
+ resourceLoaderOptions.allowCredentials = AllowStoredCredentials;
+ }
+
+ ThreadableLoaderOptions threadableLoaderOptions;
+ 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()
{
if (m_failed)
@@ -162,13 +336,14 @@ FetchManager::~FetchManager()
}
}
-ScriptPromise FetchManager::fetch(ScriptState* scriptState, PassOwnPtr<ResourceRequest> request)
+ScriptPromise FetchManager::fetch(ScriptState* scriptState, PassRefPtr<FetchRequestData> request)
{
RefPtr<ScriptPromiseResolver> resolver = ScriptPromiseResolver::create(scriptState);
ScriptPromise promise = resolver->promise();
- OwnPtr<Loader> loader(adoptPtr(new Loader(m_executionContext, this, resolver.release(), request)));
- (*m_loaders.add(loader.release()).storedValue)->start();
+ 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;
}
@@ -185,14 +360,16 @@ bool FetchManager::isSimpleMethod(const String& method)
bool FetchManager::isForbiddenMethod(const String& method)
{
- // "A forbidden method is a method that is a byte case-insensitive match for one of `CONNECT`, `TRACE`, and `TRACK`."
+ // "A forbidden method is a method that is a byte case-insensitive match for
+ // one of `CONNECT`, `TRACE`, and `TRACK`."
return !XMLHttpRequest::isAllowedHTTPMethod(method);
}
bool FetchManager::isUsefulMethod(const String& method)
{
// "A useful method is a method that is not a forbidden method."
- // "A forbidden method is a method that is a byte case-insensitive match for one of `CONNECT`, `TRACE`, and `TRACK`."
+ // "A forbidden method is a method that is a byte case-insensitive match for
+ // one of `CONNECT`, `TRACE`, and `TRACK`."
return XMLHttpRequest::isAllowedHTTPMethod(method);
}
« no previous file with comments | « Source/modules/serviceworkers/FetchManager.h ('k') | Source/modules/serviceworkers/FetchRequestData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698