[Fetch API] Implement Fetch redirect mode
authoryouenn.fablet@crf.canon.fr <youenn.fablet@crf.canon.fr@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 May 2016 07:35:09 +0000 (07:35 +0000)
committeryouenn.fablet@crf.canon.fr <youenn.fablet@crf.canon.fr@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Tue, 24 May 2016 07:35:09 +0000 (07:35 +0000)
https://bugs.webkit.org/show_bug.cgi?id=157837

Reviewed by Alex Christensen.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/redirect/redirect-location-expected.txt:
* web-platform-tests/fetch/api/redirect/redirect-location.js:
* web-platform-tests/fetch/api/redirect/redirect-method.js:
* web-platform-tests/fetch/api/redirect/redirect-method-expected.txt:
* web-platform-tests/fetch/api/redirect/redirect-mode-expected.txt:

Source/WebCore:

Implementing step 5 of https://fetch.spec.whatwg.org/#http-fetch.
Making ResourceLoaderOptions include FetchOptions.
This allows SubresourceLoader to follow or not redirections based on that option.
CachedResource is made responsible to handle the type of the response (opaqueredirect, opaque, cors, basic...).
If redirection is not to be followed, either an error is returned or an empty response is returned.

Moved Response type and redirected flag from FetchResponse to ResourceResponse.
This allows CachedResource to easily communicate that information to FetchResponse.

Made some clean-up refactoring in ThreadableLoaderOptions.

http/tests/fetch/caching-with-different-options.html ensures that
caching at CachedResourceLoader will not have bad effects on fetch.
Covered by updated and rebased tests.

* Modules/fetch/FetchLoader.cpp:
(WebCore::FetchLoader::start):
* Modules/fetch/FetchResponse.cpp:
(WebCore::FetchResponse::error):
(WebCore::FetchResponse::redirect):
(WebCore::FetchResponse::FetchResponse):
(WebCore::FetchResponse::clone):
(WebCore::FetchResponse::startFetching):
* Modules/fetch/FetchResponse.h:
* WebCore.xcodeproj/project.pbxproj:
* loader/FetchOptions.h: Moved from Source/WebCore/Modules/fetch/FetchOptions.h.
* loader/ResourceLoaderOptions.h:
(WebCore::ResourceLoaderOptions::fetchOptions):
(WebCore::ResourceLoaderOptions::setFetchOptions):
* loader/SubresourceLoader.cpp:
(WebCore::SubresourceLoader::willSendRequestInternal):
* loader/ThreadableLoader.cpp:
* loader/ThreadableLoader.h:
* loader/cache/CachedResource.cpp:
(WebCore::CachedResource::setResponse):
* loader/cache/CachedResource.h:
(WebCore::CachedResource::setOpaqueRedirect):
* platform/network/ResourceResponseBase.cpp:
(WebCore::ResourceResponseBase::adopt):
(WebCore::ResourceResponseBase::copyData):
* platform/network/ResourceResponseBase.h:
(WebCore::ResourceResponseBase::type):
(WebCore::ResourceResponseBase::setType):
(WebCore::ResourceResponseBase::encode):
(WebCore::ResourceResponseBase::decode):

LayoutTests:

* http/tests/fetch/caching-with-different-options-expected.txt: Added.
* http/tests/fetch/caching-with-different-options.html: Added.
* http/tests/fetch/resources/redirect-with-cache.php: Added.
* platform/gtk/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-location-expected.txt:
* platform/gtk/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-method-expected.txt:

git-svn-id: https://svn.webkit.org/repository/webkit/trunk@201324 268f45cc-cd09-0410-ab3c-d52691b4dbfc

26 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/fetch/caching-with-different-options-expected.txt [new file with mode: 0644]
LayoutTests/http/tests/fetch/caching-with-different-options.html [new file with mode: 0644]
LayoutTests/http/tests/fetch/resources/redirect-with-cache.php [new file with mode: 0644]
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-location-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-location.js
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-method-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-method.js
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-mode-expected.txt
LayoutTests/platform/gtk/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-location-expected.txt
LayoutTests/platform/gtk/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-method-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/Modules/fetch/FetchLoader.cpp
Source/WebCore/Modules/fetch/FetchResponse.cpp
Source/WebCore/Modules/fetch/FetchResponse.h
Source/WebCore/WebCore.xcodeproj/project.pbxproj
Source/WebCore/loader/FetchOptions.h [moved from Source/WebCore/Modules/fetch/FetchOptions.h with 97% similarity]
Source/WebCore/loader/ResourceLoaderOptions.h
Source/WebCore/loader/SubresourceLoader.cpp
Source/WebCore/loader/ThreadableLoader.cpp
Source/WebCore/loader/ThreadableLoader.h
Source/WebCore/loader/cache/CachedResource.cpp
Source/WebCore/loader/cache/CachedResource.h
Source/WebCore/platform/network/ResourceResponseBase.cpp
Source/WebCore/platform/network/ResourceResponseBase.h

index 49283c3..3baf05d 100644 (file)
@@ -1,3 +1,16 @@
+2016-05-24  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        [Fetch API] Implement Fetch redirect mode
+        https://bugs.webkit.org/show_bug.cgi?id=157837
+
+        Reviewed by Alex Christensen.
+
+        * http/tests/fetch/caching-with-different-options-expected.txt: Added.
+        * http/tests/fetch/caching-with-different-options.html: Added.
+        * http/tests/fetch/resources/redirect-with-cache.php: Added.
+        * platform/gtk/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-location-expected.txt:
+        * platform/gtk/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-method-expected.txt:
+
 2016-05-23  Yoav Weiss  <yoav@yoav.ws>
 
         Add a few initiator tests to resource timing.
