fetch redirect is incompatible with "no-cors" mode
authorcommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 20 Jan 2018 10:45:25 +0000 (10:45 +0000)
committercommit-queue@webkit.org <commit-queue@webkit.org@268f45cc-cd09-0410-ab3c-d52691b4dbfc>
Sat, 20 Jan 2018 10:45:25 +0000 (10:45 +0000)
https://bugs.webkit.org/show_bug.cgi?id=181866
<rdar://problem/35827140>

Patch by Youenn Fablet <youenn@apple.com> on 2018-01-20
Reviewed by Chris Dumez.

LayoutTests/imported/w3c:

* web-platform-tests/fetch/api/redirect/redirect-mode-expected.txt:
* web-platform-tests/fetch/api/redirect/redirect-mode-worker-expected.txt:
* web-platform-tests/fetch/api/redirect/redirect-mode.js:
(redirectMode):
* web-platform-tests/service-workers/service-worker/fetch-event-redirect.https-expected.txt:
* web-platform-tests/service-workers/service-worker/fetch-event-redirect.https.html:
* web-platform-tests/service-workers/service-worker/fetch-request-redirect.https-expected.txt:

Source/WebCore:

Covered by updated tests.

Return a network error when no-cors mode and redirect mode is manual or error.
Update preflight implementation to no longer use manual redirect mode to simulate https://fetch.spec.whatwg.org/#http-network-or-cache-fetch.
Instead implement redirectReceived callback to treat any redirect response as the preflight response.

* loader/cache/CachedResourceLoader.cpp:
(WebCore::CachedResourceLoader::canRequest):
* loader/CrossOriginPreflightChecker.cpp:
(WebCore::CrossOriginPreflightChecker::redirectReceived):
(WebCore::CrossOriginPreflightChecker::startPreflight):
* loader/CrossOriginPreflightChecker.h:

LayoutTests:

* http/tests/fetch/redirectmode-and-preload-expected.txt:
* http/tests/fetch/redirectmode-and-preload.html:

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

14 files changed:
LayoutTests/ChangeLog
LayoutTests/http/tests/fetch/redirectmode-and-preload-expected.txt
LayoutTests/http/tests/fetch/redirectmode-and-preload.html
LayoutTests/imported/w3c/ChangeLog
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-mode-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-mode-worker-expected.txt
LayoutTests/imported/w3c/web-platform-tests/fetch/api/redirect/redirect-mode.js
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-redirect.https-expected.txt
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-event-redirect.https.html
LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/fetch-request-redirect.https-expected.txt
Source/WebCore/ChangeLog
Source/WebCore/loader/CrossOriginPreflightChecker.cpp
Source/WebCore/loader/CrossOriginPreflightChecker.h
Source/WebCore/loader/cache/CachedResourceLoader.cpp

index 08d3cf6..6c841ec 100644 (file)
@@ -1,3 +1,14 @@
+2018-01-20  Youenn Fablet  <youenn@apple.com>
+
+        fetch redirect is incompatible with "no-cors" mode
+        https://bugs.webkit.org/show_bug.cgi?id=181866
+        <rdar://problem/35827140>
+
+        Reviewed by Chris Dumez.
+
+        * http/tests/fetch/redirectmode-and-preload-expected.txt:
+        * http/tests/fetch/redirectmode-and-preload.html:
+
 2018-01-19  Ryan Haddad  <ryanhaddad@apple.com>
 
         Mark imported/w3c/web-platform-tests/service-workers/service-worker/fetch-cors-xhr.https.html as flaky.
index e958842..ac99d05 100644 (file)
@@ -1,4 +1,7 @@
-CONSOLE MESSAGE: Fetch API cannot load http://127.0.0.1:8000/fetch/resources/redirect-with-cache.php?enableCaching&url=http://localhost:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2F127.0.0.1%3A8000&name=alert-fail.js&contentType=text/ascii. Redirections are not allowed
+CONSOLE MESSAGE: line 19: No-Cors mode requires follow redirect mode
+CONSOLE MESSAGE: line 19: Fetch API cannot load http://127.0.0.1:8000/fetch/resources/redirect-with-cache.php?enableCaching&url=http://localhost:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2F127.0.0.1%3A8000&name=alert-fail.js&contentType=text/ascii. Not allowed to request resource
+CONSOLE MESSAGE: line 32: No-Cors mode requires follow redirect mode
+CONSOLE MESSAGE: line 32: Fetch API cannot load http://127.0.0.1:8000/fetch/resources/redirect-with-cache.php?enableCaching&url=http://localhost:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2F127.0.0.1%3A8000&name=alert-fail.js&contentType=text/ascii. Not allowed to request resource
 CONSOLE MESSAGE: Fetch API cannot load http://127.0.0.1:8000/fetch/resources/redirect-with-cache.php?enableCaching&url=http://localhost:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2F127.0.0.1%3A8000&name=alert-fail.js&contentType=text/ascii. Redirections are not allowed
 
 PASS Fetch should check for redirections even if resource is preloaded (same fetch options except for redirect mode) 
