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

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

Issue 333423004: moved to https://codereview.chromium.org/399543002/ (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebase 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/FetchResponseData.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 13e416c26af123d8ed16bbe52b637ee4b7304fb5..4f56b4710b31d7218d8de2f4beaa070eaf7415ad 100644
--- a/Source/modules/serviceworkers/FetchManager.cpp
+++ b/Source/modules/serviceworkers/FetchManager.cpp
@@ -5,6 +5,7 @@
#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"
@@ -16,13 +17,15 @@
#include "modules/serviceworkers/Response.h"
#include "modules/serviceworkers/ResponseInit.h"
#include "platform/network/ResourceRequest.h"
+#include "platform/weborigin/SecurityOrigin.h"
+#include "public/platform/WebServiceWorkerRequest.h"
#include "wtf/HashSet.h"
namespace WebCore {
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);
@@ -35,20 +38,23 @@ public:
void cleanup();
private:
+ void performBasicFetch();
+ void performNetworkError();
+ void performeHTTPFetch(bool, bool);
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_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)
@@ -77,15 +83,28 @@ void FetchManager::Loader::didFinishLoading(unsigned long, double)
blobData->appendFile(filePath);
// FIXME: Set the ContentType correctly.
}
- 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.
- m_resolver->resolve(Response::create(blob.get(), responseInit));
+ 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();
}
@@ -111,13 +130,79 @@ 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);
+
+ // FIXME: 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. [HSTS]
+
+ // FIXME: 2. If request's referrer is not none, set request's referrer to the result of invoking determine request's referrer. [REFERRER]
+
+ // FIXME: 3. If request's synchronous flag is unset and fetch is not invoked recursively, run the remaining steps asynchronously.
+
+ // FIXME: 4. Let response be the value corresponding to the first matching statement:
+ // - should fetching request be blocked as mixed content returns blocked [MIX]
+ // - should fetching request be blocked as content security returns blocked [CSP]
+ // A network error.
+
+ // - 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 ((m_request->mode() != FetchRequestData::CORSMode
+ && m_request->mode() != FetchRequestData::CORSWithForcedPreflight
+ && SecurityOrigin::create(m_request->url())->isSameSchemeHostPort(m_request->origin().get()))
+ || (m_request->url().protocol() == "data" && m_request->sameOriginDataURLFlag())
+ || (m_request->url().protocol() == "about")) {
+ // 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().protocol() != "http" && m_request->url().protocol() != "https") {
+ // A network error.
+ performNetworkError();
+ return;
+ }
+
+ // - request's mode is CORS-with-forced-preflight
+ if (m_request->mode() == FetchRequestData::CORSWithForcedPreflight) {
+ // 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.
+ performeHTTPFetch(true, true);
+ return;
+ }
+
+ // - 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->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.
+ performeHTTPFetch(true, true);
+ 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.
+ performeHTTPFetch(true, false);
}
void FetchManager::Loader::cleanup()
@@ -131,6 +216,87 @@ 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:
+ String protocol(m_request->url().protocol());
+ if (protocol == "about") {
+ // If request's url's scheme data is "blank", return a response whose
+ // header list consist of a single header whose name is `Content-Type`
+ // and value is `text/html;charset=utf-8`, and body is the empty byte
+ // sequence.
+ // FIXME: implement this.
+ performNetworkError();
+ } else if (protocol == "blob") {
+ // It has been argued this should be handled outside of fetching.
+ performNetworkError();
+ } else if (protocol == "data") {
+ // If request's method is `GET` and obtaining a resource from request's
+ // url does not return failure, return a response whose header list
+ // consist of a single header whose name is `Content-Type` and value is
+ // the MIME type and parameters returned from obtaining a resource, and
+ // body is the data returned from obtaining a resource. [DATAURL]
+ // Otherwise, return a network error.
+ // FIXME: implement this.
+ performNetworkError();
+ } else if (protocol == "file" || protocol == "ftp") {
+ // For now, unfortunate as it is, file and ftp URLs are left as an
+ // exercise for the reader.
+ // When in doubt, return a network error.
+ performNetworkError();
+ } else if (protocol == "http" || protocol == "https") {
+ // Return the result of performing an HTTP fetch using request.
+ performeHTTPFetch(false, false);
+ } else {
+ // Return a network error.
+ performNetworkError();
+ }
+}
+
+void FetchManager::Loader::performNetworkError()
+{
+ failed();
+}
+
+void FetchManager::Loader::performeHTTPFetch(bool CORSFlag, bool CORSPreflightFlag)
+{
+ ResourceRequest request(m_request->url());
+ request.setDownloadToFile(true);
+ request.setHTTPMethod(m_request->method());
+
+ // 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.
+ // FIXME: Support Referer.
+ 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));
+ }
+
+
+ ThreadableLoaderOptions threadableLoaderOptions;
+ if (CORSPreflightFlag)
+ threadableLoaderOptions.preflightPolicy = ForcePreflight;
+ if (CORSFlag)
+ threadableLoaderOptions.crossOriginRequestPolicy = UseAccessControl;
+ else
+ threadableLoaderOptions.crossOriginRequestPolicy = AllowCrossOriginRequests;
+
+ ResourceLoaderOptions resourceLoaderOptions;
+ resourceLoaderOptions.dataBufferingPolicy = DoNotBufferData;
+ // 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.
+ if (m_request->credentials() == FetchRequestData::IncludeCredentials
+ || (m_request->credentials() == FetchRequestData::SameOriginCredentials && !CORSFlag)) {
+ resourceLoaderOptions.allowCredentials = AllowStoredCredentials;
+ }
+ if (m_request->credentials() == FetchRequestData::IncludeCredentials)
+ resourceLoaderOptions.credentialsRequested = ClientRequestedCredentials;
+
+ m_loader = ThreadableLoader::create(*m_executionContext, this, request, threadableLoaderOptions, resourceLoaderOptions);
+}
+
void FetchManager::Loader::failed()
{
if (m_failed)
@@ -160,16 +326,36 @@ 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;
}
+bool FetchManager::isSimpleMethod(const String& method)
+{
+ // A simple method is a method that is `GET`, `HEAD`, or `POST`.
+ return isOnAccessControlSimpleRequestMethodWhitelist(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`.
+ 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`.
+ return XMLHttpRequest::isAllowedHTTPMethod(method);
+}
+
void FetchManager::onLoaderFinished(Loader* loader)
{
m_loaders.remove(loader);
« no previous file with comments | « Source/modules/serviceworkers/FetchManager.h ('k') | Source/modules/serviceworkers/FetchResponseData.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698