diff --git a/LayoutTests/http/tests/fetch/caching-with-different-options-expected.txt b/LayoutTests/http/tests/fetch/caching-with-different-options-expected.txt
new file mode 100644 (file)
index 0000000..dddbce1
--- /dev/null
@@ -0,0 +1,5 @@
+
+PASS Manual redirect fetch should not disrupt follow redirect fetch of the same resource 
+PASS Follow redirect fetch should not disrupt manual redirect fetch of the same resource 
+PASS Being loaded resources with different redirect mode should not break each other 
+
diff --git a/LayoutTests/http/tests/fetch/caching-with-different-options.html b/LayoutTests/http/tests/fetch/caching-with-different-options.html
new file mode 100644 (file)
index 0000000..7725606
--- /dev/null
@@ -0,0 +1,55 @@
+<!doctype html>
+<html>
+  <head>
+    <meta charset="utf-8">
+    <title>Fetch: retrieve response's body progressively</title>
+    <meta name="help" href="https://fetch.spec.whatwg.org/#main-fetch">
+    <meta name="help" href="https://fetch.spec.whatwg.org/#http-fetch">
+    <meta name="author" title="Canon Research France" href="https://www.crf.canon.fr">
+    <script src="/js-test-resources/testharness.js"></script>
+    <script src="/js-test-resources/testharnessreport.js"></script>
+  </head>
+  <body>
+    <div id="test"></div>
+    <script>
+
+var redirectUrl = "./resources/redirect-with-cache.php?url=/js-test-resources/testharness.js&";
+function redirectMode(test, redirect, urlSuffix) {
+  var requestInit = {"redirect": redirect};
+  requestInit.headers = [["enablecaching", "true"]];
+  if (redirect === "manual") {
+    return fetch(redirectUrl + urlSuffix, requestInit).then(function(response) {
+      assert_equals(response.type, "opaqueredirect", "Response type is opaqueredirect");
+      assert_equals(response.status, 0, "Response status is 0");
+    });
+  }
+  else {
+    return fetch(redirectUrl + urlSuffix, requestInit).then(function(response) {
+      assert_equals(response.type, "basic", "Response type is basic");
+      assert_equals(response.status, 200, "Response status is 200");
+    });
+  }
+}
+
+promise_test(function(test) {
+  return redirectMode(test, "manual", "test1").then(() => {
+    return redirectMode(test, "follow", "test1");
+  });
+}, "Manual redirect fetch should not disrupt follow redirect fetch of the same resource");
+
+promise_test(function(test) {
+  return redirectMode(test, "follow", "test2").then(() => {
+    return redirectMode(test, "manual", "test2");
+  });
+}, "Follow redirect fetch should not disrupt manual redirect fetch of the same resource");
+
+promise_test(function(test) {
+  return Promise.all([
+    redirectMode(test, "follow", "test3"),
+    redirectMode(test, "manual", "test3")
+  ]);
+}, "Being loaded resources with different redirect mode should not break each other");
+
+    </script>
+  </body>
+</html>
diff --git a/LayoutTests/http/tests/fetch/resources/redirect-with-cache.php b/LayoutTests/http/tests/fetch/resources/redirect-with-cache.php
new file mode 100644 (file)
index 0000000..19c81ed
--- /dev/null
@@ -0,0 +1,14 @@
+<?php
+    $url = $_GET["url"];
+
+    $enableCaching = isset($_SERVER["ENABLECACHING"]) ? true : false;
+    $code = isset($_GET["code"]) ? $_GET["code"] : 302;
+
+    header("HTTP/1.1 $code");
+    header("Location: $url");
+
+    if ($enableCaching)
+        header("Cache-Control: max-age=31536000");
+    else
+        header("Cache-Control: no-store");
+?>
index 1342493..6ac1859 100644 (file)
@@ -1,3 +1,16 @@
+2016-05-24  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        [Fetch API] Implement Fetch redirect mode
+        https://bugs.webkit.org/show_bug.cgi?id=157837
+
+        Reviewed by Alex Christensen.
+
+        * web-platform-tests/fetch/api/redirect/redirect-location-expected.txt:
+        * web-platform-tests/fetch/api/redirect/redirect-location.js:
+        * web-platform-tests/fetch/api/redirect/redirect-method.js:
+        * web-platform-tests/fetch/api/redirect/redirect-method-expected.txt:
+        * web-platform-tests/fetch/api/redirect/redirect-mode-expected.txt:
+
 2016-05-18  Antti Koivisto  <antti@apple.com>
 
         Cascading order for !important properties in ::slotted and ::host rules is incorrect
index 3a1ba49..ff55995 100644 (file)
@@ -4,29 +4,29 @@ PASS Redirect 301 in "manual" mode without location
 PASS Redirect 301 in "follow" mode with invalid location 
 PASS Redirect 301 in "manual" mode with invalid location 
 PASS Redirect 301 in "follow" mode with data location 
-FAIL Redirect 301 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 301 in "manual" mode with data location 
 PASS Redirect 302 in "follow" mode without location 
 PASS Redirect 302 in "manual" mode without location 
 PASS Redirect 302 in "follow" mode with invalid location 
 PASS Redirect 302 in "manual" mode with invalid location 
 PASS Redirect 302 in "follow" mode with data location 