index b0b1dd6..8dbb008 100644 (file)
@@ -16,12 +16,7 @@ function startTests()
 {
     var preloadUrl = "./resources/redirect-with-cache.php?enableCaching&url=http://localhost:8000/security/resources/allow-if-origin.php?allowCache&origin=http%3A%2F%2F127.0.0.1%3A8000&name=alert-fail.js&contentType=text/ascii";
     promise_test(function(test) {
-        return fetch(preloadUrl, {redirect: "manual", mode: "no-cors", credentials: "include"}).then((response) => {
-            assert_equals(response.type, "opaqueredirect", "Response's type should be opaqueRedirect");
-            return response.text();
-        }).then((text) => {
-            assert_equals(text, "");
-        });
+        return promise_rejects(test,new TypeError(), fetch(preloadUrl, {redirect: "manual", mode: "no-cors", credentials: "include"}));
     }, "Fetch should check for redirections even if resource is preloaded (same fetch options except for redirect mode)");
 
     promise_test(function(test) {
index 02cf10a..c41a5d8 100644 (file)
@@ -1,3 +1,19 @@
+2018-01-20  Youenn Fablet  <youenn@apple.com>
+
+        fetch redirect is incompatible with "no-cors" mode
+        https://bugs.webkit.org/show_bug.cgi?id=181866
+        <rdar://problem/35827140>
+
+        Reviewed by Chris Dumez.
+
+        * web-platform-tests/fetch/api/redirect/redirect-mode-expected.txt:
+        * web-platform-tests/fetch/api/redirect/redirect-mode-worker-expected.txt:
+        * web-platform-tests/fetch/api/redirect/redirect-mode.js:
+        (redirectMode):
+        * web-platform-tests/service-workers/service-worker/fetch-event-redirect.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/fetch-event-redirect.https.html:
+        * web-platform-tests/service-workers/service-worker/fetch-request-redirect.https-expected.txt:
+
 2018-01-19  Joseph Pecoraro  <pecoraro@apple.com>
 
         AppCache: Log a Deprecation warning to the Console when AppCache is used
index dddda69..3f1f1ac 100644 (file)
@@ -1,17 +1,19 @@
 
-PASS Redirect 301 in "error" mode  
-PASS Redirect 301 in "follow" mode  
-PASS Redirect 301 in "manual" mode  
-PASS Redirect 302 in "error" mode  
-PASS Redirect 302 in "follow" mode  
-PASS Redirect 302 in "manual" mode  
-PASS Redirect 303 in "error" mode  
-PASS Redirect 303 in "follow" mode  
-PASS Redirect 303 in "manual" mode  
-PASS Redirect 307 in "error" mode  
-PASS Redirect 307 in "follow" mode  
-PASS Redirect 307 in "manual" mode  
-PASS Redirect 308 in "error" mode  
-PASS Redirect 308 in "follow" mode  
-PASS Redirect 308 in "manual" mode  
+PASS Redirect 301 in "error" redirect, cors mode 
+PASS Redirect 301 in "follow" redirect, cors mode 
+PASS Redirect 301 in "manual" redirect, cors mode 
+PASS Redirect 302 in "error" redirect, cors mode 
+PASS Redirect 302 in "follow" redirect, cors mode 
+PASS Redirect 302 in "manual" redirect, cors mode 
+PASS Redirect 303 in "error" redirect, cors mode 
+PASS Redirect 303 in "follow" redirect, cors mode 
+PASS Redirect 303 in "manual" redirect, cors mode 
+PASS Redirect 307 in "error" redirect, cors mode 
+PASS Redirect 307 in "follow" redirect, cors mode 
+PASS Redirect 307 in "manual" redirect, cors mode 
+PASS Redirect 308 in "error" redirect, cors mode 
+PASS Redirect 308 in "follow" redirect, cors mode 
+PASS Redirect 308 in "manual" redirect, cors mode 
+PASS Redirect in "error" redirect, no cors mode 
+PASS Redirect in "manual" redirect, no cors mode 
 
index dddda69..885b325 100644 (file)
@@ -1,17 +1,21 @@
+CONSOLE MESSAGE: No-Cors mode requires follow redirect mode
+CONSOLE MESSAGE: No-Cors mode requires follow redirect mode
 
-PASS Redirect 301 in "error" mode  
-PASS Redirect 301 in "follow" mode  
-PASS Redirect 301 in "manual" mode  
-PASS Redirect 302 in "error" mode  
-PASS Redirect 302 in "follow" mode  
-PASS Redirect 302 in "manual" mode  
-PASS Redirect 303 in "error" mode  
-PASS Redirect 303 in "follow" mode  
-PASS Redirect 303 in "manual" mode  
-PASS Redirect 307 in "error" mode  
-PASS Redirect 307 in "follow" mode  
-PASS Redirect 307 in "manual" mode  
-PASS Redirect 308 in "error" mode  
-PASS Redirect 308 in "follow" mode  
-PASS Redirect 308 in "manual" mode  
+PASS Redirect 301 in "error" redirect, cors mode 
+PASS Redirect 301 in "follow" redirect, cors mode 
+PASS Redirect 301 in "manual" redirect, cors mode 
+PASS Redirect 302 in "error" redirect, cors mode 
+PASS Redirect 302 in "follow" redirect, cors mode 
+PASS Redirect 302 in "manual" redirect, cors mode 
+PASS Redirect 303 in "error" redirect, cors mode 
+PASS Redirect 303 in "follow" redirect, cors mode 
+PASS Redirect 303 in "manual" redirect, cors mode 
+PASS Redirect 307 in "error" redirect, cors mode 
+PASS Redirect 307 in "follow" redirect, cors mode 
+PASS Redirect 307 in "manual" redirect, cors mode 
+PASS Redirect 308 in "error" redirect, cors mode 
+PASS Redirect 308 in "follow" redirect, cors mode 
+PASS Redirect 308 in "manual" redirect, cors mode 
+PASS Redirect in "error" redirect, no cors mode 
+PASS Redirect in "manual" redirect, no cors mode 
 
index b59a8d5..badc32a 100644 (file)
@@ -3,15 +3,15 @@ if (this.document === undefined) {
   importScripts("/common/get-host-info.sub.js")
 }
 
-function redirectMode(desc, redirectUrl, redirectLocation, redirectStatus, redirectMode) {
+function redirectMode(desc, redirectUrl, redirectLocation, redirectStatus, redirectMode, corsMode) {
   var url = redirectUrl;
   var urlParameters = "?redirect_status=" + redirectStatus;
   urlParameters += "&location=" + encodeURIComponent(redirectLocation);
 
-  var requestInit = {"redirect": redirectMode};
+  var requestInit = {"redirect": redirectMode, mode: corsMode};
 
   promise_test(function(test) {
-    if (redirectMode === "error")
+    if (redirectMode === "error" || (corsMode === "no-cors" && redirectMode !== "follow"))
       return promise_rejects(test, new TypeError(), fetch(url + urlParameters, requestInit));
     if (redirectMode === "manual")
       return fetch(url + urlParameters, requestInit).then(function(resp) {
@@ -33,9 +33,11 @@ var redirUrl = get_host_info().HTTP_ORIGIN + "/fetch/api/resources/redirect.py";
 var locationUrl = "top.txt";
 
 for (var statusCode of [301, 302, 303, 307, 308]) {
-  redirectMode("Redirect " + statusCode + " in \"error\" mode ", redirUrl, locationUrl, statusCode, "error");
-  redirectMode("Redirect " + statusCode + " in \"follow\" mode ", redirUrl, locationUrl, statusCode, "follow");
-  redirectMode("Redirect " + statusCode + " in \"manual\" mode ", redirUrl, locationUrl, statusCode, "manual");
+  redirectMode("Redirect " + statusCode + " in \"error\" redirect, cors mode", redirUrl, locationUrl, statusCode, "error", "cors");
+  redirectMode("Redirect " + statusCode + " in \"follow\" redirect, cors mode", redirUrl, locationUrl, statusCode, "follow", "cors");
+  redirectMode("Redirect " + statusCode + " in \"manual\" redirect, cors mode", redirUrl, locationUrl, statusCode, "manual", "cors");
 }
+redirectMode("Redirect in \"error\" redirect, no cors mode", redirUrl, locationUrl, 301, "error", "no-cors");
+redirectMode("Redirect in \"manual\" redirect, no cors mode", redirUrl, locationUrl, 301, "manual", "no-cors");
 
 done();
index 8da7b1d..3dcc2a2 100644 (file)
@@ -1,3 +1,7 @@
+CONSOLE MESSAGE: line 51: No-Cors mode requires follow redirect mode
+CONSOLE MESSAGE: line 51: Fetch API cannot load https://localhost:9443/nonav-manual-nocors-redirects-to-sameorigin-nocreds?url=redirect.py%3FRedirect%3Dhttps%253A%252F%252Flocalhost%253A9443%252Fservice-workers%252Fservice-worker%252Fresources%252Fsuccess.py&expected_type=opaqueredirect. Not allowed to request resource
+CONSOLE MESSAGE: line 51: No-Cors mode requires follow redirect mode
+CONSOLE MESSAGE: line 51: Fetch API cannot load https://localhost:9443/nonav-error-nocors-redirects-to-sameorigin-nocreds?url=redirect.py%3FRedirect%3Dhttps%253A%252F%252Flocalhost%253A9443%252Fservice-workers%252Fservice-worker%252Fresources%252Fsuccess.py. Not allowed to request resource
 
 PASS initialize global state 
 PASS Non-navigation, manual redirect, cors mode Request redirected to same-origin without credentials should succeed opaqueredirect interception and response should not be redirected 
@@ -6,18 +10,13 @@ PASS Non-navigation, manual redirect, cors mode Request redirected to cors witho
 PASS Non-navigation, manual redirect, same-origin mode Request redirected to same-origin without credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, same-origin mode Request redirected to no-cors without credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, same-origin mode Request redirected to cors without credentials should succeed opaqueredirect interception and response should not be redirected 
-PASS Non-navigation, manual redirect, no-cors mode Request redirected to same-origin without credentials should succeed opaqueredirect interception and response should not be redirected 
-PASS Non-navigation, manual redirect, no-cors mode Request redirected to no-cors without credentials should succeed interception and response should not be redirected 
-PASS Non-navigation, manual redirect, no-cors mode Request redirected to cors without credentials should succeed interception and response should not be redirected 
+PASS Non-navigation, manual redirect, no-cors mode Request should fail 
 PASS Non-navigation, manual redirect, cors mode Request redirected to same-origin with credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, cors mode Request redirected to no-cors with credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, cors mode Request redirected to cors with credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, same-origin mode Request redirected to same-origin with credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, same-origin mode Request redirected to no-cors with credentials should succeed opaqueredirect interception and response should not be redirected 
 PASS Non-navigation, manual redirect, same-origin mode Request redirected to cors with credentials should succeed opaqueredirect interception and response should not be redirected 
-PASS Non-navigation, manual redirect, no-cors mode Request redirected to same-origin with credentials should succeed opaqueredirect interception and response should not be redirected 
-PASS Non-navigation, manual redirect, no-cors mode Request redirected to no-cors with credentials should succeed interception and response should not be redirected 
-PASS Non-navigation, manual redirect, no-cors mode Request redirected to cors with credentials should succeed interception and response should not be redirected 
 PASS Non-navigation, follow redirect, cors mode Request redirected to same-origin without credentials should succeed interception and response should be redirected 
 PASS Non-navigation, follow redirect, cors mode Request redirected to no-cors without credentials should fail interception and response should not be redirected 
 PASS Non-navigation, follow redirect, cors mode Request redirected to cors without credentials should succeed interception and response should be redirected 
@@ -42,17 +41,12 @@ PASS Non-navigation, error redirect, cors mode Request redirected to cors withou
 PASS Non-navigation, error redirect, same-origin mode Request redirected to same-origin without credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, same-origin mode Request redirected to no-cors without credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, same-origin mode Request redirected to cors without credentials should fail interception and response should not be redirected 
-PASS Non-navigation, error redirect, no-cors mode Request redirected to same-origin without credentials should fail interception and response should not be redirected 
-PASS Non-navigation, error redirect, no-cors mode Request redirected to no-cors without credentials should fail interception and response should not be redirected 
-PASS Non-navigation, error redirect, no-cors mode Request redirected to cors without credentials should fail interception and response should not be redirected 
+PASS Non-navigation, error redirect, no-cors mode Request should fail 
 PASS Non-navigation, error redirect, cors mode Request redirected to same-origin with credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, cors mode Request redirected to no-cors with credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, cors mode Request redirected to cors with credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, same-origin mode Request redirected to same-origin with credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, same-origin mode Request redirected to no-cors with credentials should fail interception and response should not be redirected 
 PASS Non-navigation, error redirect, same-origin mode Request redirected to cors with credentials should fail interception and response should not be redirected 
-PASS Non-navigation, error redirect, no-cors mode Request redirected to same-origin with credentials should fail interception and response should not be redirected 
-PASS Non-navigation, error redirect, no-cors mode Request redirected to no-cors with credentials should fail interception and response should not be redirected 
-PASS Non-navigation, error redirect, no-cors mode Request redirected to cors with credentials should fail interception and response should not be redirected 
 PASS restore global state 
 
index c72be76..f348ca0 100644 (file)
@@ -212,45 +212,9 @@ promise_test(function(t) {
       redirect: 'manual',
       mode: 'no-cors'
     },
-    should_reject: false
-  });
-}, 'Non-navigation, manual redirect, no-cors mode Request redirected to ' +
-   'same-origin without credentials should succeed opaqueredirect interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-manual-nocors-redirects-to-nocors-nocreds',
-    redirect_dest: 'no-cors',
-    url_credentials: false,
-    expected_type: 'opaqueredirect',
-    expected_redirected: false,
-    request_init: {
-      redirect: 'manual',
-      mode: 'no-cors'
-    },
-    should_reject: false
-  });
-}, 'Non-navigation, manual redirect, no-cors mode Request redirected to ' +
-   'no-cors without credentials should succeed interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-manual-nocors-redirects-to-cors-nocreds',
-    redirect_dest: 'cors',
-    url_credentials: false,
-    expected_type: 'opaqueredirect',
-    expected_redirected: false,
-    request_init: {
-      redirect: 'manual',
-      mode: 'no-cors'
-    },
-    should_reject: false
+    should_reject: true
   });
-}, 'Non-navigation, manual redirect, no-cors mode Request redirected to ' +
-   'cors without credentials should succeed interception ' +
-   'and response should not be redirected');
+}, 'Non-navigation, manual redirect, no-cors mode Request should fail');
 
 promise_test(function(t) {
   return redirect_fetch_test(t, {
@@ -356,57 +320,6 @@ promise_test(function(t) {
 
 promise_test(function(t) {
   return redirect_fetch_test(t, {
-    name: 'nonav-manual-nocors-redirects-to-sameorigin-creds',
-    redirect_dest: 'same-origin',
-    url_credentials: true,
-    expected_type: 'opaqueredirect',
-    expected_redirected: false,
-    request_init: {
-      redirect: 'manual',
-      mode: 'no-cors'
-    },
-    should_reject: false
-  });
-}, 'Non-navigation, manual redirect, no-cors mode Request redirected to ' +
-   'same-origin with credentials should succeed opaqueredirect interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-manual-nocors-redirects-to-nocors-creds',
-    redirect_dest: 'no-cors',
-    url_credentials: true,
-    expected_type: 'opaqueredirect',
-    expected_redirected: false,
-    request_init: {
-      redirect: 'manual',
-      mode: 'no-cors'
-    },
-    should_reject: false
-  });
-}, 'Non-navigation, manual redirect, no-cors mode Request redirected to ' +
-   'no-cors with credentials should succeed interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-manual-nocors-redirects-to-cors-creds',
-    redirect_dest: 'cors',
-    url_credentials: true,
-    expected_type: 'opaqueredirect',
-    expected_redirected: false,
-    request_init: {
-      redirect: 'manual',
-      mode: 'no-cors'
-    },
-    should_reject: false
-  });
-}, 'Non-navigation, manual redirect, no-cors mode Request redirected to ' +
-   'cors with credentials should succeed interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
     name: 'nonav-follow-cors-redirects-to-sameorigin-nocreds',
     redirect_dest: 'same-origin',
     url_credentials: false,
@@ -823,47 +736,10 @@ promise_test(function(t) {
       redirect: 'error',
       mode: 'no-cors'
     },
-    // should reject because requests with 'error' RequestRedirect cannot be
-    // redirected.
-    should_reject: true
-  });
-}, 'Non-navigation, error redirect, no-cors mode Request redirected to ' +
-   'same-origin without credentials should fail interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-error-nocors-redirects-to-nocors-nocreds',
-    redirect_dest: 'no-cors',
-    url_credentials: false,
-    request_init: {
-      redirect: 'error',
-      mode: 'no-cors'
-    },
-    // should reject because requests with 'error' RequestRedirect cannot be
-    // redirected.
+    // should reject because error + no-cors is not allowed.
     should_reject: true
   });
