Navigation requests should use navigate fetch mode
https://bugs.webkit.org/show_bug.cgi?id=179808

Patch by Youenn Fablet <youenn@apple.com> on 2017-12-12
Reviewed by Chris Dumez.

LayoutTests/imported/w3c:

* web-platform-tests/service-workers/service-worker/fetch-request-redirect.https-expected.txt:
* web-platform-tests/service-workers/service-worker/navigation-redirect.https-expected.txt:
* web-platform-tests/service-workers/service-worker/register-same-scope-different-script-url.https-expected.txt:
* web-platform-tests/service-workers/service-worker/request-end-to-end.https-expected.txt:
This is a progression since test is failing at a later point. Test might need being updated to match latest fetch spec.
* web-platform-tests/service-workers/service-worker/resources/clients-get-worker.js:
(self.onfetch): Change upstreamed at https://github.com/w3c/web-platform-tests/pull/8289.

Source/WebCore:

Covered by existing tests.

* Modules/fetch/FetchRequest.cpp:
(WebCore::buildOptions): Update to throw only if init.mode is Navigate.
* Modules/fetch/FetchRequestInit.h:
(WebCore::FetchRequestInit::hasMembers const): If init is present, set default values as per spec.
* loader/DocumentLoader.cpp:
(WebCore::DocumentLoader::loadMainResource): Set fetch mode to navigate.
* loader/DocumentThreadableLoader.cpp:
(WebCore::DocumentThreadableLoader::DocumentThreadableLoader): Bypass preflight in case fetch mode is navigate.

LayoutTests:

* http/tests/workers/service/basic-fetch.https-expected.txt:
* http/tests/workers/service/resources/basic-fetch-worker.js:
* http/tests/workers/service/resources/basic-fetch.js:
(async.test):

git-svn-id: http://svn.webkit.org/repository/webkit/trunk@225796 268f45cc-cd09-0410-ab3c-d52691b4dbfc
diff --git a/LayoutTests/ChangeLog b/LayoutTests/ChangeLog
index 441d50e..49cf841 100644
--- a/LayoutTests/ChangeLog
+++ b/LayoutTests/ChangeLog
@@ -1,5 +1,17 @@
 2017-12-12  Youenn Fablet  <youenn@apple.com>
 
+        Navigation requests should use navigate fetch mode
+        https://bugs.webkit.org/show_bug.cgi?id=179808
+
+        Reviewed by Chris Dumez.
+
+        * http/tests/workers/service/basic-fetch.https-expected.txt:
+        * http/tests/workers/service/resources/basic-fetch-worker.js:
+        * http/tests/workers/service/resources/basic-fetch.js:
+        (async.test):
+
+2017-12-12  Youenn Fablet  <youenn@apple.com>
+
         Rebasing/unskipping some WPT service worker tests
         https://bugs.webkit.org/show_bug.cgi?id=180705
 
diff --git a/LayoutTests/http/tests/workers/service/basic-fetch.https-expected.txt b/LayoutTests/http/tests/workers/service/basic-fetch.https-expected.txt
index 7525785..68f0585 100644
--- a/LayoutTests/http/tests/workers/service/basic-fetch.https-expected.txt
+++ b/LayoutTests/http/tests/workers/service/basic-fetch.https-expected.txt
@@ -9,4 +9,5 @@
 PASS: test3 fetch failed as expected
 test4 status code: 404
 PASS: test5 fetch failed as expected
+PASS: / fetch failed as expected
 
diff --git a/LayoutTests/http/tests/workers/service/resources/basic-fetch-worker.js b/LayoutTests/http/tests/workers/service/resources/basic-fetch-worker.js
index dc117c7..51eab79 100644
--- a/LayoutTests/http/tests/workers/service/resources/basic-fetch-worker.js
+++ b/LayoutTests/http/tests/workers/service/resources/basic-fetch-worker.js
@@ -19,5 +19,9 @@
         return;
     }
 
+    if (event.request.mode !== "navigate") {
+        event.respondWith(Response.error());
+        return;
+    }
     event.respondWith(fetch(event.request.url));
 });
diff --git a/LayoutTests/http/tests/workers/service/resources/basic-fetch.js b/LayoutTests/http/tests/workers/service/resources/basic-fetch.js
index f70630a..d746d39 100644
--- a/LayoutTests/http/tests/workers/service/resources/basic-fetch.js
+++ b/LayoutTests/http/tests/workers/service/resources/basic-fetch.js
@@ -40,6 +40,13 @@
             log("PASS: test5 fetch failed as expected");
         }
 