-FAIL Redirect 302 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 302 in "manual" mode with data location 
 PASS Redirect 303 in "follow" mode without location 
 PASS Redirect 303 in "manual" mode without location 
 PASS Redirect 303 in "follow" mode with invalid location 
 PASS Redirect 303 in "manual" mode with invalid location 
 PASS Redirect 303 in "follow" mode with data location 
-FAIL Redirect 303 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 303 in "manual" mode with data location 
 PASS Redirect 307 in "follow" mode without location 
 PASS Redirect 307 in "manual" mode without location 
 PASS Redirect 307 in "follow" mode with invalid location 
 PASS Redirect 307 in "manual" mode with invalid location 
 PASS Redirect 307 in "follow" mode with data location 
-FAIL Redirect 307 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 307 in "manual" mode with data location 
 PASS Redirect 308 in "follow" mode without location 
 PASS Redirect 308 in "manual" mode without location 
 PASS Redirect 308 in "follow" mode with invalid location 
 PASS Redirect 308 in "manual" mode with invalid location 
 PASS Redirect 308 in "follow" mode with data location 
-FAIL Redirect 308 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 308 in "manual" mode with data location 
 
index 5b081a7..0297250 100644 (file)
@@ -41,7 +41,7 @@ for (var statusCode of [301, 302, 303, 307, 308]) {
   redirectLocation("Redirect " + statusCode + " in \"manual\" mode without location", redirUrl, undefined, statusCode, "manual", true);
 
   redirectLocation("Redirect " + statusCode + " in \"follow\" mode with invalid location", redirUrl, invalidLocationUrl, statusCode, "follow", false);
-  redirectLocation("Redirect " + statusCode + " in \"manual\" mode with invalid location", redirUrl, invalidLocationUrl, statusCode, "manual", false);
+  redirectLocation("Redirect " + statusCode + " in \"manual\" mode with invalid location", redirUrl, invalidLocationUrl, statusCode, "manual", true);
 
   redirectLocation("Redirect " + statusCode + " in \"follow\" mode with data location", redirUrl, dataLocationUrl, statusCode, "follow", false);
   redirectLocation("Redirect " + statusCode + " in \"manual\" mode with data location", redirUrl, dataLocationUrl, statusCode, "manual", true);
index a7e1b0b..1158253 100644 (file)
@@ -17,6 +17,7 @@ function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, met
       assert_equals(resp.status, 200, "Response's status is 200");
       assert_equals(resp.type, "basic", "Response's type basic");
       assert_equals(resp.headers.get("x-request-method"), expectedMethod, "Request method after redirection is " + expectedMethod);
+      assert_true(resp.redirected);
       return resp.text().then(function(text) {
         assert_equals(text, expectedMethod == "POST" ? requestInit.body : "");
       });
@@ -24,6 +25,14 @@ function redirectMethod(desc, redirectUrl, redirectLocation, redirectStatus, met
   }, desc);
 }
 
+promise_test(function(test) {
+    assert_false(new Response().redirected);
+    return fetch(RESOURCES_DIR + "method.py").then(function(resp) {
+      assert_equals(resp.status, 200, "Response's status is 200");
+      assert_false(resp.redirected);
+    });
+}, "Response.redirected should be false on not-redirected responses");
+
 var redirUrl = RESOURCES_DIR + "redirect.py";
 var locationUrl = "method.py";
 
index 899c718..dddda69 100644 (file)
@@ -1,17 +1,17 @@
 
-FAIL Redirect 301 in "error" mode  assert_unreached: Should have rejected. Reached unreachable code
+PASS Redirect 301 in "error" mode  
 PASS Redirect 301 in "follow" mode  
-FAIL Redirect 301 in "manual" mode  assert_equals: Response's status is 0 expected 0 but got 200
-FAIL Redirect 302 in "error" mode  assert_unreached: Should have rejected. Reached unreachable code
+PASS Redirect 301 in "manual" mode  
+PASS Redirect 302 in "error" mode  
 PASS Redirect 302 in "follow" mode  
-FAIL Redirect 302 in "manual" mode  assert_equals: Response's status is 0 expected 0 but got 200
-FAIL Redirect 303 in "error" mode  assert_unreached: Should have rejected. Reached unreachable code
+PASS Redirect 302 in "manual" mode  
+PASS Redirect 303 in "error" mode  
 PASS Redirect 303 in "follow" mode  
-FAIL Redirect 303 in "manual" mode  assert_equals: Response's status is 0 expected 0 but got 200
-FAIL Redirect 307 in "error" mode  assert_unreached: Should have rejected. Reached unreachable code
+PASS Redirect 303 in "manual" mode  
+PASS Redirect 307 in "error" mode  
 PASS Redirect 307 in "follow" mode  
-FAIL Redirect 307 in "manual" mode  assert_equals: Response's status is 0 expected 0 but got 200
-FAIL Redirect 308 in "error" mode  assert_unreached: Should have rejected. Reached unreachable code
+PASS Redirect 307 in "manual" mode  
+PASS Redirect 308 in "error" mode  
 PASS Redirect 308 in "follow" mode  
-FAIL Redirect 308 in "manual" mode  assert_equals: Response's status is 0 expected 0 but got 200
+PASS Redirect 308 in "manual" mode  
 
index a32a3a0..6278d35 100644 (file)
@@ -6,27 +6,27 @@ PASS Redirect 301 in "manual" mode without location
 PASS Redirect 301 in "follow" mode with invalid location 
 PASS Redirect 301 in "manual" mode with invalid location 
 PASS Redirect 301 in "follow" mode with data location 