-}, 'Non-navigation, error redirect, no-cors mode Request redirected to ' +
-   'no-cors without credentials should fail interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-error-nocors-redirects-to-cors-nocreds',
-    redirect_dest: 'cors',
-    url_credentials: false,
-    request_init: {
-      redirect: 'error',
-      mode: 'no-cors'
-    },
-    // should reject because requests with 'error' RequestRedirect cannot be
-    // redirected.
-    should_reject: true
-  });
-}, 'Non-navigation, error redirect, no-cors mode Request redirected to ' +
-   'cors without credentials should fail interception ' +
-   'and response should not be redirected');
+}, 'Non-navigation, error redirect, no-cors mode Request should fail');
 
 promise_test(function(t) {
   return redirect_fetch_test(t, {
@@ -966,56 +842,5 @@ promise_test(function(t) {
 }, 'Non-navigation, error redirect, same-origin mode Request redirected to ' +
    'cors with credentials should fail interception ' +
    'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-error-nocors-redirects-to-sameorigin-creds',
-    redirect_dest: 'same-origin',
-    url_credentials: true,
-    request_init: {
-      redirect: 'error',
-      mode: 'no-cors'
-    },
-    // should reject because requests with 'error' RequestRedirect cannot be
-    // redirected.
-    should_reject: true
-  });
-}, 'Non-navigation, error redirect, no-cors mode Request redirected to ' +
-   'same-origin with credentials should fail interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-error-nocors-redirects-to-nocors-creds',
-    redirect_dest: 'no-cors',
-    url_credentials: true,
-    request_init: {
-      redirect: 'error',
-      mode: 'no-cors'
-    },
-    // should reject because requests with 'error' RequestRedirect cannot be
-    // redirected.
-    should_reject: true
-  });
-}, 'Non-navigation, error redirect, no-cors mode Request redirected to ' +
-   'no-cors with credentials should fail interception ' +
-   'and response should not be redirected');
-
-promise_test(function(t) {
-  return redirect_fetch_test(t, {
-    name: 'nonav-error-nocors-redirects-to-cors-creds',
-    redirect_dest: 'cors',
-    url_credentials: true,
-    request_init: {
-      redirect: 'error',
-      mode: 'no-cors'
-    },
-    // should reject because requests with 'error' RequestRedirect cannot be
-    // redirected.
-    should_reject: true
-  });
-}, 'Non-navigation, error redirect, no-cors mode Request redirected to ' +
-   'cors with credentials should fail interception and response should not ' +
-   'be redirected');
 </script>
 </body>