+        try {
+            response = await fetch("/");
+            log("FAIL: / fetch succeeded unexpectedly");
+            log("/ status code: " + response.status);
+        } catch (e) {
+            log("PASS: / fetch failed as expected");
+        }
     } catch(e) {
         log("Got exception: " + e);
     }
diff --git a/LayoutTests/imported/w3c/ChangeLog b/LayoutTests/imported/w3c/ChangeLog
index 4139915..abc444a 100644
--- a/LayoutTests/imported/w3c/ChangeLog
+++ b/LayoutTests/imported/w3c/ChangeLog
@@ -1,5 +1,20 @@
 2017-12-12  Youenn Fablet  <youenn@apple.com>
 
+        Navigation requests should use navigate fetch mode
+        https://bugs.webkit.org/show_bug.cgi?id=179808
+
+        Reviewed by Chris Dumez.
+
+        * web-platform-tests/service-workers/service-worker/fetch-request-redirect.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/navigation-redirect.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/register-same-scope-different-script-url.https-expected.txt:
+        * web-platform-tests/service-workers/service-worker/request-end-to-end.https-expected.txt:
+        This is a progression since test is failing at a later point. Test might need being updated to match latest fetch spec.
+        * web-platform-tests/service-workers/service-worker/resources/clients-get-worker.js:
+        (self.onfetch): Change upstreamed at https://github.com/w3c/web-platform-tests/pull/8289.
+
+2017-12-12  Youenn Fablet  <youenn@apple.com>
+
         Rebasing/unskipping some WPT service worker tests
         https://bugs.webkit.org/show_bug.cgi?id=180705
 
diff --git a/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/request-end-to-end.https-expected.txt b/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/request-end-to-end.https-expected.txt
index 69e21c6..2cbf3ae 100644
--- a/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/request-end-to-end.https-expected.txt
+++ b/LayoutTests/imported/w3c/web-platform-tests/service-workers/service-worker/request-end-to-end.https-expected.txt
@@ -1,3 +1,3 @@
 
-FAIL Test FetchEvent.request passed to onfetch assert_equals: request.mode expected "navigate" but got "no-cors"
+FAIL Test FetchEvent.request passed to onfetch assert_equals: Constructing a Request with a Request whose mode is navigate and non-empty RequestInit must throw a TypeError. expected "TypeError" but got ""
 
diff --git a/Source/WebCore/ChangeLog b/Source/WebCore/ChangeLog
index 614e4c1..ad8e8d4 100644
--- a/Source/WebCore/ChangeLog
+++ b/Source/WebCore/ChangeLog
@@ -1,3 +1,21 @@
+2017-12-12  Youenn Fablet  <youenn@apple.com>
+
+        Navigation requests should use navigate fetch mode
+        https://bugs.webkit.org/show_bug.cgi?id=179808
+
+        Reviewed by Chris Dumez.
+
+        Covered by existing tests.
+
+        * Modules/fetch/FetchRequest.cpp:
+        (WebCore::buildOptions): Update to throw only if init.mode is Navigate.
+        * Modules/fetch/FetchRequestInit.h:
+        (WebCore::FetchRequestInit::hasMembers const): If init is present, set default values as per spec.
+        * loader/DocumentLoader.cpp:
+        (WebCore::DocumentLoader::loadMainResource): Set fetch mode to navigate.
+        * loader/DocumentThreadableLoader.cpp:
+        (WebCore::DocumentThreadableLoader::DocumentThreadableLoader): Bypass preflight in case fetch mode is navigate.
+
 2017-12-12  Simon Fraser  <simon.fraser@apple.com>
 
         HTML-page with <object type="image/svg+xml" data="foo.svg"> often is blank
diff --git a/Source/WebCore/Modules/fetch/FetchRequest.cpp b/Source/WebCore/Modules/fetch/FetchRequest.cpp
index f2b2b29..b3b7cde 100644
--- a/Source/WebCore/Modules/fetch/FetchRequest.cpp
+++ b/Source/WebCore/Modules/fetch/FetchRequest.cpp
@@ -69,6 +69,13 @@
     if (!init.window.isUndefinedOrNull() && !init.window.isEmpty())
         return Exception { TypeError, ASCIILiteral("Window can only be null.") };
 