-FAIL Redirect 301 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 301 in "manual" mode with data location 
 PASS Redirect 302 in "follow" mode without location 
 PASS Redirect 302 in "manual" mode without location 
 PASS Redirect 302 in "follow" mode with invalid location 
 PASS Redirect 302 in "manual" mode with invalid location 
 PASS Redirect 302 in "follow" mode with data location 
-FAIL Redirect 302 in "manual" mode with data location promise_test: Unhandled rejection with value: object "TypeError: Type error"
+PASS Redirect 302 in "manual" mode with data location 
 PASS Redirect 303 in "follow" mode without location 
 PASS Redirect 303 in "manual" mode without location 
 PASS Redirect 303 in "follow" mode with invalid location 
-TIMEOUT Redirect 303 in "manual" mode with invalid location Test timed out
-TIMEOUT Redirect 303 in "follow" mode with data location Test timed out
-TIMEOUT Redirect 303 in "manual" mode with data location Test timed out
-TIMEOUT Redirect 307 in "follow" mode without location Test timed out
-TIMEOUT Redirect 307 in "manual" mode without location Test timed out
-TIMEOUT Redirect 307 in "follow" mode with invalid location Test timed out
-TIMEOUT Redirect 307 in "manual" mode with invalid location Test timed out
-TIMEOUT Redirect 307 in "follow" mode with data location Test timed out
-TIMEOUT Redirect 307 in "manual" mode with data location Test timed out
-TIMEOUT Redirect 308 in "follow" mode without location Test timed out
-TIMEOUT Redirect 308 in "manual" mode without location Test timed out
+PASS Redirect 303 in "manual" mode with invalid location 
+PASS Redirect 303 in "follow" mode with data location 
+PASS Redirect 303 in "manual" mode with data location 
+PASS Redirect 307 in "follow" mode without location 
+PASS Redirect 307 in "manual" mode without location 
+PASS Redirect 307 in "follow" mode with invalid location 
+PASS Redirect 307 in "manual" mode with invalid location 
+PASS Redirect 307 in "follow" mode with data location 
+PASS Redirect 307 in "manual" mode with data location 
+PASS Redirect 308 in "follow" mode without location 
+PASS Redirect 308 in "manual" mode without location 
 TIMEOUT Redirect 308 in "follow" mode with invalid location Test timed out
 TIMEOUT Redirect 308 in "manual" mode with invalid location Test timed out
 TIMEOUT Redirect 308 in "follow" mode with data location Test timed out
index 81d4572..4636007 100644 (file)
@@ -1,3 +1,56 @@
+2016-05-24  Youenn Fablet  <youenn.fablet@crf.canon.fr>
+
+        [Fetch API] Implement Fetch redirect mode
+        https://bugs.webkit.org/show_bug.cgi?id=157837
+
+        Reviewed by Alex Christensen.
+
+        Implementing step 5 of https://fetch.spec.whatwg.org/#http-fetch.
+        Making ResourceLoaderOptions include FetchOptions.
+        This allows SubresourceLoader to follow or not redirections based on that option.
+        CachedResource is made responsible to handle the type of the response (opaqueredirect, opaque, cors, basic...).
+        If redirection is not to be followed, either an error is returned or an empty response is returned.
+
+        Moved Response type and redirected flag from FetchResponse to ResourceResponse.
+        This allows CachedResource to easily communicate that information to FetchResponse.
+
+        Made some clean-up refactoring in ThreadableLoaderOptions.
+
+        http/tests/fetch/caching-with-different-options.html ensures that
+        caching at CachedResourceLoader will not have bad effects on fetch.
+        Covered by updated and rebased tests.
+
+        * Modules/fetch/FetchLoader.cpp:
+        (WebCore::FetchLoader::start):
+        * Modules/fetch/FetchResponse.cpp:
+        (WebCore::FetchResponse::error):
+        (WebCore::FetchResponse::redirect):
+        (WebCore::FetchResponse::FetchResponse):
+        (WebCore::FetchResponse::clone):
+        (WebCore::FetchResponse::startFetching):
+        * Modules/fetch/FetchResponse.h:
+        * WebCore.xcodeproj/project.pbxproj:
+        * loader/FetchOptions.h: Moved from Source/WebCore/Modules/fetch/FetchOptions.h.
+        * loader/ResourceLoaderOptions.h:
+        (WebCore::ResourceLoaderOptions::fetchOptions):
+        (WebCore::ResourceLoaderOptions::setFetchOptions):
+        * loader/SubresourceLoader.cpp:
+        (WebCore::SubresourceLoader::willSendRequestInternal):
+        * loader/ThreadableLoader.cpp:
+        * loader/ThreadableLoader.h:
+        * loader/cache/CachedResource.cpp:
+        (WebCore::CachedResource::setResponse):
+        * loader/cache/CachedResource.h:
+        (WebCore::CachedResource::setOpaqueRedirect):
+        * platform/network/ResourceResponseBase.cpp:
+        (WebCore::ResourceResponseBase::adopt):
+        (WebCore::ResourceResponseBase::copyData):
+        * platform/network/ResourceResponseBase.h:
+        (WebCore::ResourceResponseBase::type):
+        (WebCore::ResourceResponseBase::setType):
+        (WebCore::ResourceResponseBase::encode):
+        (WebCore::ResourceResponseBase::decode):
+
 2016-05-23  Yusuke Suzuki  <utatane.tea@gmail.com>
 
         Assertion failure for Reflect.get with Proxy and primitive value as explicit receiver