index f562b2d..c2c1912 100644 (file)
@@ -1,7 +1,4 @@
 CONSOLE MESSAGE: XMLHttpRequest cannot load https://localhost:9443/service-workers/service-worker/resources/redirect.py?Redirect=%2Fservice-workers%2Fservice-worker%2Fresources%2Fsimple.txt. Response served by service worker is opaque redirect
-CONSOLE MESSAGE: Cross-origin image load denied by Cross-Origin Resource Sharing policy.
-CONSOLE MESSAGE: XMLHttpRequest cannot load https://localhost:9443/service-workers/service-worker/resources/redirect.py?Redirect=%2Fservice-workers%2Fservice-worker%2Fresources%2Fsimple.txt. Response served by service worker is opaque redirect
-CONSOLE MESSAGE: XMLHttpRequest cannot load https://localhost:9443/service-workers/service-worker/resources/redirect.py?Redirect=%2Fservice-workers%2Fservice-worker%2Fresources%2Fsimple.txt. Response served by service worker is opaque redirect
 
 PASS Verify redirect mode of Fetch API and ServiceWorker FetchEvent. 
 PASS Verify redirected of Response(Fetch API) and ServiceWorker FetchEvent. 
index 0bfca57..aa611bb 100644 (file)
@@ -1,3 +1,24 @@
+2018-01-20  Youenn Fablet  <youenn@apple.com>
+
+        fetch redirect is incompatible with "no-cors" mode
+        https://bugs.webkit.org/show_bug.cgi?id=181866
+        <rdar://problem/35827140>
+
+        Reviewed by Chris Dumez.
+
+        Covered by updated tests.
+
+        Return a network error when no-cors mode and redirect mode is manual or error.
+        Update preflight implementation to no longer use manual redirect mode to simulate https://fetch.spec.whatwg.org/#http-network-or-cache-fetch.
+        Instead implement redirectReceived callback to treat any redirect response as the preflight response.
+
+        * loader/cache/CachedResourceLoader.cpp:
+        (WebCore::CachedResourceLoader::canRequest):
+        * loader/CrossOriginPreflightChecker.cpp:
+        (WebCore::CrossOriginPreflightChecker::redirectReceived):
+        (WebCore::CrossOriginPreflightChecker::startPreflight):
+        * loader/CrossOriginPreflightChecker.h:
+
 2018-01-19  Wenson Hsieh  <wenson_hsieh@apple.com>
 
         [macOS] [WK2] Drag location is computed incorrectly when dragging content from subframes