+    if (init.hasMembers()) {
+        if (options.mode == FetchOptions::Mode::Navigate)
+            options.mode = FetchOptions::Mode::SameOrigin;
+        referrer = ASCIILiteral("client");
+        options.referrerPolicy = { };
+    }
+
     if (!init.referrer.isNull()) {
         auto result = computeReferrer(context, init.referrer);
         if (result.hasException())
@@ -79,10 +86,11 @@
     if (init.referrerPolicy)
         options.referrerPolicy = init.referrerPolicy.value();
 
-    if (init.mode)
+    if (init.mode) {
         options.mode = init.mode.value();
-    if (options.mode == FetchOptions::Mode::Navigate)
-        return Exception { TypeError, ASCIILiteral("Request constructor does not accept navigate fetch mode.") };
+        if (options.mode == FetchOptions::Mode::Navigate)
+            return Exception { TypeError, ASCIILiteral("Request constructor does not accept navigate fetch mode.") };
+    }
 
     if (init.credentials)
         options.credentials = init.credentials.value();
diff --git a/Source/WebCore/Modules/fetch/FetchRequestInit.h b/Source/WebCore/Modules/fetch/FetchRequestInit.h
index 0733ef9..d30df7c 100644
--- a/Source/WebCore/Modules/fetch/FetchRequestInit.h
+++ b/Source/WebCore/Modules/fetch/FetchRequestInit.h
@@ -47,6 +47,8 @@
     String integrity;
     std::optional<bool> keepalive;
     JSC::JSValue window;
+
+    bool hasMembers() const { return !method.isEmpty() || headers || body || !referrer.isEmpty() || referrerPolicy || mode || credentials || cache || redirect || !integrity.isEmpty() || keepalive || !window.isUndefined(); }
 };
 
 }
diff --git a/Source/WebCore/loader/DocumentLoader.cpp b/Source/WebCore/loader/DocumentLoader.cpp
index 29d79af..c6045a8 100644
--- a/Source/WebCore/loader/DocumentLoader.cpp
+++ b/Source/WebCore/loader/DocumentLoader.cpp
@@ -1591,7 +1591,7 @@
 
 void DocumentLoader::loadMainResource(ResourceRequest&& request)
 {
-    static NeverDestroyed<ResourceLoaderOptions> mainResourceLoadOptions(SendCallbacks, SniffContent, BufferData, StoredCredentialsPolicy::Use, ClientCredentialPolicy::MayAskClientForCredentials, FetchOptions::Credentials::Include, SkipSecurityCheck, FetchOptions::Mode::NoCors, IncludeCertificateInfo, ContentSecurityPolicyImposition::SkipPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching);
+    static NeverDestroyed<ResourceLoaderOptions> mainResourceLoadOptions(SendCallbacks, SniffContent, BufferData, StoredCredentialsPolicy::Use, ClientCredentialPolicy::MayAskClientForCredentials, FetchOptions::Credentials::Include, SkipSecurityCheck, FetchOptions::Mode::Navigate, IncludeCertificateInfo, ContentSecurityPolicyImposition::SkipPolicyCheck, DefersLoadingPolicy::AllowDefersLoading, CachingPolicy::AllowCaching);
     CachedResourceRequest mainResourceRequest(ResourceRequest(request), mainResourceLoadOptions);
     if (!m_frame->isMainFrame() && m_frame->document()) {
         // If we are loading the main resource of a subframe, use the cache partition of the main document.
diff --git a/Source/WebCore/loader/DocumentThreadableLoader.cpp b/Source/WebCore/loader/DocumentThreadableLoader.cpp
index f650363..b70c864 100644
--- a/Source/WebCore/loader/DocumentThreadableLoader.cpp
+++ b/Source/WebCore/loader/DocumentThreadableLoader.cpp
@@ -128,7 +128,7 @@
     if (request.url().protocolIsData())
         m_sameOriginRequest = options.sameOriginDataURLFlag == SameOriginDataURLFlag::Set;
 
-    if (m_sameOriginRequest || m_options.mode == FetchOptions::Mode::NoCors) {
+    if (m_sameOriginRequest || m_options.mode == FetchOptions::Mode::NoCors || m_options.mode == FetchOptions::Mode::Navigate) {
         loadRequest(WTFMove(request), DoSecurityCheck);
         return;
     }