index c21525f..885fb22 100644 (file)
@@ -68,7 +68,7 @@ void FetchLoader::start(ScriptExecutionContext& context, Blob& blob)
     options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
 
     m_loader = ThreadableLoader::create(&context, this, request, options);
-    m_isStarted = true;
+    m_isStarted = m_loader;
 }
 
 void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& request)
@@ -82,9 +82,10 @@ void FetchLoader::start(ScriptExecutionContext& context, const FetchRequest& req
     options.setAllowCredentials(AllowStoredCredentials);
     options.crossOriginRequestPolicy = DenyCrossOriginRequests;
     options.contentSecurityPolicyEnforcement = ContentSecurityPolicyEnforcement::DoNotEnforce;
+    options.setFetchOptions(request.fetchOptions());
 
     m_loader = ThreadableLoader::create(&context, this, request.internalRequest(), options);
-    m_isStarted = true;
+    m_isStarted = m_loader;
 }
 
 FetchLoader::FetchLoader(Type type, FetchLoaderClient& client)
@@ -96,10 +97,8 @@ FetchLoader::FetchLoader(Type type, FetchLoaderClient& client)
 void FetchLoader::stop()
 {
     m_data = nullptr;
-    if (m_loader) {
-        RefPtr<ThreadableLoader> loader = WTFMove(m_loader);
-        loader->cancel();
-    }
+    if (m_loader)
+        m_loader->cancel();
 }
 
 RefPtr<SharedBuffer> FetchLoader::startStreaming()