index 7d375fe..9aa9b61 100644 (file)
@@ -95,11 +95,17 @@ void CrossOriginPreflightChecker::notifyFinished(CachedResource& resource)
     validatePreflightResponse(m_loader, WTFMove(m_request), m_resource->identifier(), m_resource->response());
 }
 
+void CrossOriginPreflightChecker::redirectReceived(CachedResource& resource, ResourceRequest&&, const ResourceResponse& response, CompletionHandler<void(ResourceRequest&&)>&& completionHandler)
+{
+    ASSERT_UNUSED(resource, &resource == m_resource);
+    validatePreflightResponse(m_loader, WTFMove(m_request), m_resource->identifier(), response);
+    completionHandler(ResourceRequest { });
+}
+
 void CrossOriginPreflightChecker::startPreflight()
 {
     ResourceLoaderOptions options;
     options.referrerPolicy = m_loader.options().referrerPolicy;
-    options.redirect = FetchOptions::Redirect::Manual;
     options.contentSecurityPolicyImposition = ContentSecurityPolicyImposition::SkipPolicyCheck;
     options.serviceWorkersMode = ServiceWorkersMode::None;
 
index 6971c31..9a40026 100644 (file)
@@ -54,6 +54,7 @@ public:
 
 private:
     void notifyFinished(CachedResource&) final;
+    void redirectReceived(CachedResource&, ResourceRequest&&, const ResourceResponse&, CompletionHandler<void(ResourceRequest&&)>&&) final;
 
     static void handleLoadingFailure(DocumentThreadableLoader&, unsigned long, const ResourceError&);
     static void validatePreflightResponse(DocumentThreadableLoader&, ResourceRequest&&, unsigned long, const ResourceResponse&);
index ce3b915..6209ebb 100644 (file)
@@ -507,6 +507,7 @@ static inline bool isSameOriginDataURL(const URL& url, const ResourceLoaderOptio
     return url.protocolIsData() && options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set;
 }
 
+// Security checks defined in https://fetch.spec.whatwg.org/#main-fetch step 2 and 5.
 bool CachedResourceLoader::canRequest(CachedResource::Type type, const URL& url, const CachedResourceRequest& request, ForPreload forPreload)
 {
     auto& options = request.options();
@@ -523,6 +524,12 @@ bool CachedResourceLoader::canRequest(CachedResource::Type type, const URL& url,
         return false;
     }
 
+    if (options.mode == FetchOptions::Mode::NoCors && options.redirect != FetchOptions::Redirect::Follow) {
+        ASSERT(type != CachedResource::Type::MainResource);
+        frame()->document()->addConsoleMessage(MessageSource::Security, MessageLevel::Error, ASCIILiteral("No-Cors mode requires follow redirect mode"));
+        return false;
+    }
+
     if (!allowedByContentSecurityPolicy(type, url, options, ContentSecurityPolicy::RedirectResponseReceived::No))
         return false;