Hide Sec-Fetch-... headers from service worker `fetch` event.
This CL excludes Sec-Fetch-... request headers from the Request object
passes to the service worker's `fetch` event. This CL also adds WPT
tests that verify that these request headers will be re-added when the
service worker forwards the request back into the network (via implicit
fallback, or via an explicit responseWith+fetch).
Bug: 949997
Change-Id: I04422a1630f62b497961ca1789007f2402148e76
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/1611314
Commit-Queue: Ćukasz Anforowicz <lukasza@chromium.org>
Reviewed-by: Matt Falkenhagen <falken@chromium.org>
Cr-Commit-Position: refs/heads/master@{#659937}
diff --git a/content/renderer/service_worker/service_worker_context_client.cc b/content/renderer/service_worker/service_worker_context_client.cc
index 22e1e2a..5b6b4d6 100644
--- a/content/renderer/service_worker/service_worker_context_client.cc
+++ b/content/renderer/service_worker/service_worker_context_client.cc
@@ -204,6 +204,24 @@
map, std::forward<Args>(args)...);
}
+bool IsExcludedHeaderForServiceWorkerFetchEvent(
+ const std::string& header_name) {
+ // Excluding Sec-Fetch-... headers as suggested in
+ // https://crbug.com/949997#c4.
+ if (base::StartsWith(header_name, "sec-fetch-",
+ base::CompareCase::INSENSITIVE_ASCII)) {
+ return true;
+ }
+
+ if (GetContentClient()
+ ->renderer()
+ ->IsExcludedHeaderForServiceWorkerFetchEvent(header_name)) {
+ return true;
+ }
+
+ return false;
+}
+
} // namespace
// Holds data that needs to be bound to the worker context on the
@@ -1297,11 +1315,11 @@
web_request->SetURL(blink::WebURL(request->url));
web_request->SetMethod(blink::WebString::FromUTF8(request->method));
for (const auto& pair : request->headers) {
- if (!GetContentClient()
- ->renderer()
- ->IsExcludedHeaderForServiceWorkerFetchEvent(pair.first)) {
- web_request->SetHeader(blink::WebString::FromUTF8(pair.first),
- blink::WebString::FromUTF8(pair.second));
+ const std::string& header_name = pair.first;
+ const std::string& header_value = pair.second;
+ if (!IsExcludedHeaderForServiceWorkerFetchEvent(header_name)) {
+ web_request->SetHeader(blink::WebString::FromUTF8(header_name),
+ blink::WebString::FromUTF8(header_value));
}
}
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html
new file mode 100644
index 0000000..e8ec11e
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch-via-serviceworker--fallback.tentative.https.sub.html
@@ -0,0 +1,50 @@
+<!DOCTYPE html>
+<!--
+ This test verifies presence of Sec-Fetch-... request headers on a request
+ handled by a service worker - this test covers the scenario when the service
+ worker doesn't do anything and the request falls back to the network.
+-->
+<meta charset="utf-8"/>
+<link rel="author" href="lukasza@chromium.org" title="Lukasz Anforowicz">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script src=/common/utils.js></script>
+<script>
+ const nonce = token();
+ const key = "fetch-via-serviceworker--fallback--" + nonce;
+
+ promise_test(async function(t) {
+ const SCOPE = 'resources/fetch-via-serviceworker--fallback--frame.html';
+ const SCRIPT = 'resources/fetch-via-serviceworker--fallback--sw.js';
+ const URL = '/fetch/sec-metadata/resources/record-header.py?file=' + key;
+ const RETRIEVAL_URL = "/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key;
+
+ const reg = await service_worker_unregister_and_register(t, SCRIPT, SCOPE);
+ t.add_cleanup(async () => {
+ if (reg)
+ await reg.unregister();
+ });
+
+ await wait_for_state(t, reg.installing, 'activated');
+
+ const frame = await with_iframe(SCOPE);
+ t.add_cleanup(async () => {
+ if (frame)
+ frame.remove();
+ });
+
+ // Trigger a fetch that 1) will go through the service worker and 2) will
+ // fetch a special URL that records request headers.
+ await frame.contentWindow.fetch(URL, {mode:'no-cors'});
+
+ // Retrieve the request headers that have been recorded in the previous step.
+ const response = await fetch(RETRIEVAL_URL);
+ const text = await response.text();
+
+ // Verify presence of the expected Sec-Fetch-... request headers.
+ let expected = {"dest":"empty", "site":"same-origin", "user":"", "mode": "no-cors"};
+ assert_header_equals(text, expected);
+ }, 'Sec-Fetch headers after SW fallback');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html
new file mode 100644
index 0000000..24f3b27
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/fetch-via-serviceworker--respondWith.tentative.https.sub.html
@@ -0,0 +1,51 @@
+<!DOCTYPE html>
+<!--
+ This test verifies presence of Sec-Fetch-... request headers on a request
+ handled by a service worker - this test covers the scenario when the service
+ worker responds to the `fetch` event with:
+ event.respondWith(fetch(event.request));
+-->
+<meta charset="utf-8"/>
+<link rel="author" href="lukasza@chromium.org" title="Lukasz Anforowicz">
+<script src=/resources/testharness.js></script>
+<script src=/resources/testharnessreport.js></script>
+<script src=/fetch/sec-metadata/resources/helper.js></script>
+<script src=/service-workers/service-worker/resources/test-helpers.sub.js></script>
+<script src=/common/utils.js></script>
+<script>
+ const nonce = token();
+ const key = "fetch-via-serviceworker--respondWith--" + nonce;
+
+ promise_test(async function(t) {
+ const SCOPE = 'resources/fetch-via-serviceworker--respondWith--frame.html';
+ const SCRIPT = 'resources/fetch-via-serviceworker--respondWith--sw.js';
+ const URL = '/fetch/sec-metadata/resources/record-header.py?file=' + key;
+ const RETRIEVAL_URL = "/fetch/sec-metadata/resources/record-header.py?retrieve=true&file=" + key;
+
+ const reg = await service_worker_unregister_and_register(t, SCRIPT, SCOPE);
+ t.add_cleanup(async () => {
+ if (reg)
+ await reg.unregister();
+ });
+
+ await wait_for_state(t, reg.installing, 'activated');
+
+ const frame = await with_iframe(SCOPE);
+ t.add_cleanup(async () => {
+ if (frame)
+ frame.remove();
+ });
+
+ // Trigger a fetch that 1) will go through the service worker and 2) will
+ // fetch a special URL that records request headers.
+ await frame.contentWindow.fetch(URL, {mode:'no-cors'});
+
+ // Retrieve the request headers that have been recorder in the previous step.
+ const response = await fetch(RETRIEVAL_URL);
+ const text = await response.text();
+
+ // Verify presence of the expected Sec-Fetch-... request headers.
+ let expected = {"dest":"empty", "site":"same-origin", "user":"", "mode": "no-cors"};
+ assert_header_equals(text, expected);
+ }, 'Sec-Fetch headers after SW fallback');
+</script>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--fallback--frame.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--fallback--frame.html
new file mode 100644
index 0000000..9879802
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--fallback--frame.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Page Title</title>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--fallback--sw.js b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--fallback--sw.js
new file mode 100644
index 0000000..09858b26
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--fallback--sw.js
@@ -0,0 +1,3 @@
+self.addEventListener('fetch', function(event) {
+ // Empty event handler - will fallback to the network.
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--respondWith--frame.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--respondWith--frame.html
new file mode 100644
index 0000000..9879802
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--respondWith--frame.html
@@ -0,0 +1,3 @@
+<!DOCTYPE html>
+<meta charset="utf-8">
+<title>Page Title</title>
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--respondWith--sw.js b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--respondWith--sw.js
new file mode 100644
index 0000000..8bf8d8f
--- /dev/null
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/resources/fetch-via-serviceworker--respondWith--sw.js
@@ -0,0 +1,3 @@
+self.addEventListener('fetch', function(event) {
+ event.respondWith(fetch(event.request));
+});
diff --git a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
index ee436d9..c86198d 100644
--- a/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
+++ b/third_party/blink/web_tests/external/wpt/fetch/sec-metadata/serviceworker.tentative.https.sub.html
@@ -1,4 +1,9 @@
<!DOCTYPE html>
+<!--
+ This test verifies presence of Sec-Fetch-... request headers on a request
+ that fetches the service worker script itself (i.e. the script at the URL
+ passed as an argument to navigator.serviceWorker.register).
+-->
<meta charset="utf-8"/>
<link rel="author" href="mtrzos@google.com" title="Maciek Trzos">
<script src=/resources/testharness.js></script>
diff --git a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
index 76e0835..44c6a05 100644
--- a/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
+++ b/third_party/blink/web_tests/external/wpt/service-workers/service-worker/fetch-request-xhr.https-expected.txt
@@ -1,9 +1,9 @@
This is a testharness.js-based test.
PASS initialize global state
-FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 6"
-FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 8"
-FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 6"
-FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 8"
+FAIL event.request has the expected headers for same-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin GET. lengths differ, expected 1 got 3"
+FAIL event.request has the expected headers for same-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for same-origin POST. lengths differ, expected 2 got 5"
+FAIL event.request has the expected headers for cross-origin GET. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin GET. lengths differ, expected 1 got 3"
+FAIL event.request has the expected headers for cross-origin POST. promise_test: Unhandled rejection with value: object "Error: assert_array_equals: event.request has the expected headers for cross-origin POST. lengths differ, expected 2 got 5"
PASS FetchEvent#request.body contains XHR request data (string)
PASS FetchEvent#request.body contains XHR request data (blob)
PASS FetchEvent#request.method is set to XHR method
diff --git a/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html b/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html
index e98cbba..76f86e9 100644
--- a/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html
+++ b/third_party/blink/web_tests/http/tests/serviceworker/fetch-event-headers.html
@@ -31,7 +31,7 @@
header_names.sort();
assert_array_equals(
header_names,
- ["accept", "sec-fetch-dest", "sec-fetch-mode", "sec-fetch-site", "upgrade-insecure-requests", "user-agent"],
+ ["accept", "upgrade-insecure-requests", "user-agent"],
'event.request has the expected headers.');
return service_worker_unregister_and_done(t, scope);