index 6f38902..19c00ac 100644 (file)
@@ -51,7 +51,9 @@ static inline bool isNullBodyStatus(int status)
 
 Ref<FetchResponse> FetchResponse::error(ScriptExecutionContext& context)
 {
-    return adoptRef(*new FetchResponse(context, Type::Error, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
+    auto response = adoptRef(*new FetchResponse(context, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
+    response->m_response.setType(Type::Error);
+    return response;
 }
 
 RefPtr<FetchResponse> FetchResponse::redirect(ScriptExecutionContext& context, const String& url, int status, ExceptionCode& ec)
@@ -66,7 +68,7 @@ RefPtr<FetchResponse> FetchResponse::redirect(ScriptExecutionContext& context, c
         ec = TypeError;
         return nullptr;
     }
-    auto redirectResponse = adoptRef(*new FetchResponse(context, Type::Default, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
+    auto redirectResponse = adoptRef(*new FetchResponse(context, { }, FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
     redirectResponse->m_response.setHTTPStatusCode(status);
     redirectResponse->m_headers->fastSet(HTTPHeaderName::Location, requestURL.string());
     return WTFMove(redirectResponse);
@@ -109,9 +111,8 @@ void FetchResponse::initializeWith(const Dictionary& init, ExceptionCode& ec)
     }
 }
 
-FetchResponse::FetchResponse(ScriptExecutionContext& context, Type type, FetchBody&& body, Ref<FetchHeaders>&& headers, ResourceResponse&& response)
+FetchResponse::FetchResponse(ScriptExecutionContext& context, FetchBody&& body, Ref<FetchHeaders>&& headers, ResourceResponse&& response)
     : FetchBodyOwner(context, WTFMove(body))
-    , m_type(type)
     , m_response(WTFMove(response))
     , m_headers(WTFMove(headers))
 {
@@ -123,14 +124,12 @@ RefPtr<FetchResponse> FetchResponse::clone(ScriptExecutionContext& context, Exce
         ec = TypeError;
         return nullptr;
     }
-    auto cloned = adoptRef(*new FetchResponse(context, m_type, FetchBody(m_body), FetchHeaders::create(headers()), ResourceResponse(m_response)));
-    cloned->m_isRedirected = m_isRedirected;
-    return WTFMove(cloned);
+    return adoptRef(*new FetchResponse(context, FetchBody(m_body), FetchHeaders::create(headers()), ResourceResponse(m_response)));
 }
 
 void FetchResponse::startFetching(ScriptExecutionContext& context, const FetchRequest& request, FetchPromise&& promise)
 {
-    auto response = adoptRef(*new FetchResponse(context, Type::Basic, FetchBody::loadingBody(), FetchHeaders::create(FetchHeaders::Guard::Immutable), ResourceResponse()));
+    auto response = adoptRef(*new FetchResponse(context, FetchBody::loadingBody(), FetchHeaders::create(FetchHeaders::Guard::Immutable), { }));
 
     // Setting pending activity until BodyLoader didFail or didSucceed callback is called.
     response->setPendingActivity(response.ptr());
@@ -173,7 +172,8 @@ void FetchResponse::BodyLoader::didSucceed()
         m_response.m_readableStreamSource = nullptr;
     }
 #endif
-    m_response.m_bodyLoader = Nullopt;
+    if (m_loader->isStarted())
+        m_response.m_bodyLoader = Nullopt;
     m_response.unsetPendingActivity(&m_response);
 }
 
index ed24711..dd2232a 100644 (file)
@@ -48,9 +48,9 @@ typedef int ExceptionCode;
 
 class FetchResponse final : public FetchBodyOwner {
 public:
-    enum class Type { Basic, Cors, Default, Error, Opaque, Opaqueredirect };
+    using Type = ResourceResponse::Type;
 
-    static Ref<FetchResponse> create(ScriptExecutionContext& context) { return adoptRef(*new FetchResponse(context, Type::Default, { }, FetchHeaders::create(FetchHeaders::Guard::Response), ResourceResponse())); }
+    static Ref<FetchResponse> create(ScriptExecutionContext& context) { return adoptRef(*new FetchResponse(context, { }, FetchHeaders::create(FetchHeaders::Guard::Response), ResourceResponse())); }
     static Ref<FetchResponse> error(ScriptExecutionContext&);
     static RefPtr<FetchResponse> redirect(ScriptExecutionContext&, const String&, int, ExceptionCode&);
 
@@ -60,9 +60,9 @@ public:
 
     void initializeWith(const Dictionary&, ExceptionCode&);
 
-    Type type() const;
+    Type type() const { return m_response.type(); }
     const String& url() const { return m_response.url().string(); }
-    bool redirected() const { return m_isRedirected; }
+    bool redirected() const { return m_response.isRedirected(); }
     int status() const { return m_response.httpStatusCode(); }
     bool ok() const { return status() >= 200 && status() <= 299; }
     const String& statusText() const { return m_response.httpStatusText(); }
@@ -76,7 +76,7 @@ public:
 #endif
 
 private:
-    FetchResponse(ScriptExecutionContext&, Type, FetchBody&&, Ref<FetchHeaders>&&, ResourceResponse&&);
+    FetchResponse(ScriptExecutionContext&, FetchBody&&, Ref<FetchHeaders>&&, ResourceResponse&&);
 
     static void startFetching(ScriptExecutionContext&, const FetchRequest&, FetchPromise&&);
 
@@ -100,7 +100,7 @@ private:
         // FetchLoaderClient API
         void didSucceed() final;
         void didFail() final;
-        void didReceiveResponse(const ResourceResponse&);
+        void didReceiveResponse(const ResourceResponse&) final;
         void didReceiveData(const char*, size_t) final;
         void didFinishLoadingAsArrayBuffer(RefPtr<ArrayBuffer>&&) final;
 
@@ -109,18 +109,11 @@ private:
         std::unique_ptr<FetchLoader> m_loader;
     };
 
-    Type m_type;
     ResourceResponse m_response;
     Ref<FetchHeaders> m_headers;
-    bool m_isRedirected = false;
     Optional<BodyLoader> m_bodyLoader;
 };
 
-inline auto FetchResponse::type() const -> Type
-{
-    return m_type;
-}
-
 } // namespace WebCore
 
 #endif // ENABLE(FETCH_API)
index 0be0b17..e7596bf 100644 (file)
                419BE7591BC7F42B00E1C85B /* WebCoreBuiltinNames.h in Headers */ = {isa = PBXBuildFile; fileRef = 419BE7521BC7F3DB00E1C85B /* WebCoreBuiltinNames.h */; };
                41A3D58E101C152D00316D07 /* DedicatedWorkerThread.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41A3D58C101C152D00316D07 /* DedicatedWorkerThread.cpp */; };
                41A3D58F101C152D00316D07 /* DedicatedWorkerThread.h in Headers */ = {isa = PBXBuildFile; fileRef = 41A3D58D101C152D00316D07 /* DedicatedWorkerThread.h */; };
+               41AD753A1CEF6BD100A31486 /* FetchOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 41AD75391CEF6BCE00A31486 /* FetchOptions.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41BF700C0FE86F49005E8DEC /* MessagePortChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF700A0FE86F49005E8DEC /* MessagePortChannel.h */; settings = {ATTRIBUTES = (Private, ); }; };
                41BF700F0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */; };
                41BF70100FE86F61005E8DEC /* PlatformMessagePortChannel.h in Headers */ = {isa = PBXBuildFile; fileRef = 41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */; };
                41A023ED1A39DB7900F722DF /* WritableStream.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = WritableStream.idl; sourceTree = "<group>"; };
                41A3D58C101C152D00316D07 /* DedicatedWorkerThread.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DedicatedWorkerThread.cpp; sourceTree = "<group>"; };
                41A3D58D101C152D00316D07 /* DedicatedWorkerThread.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DedicatedWorkerThread.h; sourceTree = "<group>"; };
+               41AD75391CEF6BCE00A31486 /* FetchOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchOptions.h; sourceTree = "<group>"; };
                41BF700A0FE86F49005E8DEC /* MessagePortChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MessagePortChannel.h; sourceTree = "<group>"; };
                41BF700D0FE86F61005E8DEC /* PlatformMessagePortChannel.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = PlatformMessagePortChannel.cpp; path = default/PlatformMessagePortChannel.cpp; sourceTree = "<group>"; };
                41BF700E0FE86F61005E8DEC /* PlatformMessagePortChannel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = PlatformMessagePortChannel.h; path = default/PlatformMessagePortChannel.h; sourceTree = "<group>"; };
                41F54F831C50C4F600338488 /* FetchHeaders.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchHeaders.h; sourceTree = "<group>"; };
                41F54F841C50C4F600338488 /* FetchHeaders.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = FetchHeaders.idl; sourceTree = "<group>"; };
                41F54F851C50C4F600338488 /* FetchHeaders.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; path = FetchHeaders.js; sourceTree = "<group>"; };
-               41F54F861C50C4F600338488 /* FetchOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchOptions.h; sourceTree = "<group>"; };
                41F54F871C50C4F600338488 /* FetchRequest.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = FetchRequest.cpp; sourceTree = "<group>"; };
                41F54F881C50C4F600338488 /* FetchRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FetchRequest.h; sourceTree = "<group>"; };
                41F54F891C50C4F600338488 /* FetchRequest.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = FetchRequest.idl; sourceTree = "<group>"; };
                                4147E2B41C89912600A7E715 /* FetchLoader.cpp */,
                                4147E2B51C89912600A7E715 /* FetchLoader.h */,
                                4147E2B61C89912600A7E715 /* FetchLoaderClient.h */,
-                               41F54F861C50C4F600338488 /* FetchOptions.h */,
                                41F54F871C50C4F600338488 /* FetchRequest.cpp */,
                                41F54F881C50C4F600338488 /* FetchRequest.h */,
                                41F54F891C50C4F600338488 /* FetchRequest.idl */,
                                9738899F116EA9DC00ADF313 /* DocumentWriter.h */,
                                F52AD5E31534245F0059FBE6 /* EmptyClients.cpp */,
                                B255990D0D00D8B900BB825C /* EmptyClients.h */,
+                               41AD75391CEF6BCE00A31486 /* FetchOptions.h */,
                                656D37230ADBA5DE00A4554D /* FormState.cpp */,
                                656D37220ADBA5DE00A4554D /* FormState.h */,
                                41885B9211B6FDA6003383BB /* FormSubmission.cpp */,
                                E4AFD0100DAF335500F5F55C /* SVGSMILElement.h in Headers */,
                                0880F70E1282B46D00948505 /* SVGStaticListPropertyTearOff.h in Headers */,
                                0813A4EA1284132600992511 /* SVGStaticPropertyTearOff.h in Headers */,
+                               41AD753A1CEF6BD100A31486 /* FetchOptions.h in Headers */,
                                B2227AA90D00BF220071B782 /* SVGStopElement.h in Headers */,
                                B2227AAC0D00BF220071B782 /* SVGStringList.h in Headers */,
                                B2227AB80D00BF220071B782 /* SVGStyleElement.h in Headers */,
similarity index 97%
rename from Source/WebCore/Modules/fetch/FetchOptions.h
rename to Source/WebCore/loader/FetchOptions.h
index 993d708..cfe53d0 100644 (file)
@@ -28,8 +28,6 @@
 
 #pragma once
 
-#if ENABLE(FETCH_API)
-
 namespace WebCore {
 
 struct FetchOptions {
@@ -56,5 +54,3 @@ struct FetchOptions {
 };
 
 } // namespace WebCore
-
-#endif // ENABLE(FETCH_API)
index d258e1e..8587f79 100644 (file)
@@ -31,6 +31,7 @@
 #ifndef ResourceLoaderOptions_h
 #define ResourceLoaderOptions_h
 
+#include "FetchOptions.h"
 #include "ResourceHandleTypes.h"
 
 namespace WebCore {
@@ -135,6 +136,8 @@ struct ResourceLoaderOptions {
     void setDefersLoadingPolicy(DefersLoadingPolicy defersLoadingPolicy) { m_defersLoadingPolicy = defersLoadingPolicy; }
     CachingPolicy cachingPolicy() const { return m_cachingPolicy; }
     void setCachingPolicy(CachingPolicy cachingPolicy) { m_cachingPolicy = cachingPolicy; }
+    FetchOptions fetchOptions() const { return m_fetchOptions; }
+    void setFetchOptions(FetchOptions fetchOptions) { m_fetchOptions = fetchOptions; }
 
     unsigned m_sendLoadCallbacks : 1;
     unsigned m_sniffContent : 1;
@@ -148,6 +151,7 @@ struct ResourceLoaderOptions {
     ContentSecurityPolicyImposition m_contentSecurityPolicyImposition { ContentSecurityPolicyImposition::DoPolicyCheck };
     DefersLoadingPolicy m_defersLoadingPolicy { DefersLoadingPolicy::AllowDefersLoading };
     CachingPolicy m_cachingPolicy { CachingPolicy::AllowCaching };
+    FetchOptions m_fetchOptions;
 };
 
 } // namespace WebCore    
index 7e7a9c2..b75f396 100644 (file)
@@ -175,6 +175,17 @@ void SubresourceLoader::willSendRequestInternal(ResourceRequest& newRequest, con
 
     ASSERT(!newRequest.isNull());
     if (!redirectResponse.isNull()) {
+        if (options().fetchOptions().redirect != FetchOptions::Redirect::Follow) {
+            if (options().fetchOptions().redirect == FetchOptions::Redirect::Error) {
+                cancel();
+                return;
+            }
+            m_resource->setOpaqueRedirect();
+            m_resource->responseReceived({ });
+            didFinishLoading(currentTime());
+            return;
+        }
+
         // CachedResources are keyed off their original request URL.
         // Requesting the same original URL a second time can redirect to a unique second resource.
         // Therefore, if a redirect to a different destination URL occurs, we should no longer consider this a revalidation of the first resource.
index 2c2d5e3..d889af5 100644 (file)
@@ -42,8 +42,6 @@
 namespace WebCore {
 
 ThreadableLoaderOptions::ThreadableLoaderOptions()
-    : preflightPolicy(ConsiderPreflight)
-    , crossOriginRequestPolicy(DenyCrossOriginRequests)
 {
 }
 
index c3a7496..b6310b8 100644 (file)
@@ -72,8 +72,8 @@ namespace WebCore {
 
         std::unique_ptr<ThreadableLoaderOptions> isolatedCopy() const;
 
-        PreflightPolicy preflightPolicy; // If AccessControl is used, how to determine if a preflight is needed.
-        CrossOriginRequestPolicy crossOriginRequestPolicy;
+        PreflightPolicy preflightPolicy { ConsiderPreflight };
+        CrossOriginRequestPolicy crossOriginRequestPolicy { DenyCrossOriginRequests };
         ContentSecurityPolicyEnforcement contentSecurityPolicyEnforcement { ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective };
         RefPtr<SecurityOrigin> securityOrigin;
         String initiator; // This cannot be an AtomicString, as isolatedCopy() wouldn't create an object that's safe for passing to another thread.
index 6676cbe..1f56467 100644 (file)
@@ -411,6 +411,13 @@ const ResourceResponse& CachedResource::responseForSameOriginPolicyChecks() cons
     return m_redirectResponseForSameOriginPolicyChecks.isNull() ? m_response : m_redirectResponseForSameOriginPolicyChecks;
 }
 
+void CachedResource::setResponse(const ResourceResponse& response)
+{
+    m_response = response;
+    m_response.setType(m_responseType);
+    m_response.setRedirected(m_redirectChainCacheStatus.status != RedirectChainCacheStatus::NoRedirection);
+}
+
 void CachedResource::responseReceived(const ResourceResponse& response)
 {
     setResponse(response);
index 1089365..3892069 100644 (file)
@@ -199,7 +199,8 @@ public:
     virtual void redirectReceived(ResourceRequest&, const ResourceResponse&);
     virtual void responseReceived(const ResourceResponse&);
     virtual bool shouldCacheResponse(const ResourceResponse&) { return true; }
-    void setResponse(const ResourceResponse& response) { m_response = response; }
+    void setResponse(const ResourceResponse&);
+    void setOpaqueRedirect() { m_responseType = ResourceResponseBase::Type::Opaqueredirect; }
     const ResourceResponse& response() const { return m_response; }
     // This is the same as response() except after HTTP redirect to data: URL.
     const ResourceResponse& responseForSameOriginPolicyChecks() const;
@@ -281,6 +282,7 @@ protected:
     RefPtr<SubresourceLoader> m_loader;
     ResourceLoaderOptions m_options;
     ResourceResponse m_response;
+    ResourceResponseBase::Type m_responseType { ResourceResponseBase::Type::Basic };
     ResourceResponse m_redirectResponseForSameOriginPolicyChecks;
     RefPtr<SharedBuffer> m_data;
     DeferrableOneShotTimer m_decodedDataDeletionTimer;
index 31f04de..8aad98c 100644 (file)
@@ -78,6 +78,7 @@ std::unique_ptr<ResourceResponse> ResourceResponseBase::adopt(std::unique_ptr<Cr
     response->lazyInit(AllFields);
     response->m_httpHeaderFields.adopt(WTFMove(data->m_httpHeaders));
     response->m_resourceLoadTiming = data->m_resourceLoadTiming;
+    response->m_type = data->m_type;
     response->doPlatformAdopt(WTFMove(data));
     return response;
 }
@@ -94,6 +95,7 @@ std::unique_ptr<CrossThreadResourceResponseData> ResourceResponseBase::copyData(
     data->m_httpVersion = httpVersion().isolatedCopy();
     data->m_httpHeaders = httpHeaderFields().copyData();
     data->m_resourceLoadTiming = m_resourceLoadTiming;
+    data->m_type = m_type;
     return asResourceResponse().doPlatformCopyData(WTFMove(data));
 }
 
index 1c88458..6af490a 100644 (file)
@@ -128,6 +128,12 @@ public:
         return 1280;
     }
 
+    enum class Type { Basic, Cors, Default, Error, Opaque, Opaqueredirect };
+    Type type() const { return m_type; }
+    void setType(Type type) { m_type = type; }
+    bool isRedirected() const { return m_isRedirected; }
+    void setRedirected(bool isRedirected) { m_isRedirected = isRedirected; }
+
     static bool compare(const ResourceResponse&, const ResourceResponse&);
 
     template<class Encoder> void encode(Encoder&) const;
@@ -189,6 +195,9 @@ private:
     mutable bool m_haveParsedContentRangeHeader { false };
 
     Source m_source { Source::Unknown };
+
+    Type m_type { Type::Default };
+    bool m_isRedirected { false };
 };
 
 inline bool operator==(const ResourceResponse& a, const ResourceResponse& b) { return ResourceResponseBase::compare(a, b); }
@@ -215,6 +224,8 @@ void ResourceResponseBase::encode(Encoder& encoder) const
     if (m_includesCertificateInfo)
         encoder << m_certificateInfo;
     encoder.encodeEnum(m_source);
+    encoder.encodeEnum(m_type);
+    encoder << m_isRedirected;
 }
 
 template<class Decoder>
@@ -255,6 +266,10 @@ bool ResourceResponseBase::decode(Decoder& decoder, ResourceResponseBase& respon
     }
     if (!decoder.decodeEnum(response.m_source))
         return false;
+    if (!decoder.decodeEnum(response.m_type))
+        return false;
+    if (!decoder.decode(response.m_isRedirected))
+        return false;
     response.m_isNull = false;
 
     return true;
@@ -273,6 +288,8 @@ public:
     String m_httpVersion;
     std::unique_ptr<CrossThreadHTTPHeaderMapData> m_httpHeaders;
     ResourceLoadTiming m_resourceLoadTiming;
+    ResourceResponseBase::Type m_type;
+    bool m_isRedirected;
 };
 
 } // namespace WebCore