Diff
Modified: trunk/LayoutTests/imported/w3c/ChangeLog (232570 => 232571)
--- trunk/LayoutTests/imported/w3c/ChangeLog 2018-06-07 03:14:03 UTC (rev 232570)
+++ trunk/LayoutTests/imported/w3c/ChangeLog 2018-06-07 04:03:31 UTC (rev 232571)
@@ -1,3 +1,28 @@
+2018-06-06 Youenn Fablet <[email protected]>
+
+ Add Accept-Encoding: identity to Range requests
+ https://bugs.webkit.org/show_bug.cgi?id=186335
+ <rdar://problem/40837190>
+
+ Reviewed by Eric Carlson.
+
+ * resources/import-expectations.json:
+ * web-platform-tests/fetch/range/general.any-expected.txt: Added.
+ * web-platform-tests/fetch/range/general.any.html: Added.
+ * web-platform-tests/fetch/range/general.any.js: Added.
+ * web-platform-tests/fetch/range/general.any.worker-expected.txt: Added.
+ * web-platform-tests/fetch/range/general.any.worker.html: Added.
+ * web-platform-tests/fetch/range/general.window.js: Added.
+ * web-platform-tests/fetch/range/resources/basic.html: Added.
+ * web-platform-tests/fetch/range/resources/long-wav.py: Added.
+ * web-platform-tests/fetch/range/resources/partial-script.py: Added.
+ * web-platform-tests/fetch/range/resources/range-sw.js: Added.
+ * web-platform-tests/fetch/range/resources/stash-take.py: Added.
+ * web-platform-tests/fetch/range/resources/utils.js: Added.
+ * web-platform-tests/fetch/range/resources/w3c-import.log: Added.
+ * web-platform-tests/fetch/range/sw.https.window.js: Added.
+ * web-platform-tests/fetch/range/w3c-import.log: Added.
+
2018-06-05 Youenn Fablet <[email protected]>
ServiceWorker registration should store any script fetched through importScripts
Modified: trunk/LayoutTests/imported/w3c/resources/import-expectations.json (232570 => 232571)
--- trunk/LayoutTests/imported/w3c/resources/import-expectations.json 2018-06-07 03:14:03 UTC (rev 232570)
+++ trunk/LayoutTests/imported/w3c/resources/import-expectations.json 2018-06-07 04:03:31 UTC (rev 232571)
@@ -144,6 +144,8 @@
"web-platform-tests/feature-policy/resources": "import",
"web-platform-tests/feature-policy/resources/": "import",
"web-platform-tests/fetch": "import",
+ "web-platform-tests/fetch/api": "import",
+ "web-platform-tests/fetch/range": "import",
"web-platform-tests/fullscreen": "skip",
"web-platform-tests/gamepad": "skip",
"web-platform-tests/generic-sensor": "skip",
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any-expected.txt (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any-expected.txt 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,7 @@
+
+PASS Range header setting allowed for guard type: none
+PASS Range header setting allowed for guard type: response
+PASS Range header setting allowed for guard type: request
+PASS Privileged header not allowed for guard type: request-no-cors
+PASS Fetch with range header will be sent with Accept-Encoding: identity
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.html (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.html 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1 @@
+<!-- This file is required for WebKit test infrastructure to run the templated test -->
\ No newline at end of file
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.js (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.js (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.js 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,90 @@
+// META: script=/common/utils.js
+
+// Helpers that return headers objects with a particular guard
+function headersGuardNone(fill) {
+ if (fill) return new Headers(fill);
+ return new Headers();
+}
+
+function headersGuardResponse(fill) {
+ const opts = {};
+ if (fill) opts.headers = fill;
+ return new Response('', opts).headers;
+}
+
+function headersGuardRequest(fill) {
+ const opts = {};
+ if (fill) opts.headers = fill;
+ return new Request('./', opts).headers;
+}
+
+function headersGuardRequestNoCors(fill) {
+ const opts = { mode: 'no-cors' };
+ if (fill) opts.headers = fill;
+ return new Request('./', opts).headers;
+}
+
+const headerGuardTypes = [
+ ['none', headersGuardNone],
+ ['response', headersGuardResponse],
+ ['request', headersGuardRequest]
+];
+
+for (const [guardType, createHeaders] of headerGuardTypes) {
+ test(() => {
+ // There are three ways to set headers.
+ // Filling, appending, and setting. Test each:
+ let headers = createHeaders({ Range: 'foo' });
+ assert_equals(headers.get('Range'), 'foo');
+
+ headers = createHeaders();
+ headers.append('Range', 'foo');
+ assert_equals(headers.get('Range'), 'foo');
+
+ headers = createHeaders();
+ headers.set('Range', 'foo');
+ assert_equals(headers.get('Range'), 'foo');
+ }, `Range header setting allowed for guard type: ${guardType}`);
+}
+
+test(() => {
+ let headers = headersGuardRequestNoCors({ Range: 'foo' });
+ assert_false(headers.has('Range'));
+
+ headers = headersGuardRequestNoCors();
+ headers.append('Range', 'foo');
+ assert_false(headers.has('Range'));
+
+ headers = headersGuardRequestNoCors();
+ headers.set('Range', 'foo');
+ assert_false(headers.has('Range'));
+}, `Privileged header not allowed for guard type: request-no-cors`);
+
+promise_test(async () => {
+ const wavURL = new URL('resources/long-wav.py', location);
+ const stashTakeURL = new URL('resources/stash-take.py', location);
+
+ function changeToken() {
+ const stashToken = token();
+ wavURL.searchParams.set('accept-encoding-key', stashToken);
+ stashTakeURL.searchParams.set('key', stashToken);
+ }
+
+ const rangeHeaders = [
+ 'bytes=0-10',
+ 'foo=0-10',
+ 'foo',
+ ''
+ ];
+
+ for (const rangeHeader of rangeHeaders) {
+ changeToken();
+
+ await fetch(wavURL, {
+ headers: { Range: rangeHeader }
+ });
+
+ const response = await fetch(stashTakeURL);
+ assert_equals(await response.json(), 'identity', `Expect identity accept-encoding if range header is ${JSON.stringify(rangeHeader)}`);
+ }
+}, `Fetch with range header will be sent with Accept-Encoding: identity`);
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.worker-expected.txt (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.worker-expected.txt (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.worker-expected.txt 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,7 @@
+
+PASS Range header setting allowed for guard type: none
+PASS Range header setting allowed for guard type: response
+PASS Range header setting allowed for guard type: request
+PASS Privileged header not allowed for guard type: request-no-cors
+PASS Fetch with range header will be sent with Accept-Encoding: identity
+
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.worker.html (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.worker.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.worker.html 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1 @@
+<!-- This file is required for WebKit test infrastructure to run the templated test -->
\ No newline at end of file
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.window.js (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.window.js (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.window.js 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,29 @@
+// META: script=resources/utils.js
+// META: script=/common/utils.js
+
+const _onload_ = new Promise(r => window.addEventListener('load', r));
+
+// It's weird that browsers do this, but it should continue to work.
+promise_test(async t => {
+ await loadScript('resources/partial-script.py?pretend-offset=90000');
+ assert_true(self.scriptExecuted);
+}, `Script executed from partial response`);
+
+promise_test(async () => {
+ const wavURL = new URL('resources/long-wav.py', location);
+ const stashTakeURL = new URL('resources/stash-take.py', location);
+ const stashToken = token();
+ wavURL.searchParams.set('accept-encoding-key', stashToken);
+ stashTakeURL.searchParams.set('key', stashToken);
+
+ // The testing framework waits for window onload. If the audio element
+ // is appended before onload, it extends it, and the test times out.
+ await onload;
+
+ const audio = appendAudio(document, wavURL);
+ await new Promise(r => audio.addEventListener('progress', r));
+ audio.remove();
+
+ const response = await fetch(stashTakeURL);
+ assert_equals(await response.json(), 'identity', `Expect identity accept-encoding on media request`);
+}, `Fetch with range header will be sent with Accept-Encoding: identity`);
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/basic.html (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/basic.html (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/basic.html 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1 @@
+<!DOCTYPE html>
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/long-wav.py (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/long-wav.py (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/long-wav.py 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,128 @@
+"""
+This generates a 30 minute silent wav, and is capable of
+responding to Range requests.
+"""
+import time
+import re
+import struct
+
+
+def create_wav_header(sample_rate, bit_depth, channels, duration):
+ bytes_per_sample = bit_depth / 8
+ block_align = bytes_per_sample * channels
+ byte_rate = sample_rate * block_align
+ sub_chunk_2_size = duration * byte_rate
+
+ data = ""
+ # ChunkID
+ data += b'RIFF'
+ # ChunkSize
+ data += struct.pack('<L', 36 + sub_chunk_2_size)
+ # Format
+ data += b'WAVE'
+ # Subchunk1ID
+ data += b'fmt '
+ # Subchunk1Size
+ data += struct.pack('<L', 16)
+ # AudioFormat
+ data += struct.pack('<H', 1)
+ # NumChannels
+ data += struct.pack('<H', channels)
+ # SampleRate
+ data += struct.pack('<L', sample_rate)
+ # ByteRate
+ data += struct.pack('<L', byte_rate)
+ # BlockAlign
+ data += struct.pack('<H', block_align)
+ # BitsPerSample
+ data += struct.pack('<H', bit_depth)
+ # Subchunk2ID
+ data += b'data'
+ # Subchunk2Size
+ data += struct.pack('<L', sub_chunk_2_size)
+
+ return data
+
+
+def main(request, response):
+ response.headers.set("Content-Type", "audio/wav")
+ response.headers.set("Accept-Ranges", "bytes")
+ response.headers.set("Cache-Control", "no-cache")
+
+ range_header = request.headers.get('Range', '')
+ range_header_match = range_header and re.search(r'^bytes=(\d*)-(\d*)$', range_header)
+ range_received_key = request.GET.first('range-received-key', '')
+ accept_encoding_key = request.GET.first('accept-encoding-key', '')
+
+ if range_received_key and range_header:
+ # Remove any current value
+ request.server.stash.take(range_received_key, '/fetch/range/')
+ # This is later collected using stash-take.py
+ request.server.stash.put(range_received_key, 'range-header-received', '/fetch/range/')
+
+ if accept_encoding_key:
+ # Remove any current value
+ request.server.stash.take(
+ accept_encoding_key,
+ '/fetch/range/'
+ )
+ # This is later collected using stash-take.py
+ request.server.stash.put(
+ accept_encoding_key,
+ request.headers.get('Accept-Encoding', ''),
+ '/fetch/range/'
+ )
+
+ # Audio details
+ sample_rate = 8000
+ bit_depth = 8
+ channels = 1
+ duration = 60 * 5
+
+ total_length = (sample_rate * bit_depth * channels * duration) / 8
+ bytes_remaining_to_send = total_length
+ initial_write = ''
+
+ if range_header_match:
+ response.status = 206
+ start, end = range_header_match.groups()
+
+ start = int(start)
+ end = int(end) if end else 0
+
+ if end:
+ bytes_remaining_to_send = (end + 1) - start
+ else:
+ bytes_remaining_to_send = total_length - start
+
+ wav_header = create_wav_header(sample_rate, bit_depth, channels, duration)
+
+ if start < len(wav_header):
+ initial_write = wav_header[start:]
+
+ if bytes_remaining_to_send < len(initial_write):
+ initial_write = initial_write[0:bytes_remaining_to_send]
+
+ content_range = "bytes {}-{}/{}".format(start, end or total_length - 1, total_length)
+
+ response.headers.set("Content-Range", content_range)
+ else:
+ initial_write = create_wav_header(sample_rate, bit_depth, channels, duration)
+
+ response.headers.set("Content-Length", bytes_remaining_to_send)
+
+ response.write_status_headers()
+ response.writer.write(initial_write)
+
+ bytes_remaining_to_send -= len(initial_write)
+
+ while bytes_remaining_to_send > 0:
+ if not response.writer.flush():
+ break
+
+ to_send = b'\x00' * min(bytes_remaining_to_send, sample_rate)
+ bytes_remaining_to_send -= len(to_send)
+
+ response.writer.write(to_send)
+ # Throttle the stream
+ time.sleep(0.5)
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/partial-script.py (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/partial-script.py (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/partial-script.py 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,30 @@
+"""
+This generates a partial response containing valid _javascript_.
+"""
+
+
+def main(request, response):
+ require_range = request.GET.first('require-range', '')
+ pretend_offset = int(request.GET.first('pretend-offset', '0'))
+ range_header = request.headers.get('Range', '')
+
+ if require_range and not range_header:
+ response.set_error(412, "Range header required")
+ response.write()
+ return
+
+ response.headers.set("Content-Type", "text/plain")
+ response.headers.set("Accept-Ranges", "bytes")
+ response.headers.set("Cache-Control", "no-cache")
+ response.status = 206
+
+ to_send = 'self.scriptExecuted = true;'
+ length = len(to_send)
+
+ content_range = "bytes {}-{}/{}".format(
+ pretend_offset, pretend_offset + length - 1, pretend_offset + length)
+
+ response.headers.set("Content-Range", content_range)
+ response.headers.set("Content-Length", length)
+
+ response.content = to_send
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/range-sw.js (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/range-sw.js (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/range-sw.js 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,159 @@
+importScripts('/resources/testharness.js');
+
+setup({ explicit_done: true });
+
+function assert_range_request(request, expectedRangeHeader, name) {
+ assert_equals(request.headers.get('Range'), expectedRangeHeader, name);
+}
+
+async function broadcast(msg) {
+ for (const client of await clients.matchAll()) {
+ client.postMessage(msg);
+ }
+}
+
+addEventListener('fetch', event => {
+ /** @type Request */
+ const request = event.request;
+ const url = "" URL(request.url);
+ const action = ""
+
+ switch (action) {
+ case 'range-header-filter-test':
+ rangeHeaderFilterTest(request);
+ return;
+ case 'range-header-passthrough-test':
+ rangeHeaderPassthroughTest(event);
+ return;
+ case 'store-ranged-response':
+ storeRangedResponse(event);
+ return;
+ case 'use-stored-ranged-response':
+ useStoredRangeResponse(event);
+ return;
+ case 'broadcast-accept-encoding':
+ broadcastAcceptEncoding(event);
+ return;
+ }
+});
+
+/**
+ * @param {Request} request
+ */
+function rangeHeaderFilterTest(request) {
+ const rangeValue = request.headers.get('Range');
+
+ test(() => {
+ assert_range_request(new Request(request), rangeValue, `Untampered`);
+ assert_range_request(new Request(request, {}), rangeValue, `Untampered (no init props set)`);
+ assert_range_request(new Request(request, { __foo: 'bar' }), rangeValue, `Untampered (only invalid props set)`);
+ assert_range_request(new Request(request, { mode: 'cors' }), rangeValue, `More permissive mode`);
+ assert_range_request(request.clone(), rangeValue, `Clone`);
+ }, "Range headers correctly preserved");
+
+ test(() => {
+ assert_range_request(new Request(request, { headers: { Range: 'foo' } }), null, `Tampered - range header set`);
+ assert_range_request(new Request(request, { headers: {} }), null, `Tampered - empty headers set`);
+ assert_range_request(new Request(request, { mode: 'no-cors' }), null, `Tampered – mode set`);
+ assert_range_request(new Request(request, { cache: 'no-cache' }), null, `Tampered – cache mode set`);
+ }, "Range headers correctly removed");
+
+ test(() => {
+ let headers;
+
+ headers = new Request(request).headers;
+ headers.delete('does-not-exist');
+ assert_equals(headers.get('Range'), rangeValue, `Preserved if no header actually removed`);
+
+ headers = new Request(request).headers;
+ headers.append('foo', 'bar');
+ assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on append (due to request-no-cors guard)`);
+
+ headers = new Request(request).headers;
+ headers.set('foo', 'bar');
+ assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on set (due to request-no-cors guard)`);
+
+ headers = new Request(request).headers;
+ headers.append('Range', 'foo');
+ assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on append (due to request-no-cors guard)`);
+
+ headers = new Request(request).headers;
+ headers.set('Range', 'foo');
+ assert_equals(headers.get('Range'), rangeValue, `Preserved if silent-failure on set (due to request-no-cors guard)`);
+
+ headers = new Request(request).headers;
+ headers.append('Accept', 'whatever');
+ assert_equals(headers.get('Range'), null, `Stripped if header successfully appended`);
+
+ headers = new Request(request).headers;
+ headers.set('Accept', 'whatever');
+ assert_equals(headers.get('Range'), null, `Stripped if header successfully set`);
+
+ headers = new Request(request).headers;
+ headers.delete('Accept');
+ assert_equals(headers.get('Range'), null, `Stripped if header successfully deleted`);
+
+ headers = new Request(request).headers;
+ headers.delete('Range');
+ assert_equals(headers.get('Range'), null, `Stripped if range header successfully deleted`);
+ }, "Headers correctly filtered");
+
+ done();
+}
+
+function rangeHeaderPassthroughTest(event) {
+ /** @type Request */
+ const request = event.request;
+ const url = "" URL(request.url);
+ const key = url.searchParams.get('range-received-key');
+
+ event.waitUntil(new Promise(resolve => {
+ promise_test(async () => {
+ await fetch(event.request);
+ const response = await fetch('stash-take.py?key=' + key);
+ assert_equals(await response.json(), 'range-header-received');
+ resolve();
+ }, `Include range header in network request`);
+
+ done();
+ }));
+
+ // Just send back any response, it isn't important for the test.
+ event.respondWith(new Response(''));
+}
+
+let storedRangeResponseP;
+
+function storeRangedResponse(event) {
+ /** @type Request */
+ const request = event.request;
+ const id = new URL(request.url).searchParams.get('id');
+
+ storedRangeResponseP = fetch(event.request);
+ broadcast({ id });
+
+ // Just send back any response, it isn't important for the test.
+ event.respondWith(new Response(''));
+}
+
+function useStoredRangeResponse(event) {
+ event.respondWith(async function() {
+ const response = await storedRangeResponseP;
+ if (!response) throw Error("Expected stored range response");
+ return response.clone();
+ }());
+}
+
+function broadcastAcceptEncoding(event) {
+ /** @type Request */
+ const request = event.request;
+ const id = new URL(request.url).searchParams.get('id');
+
+ broadcast({
+ id,
+ acceptEncoding: request.headers.get('Accept-Encoding')
+ });
+
+ // Just send back any response, it isn't important for the test.
+ event.respondWith(new Response(''));
+}
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/stash-take.py (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/stash-take.py (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/stash-take.py 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,7 @@
+from wptserve.handlers import json_handler
+
+
+@json_handler
+def main(request, response):
+ key = request.GET.first("key")
+ return request.server.stash.take(key, '/fetch/range/')
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/utils.js (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/utils.js (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/utils.js 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,24 @@
+function loadScript(url, { doc = document }={}) {
+ return new Promise((resolve, reject) => {
+ const script = doc.createElement('script');
+ script._onload_ = () => resolve();
+ script._onerror_ = () => reject(Error("Script load failed"));
+ script.src = ""
+ doc.body.appendChild(script);
+ })
+}
+
+/**
+ *
+ * @param {Document} document
+ * @param {string|URL} url
+ * @returns {HTMLAudioElement}
+ */
+function appendAudio(document, url) {
+ const audio = document.createElement('audio');
+ audio.muted = true;
+ audio.src = ""
+ audio.preload = true;
+ document.body.appendChild(audio);
+ return audio;
+}
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/w3c-import.log (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/w3c-import.log (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/w3c-import.log 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,22 @@
+The tests in this directory were imported from the W3C repository.
+Do NOT modify these tests directly in WebKit.
+Instead, create a pull request on the WPT github:
+ https://github.com/w3c/web-platform-tests
+
+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport
+
+Do NOT modify or remove this file.
+
+------------------------------------------------------------------------
+Properties requiring vendor prefixes:
+None
+Property values requiring vendor prefixes:
+None
+------------------------------------------------------------------------
+List of files:
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/basic.html
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/long-wav.py
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/partial-script.py
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/range-sw.js
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/stash-take.py
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/resources/utils.js
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/sw.https.window.js (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/sw.https.window.js (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/sw.https.window.js 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,151 @@
+// META: script=../../../service-workers/service-worker/resources/test-helpers.sub.js
+// META: script=/common/utils.js
+// META: script=/common/get-host-info.sub.js
+// META: script=resources/utils.js
+
+const { REMOTE_HOST } = get_host_info();
+const BASE_SCOPE = 'resources/basic.html?';
+
+async function cleanup() {
+ for (const iframe of document.querySelectorAll('.test-iframe')) {
+ iframe.parentNode.removeChild(iframe);
+ }
+
+ for (const reg of await navigator.serviceWorker.getRegistrations()) {
+ await reg.unregister();
+ }
+}
+
+async function setupRegistration(t, scope) {
+ await cleanup();
+ const reg = await navigator.serviceWorker.register('resources/range-sw.js', { scope });
+ await wait_for_state(t, reg.installing, 'activated');
+ return reg;
+}
+
+function awaitMessage(obj, id) {
+ return new Promise(resolve => {
+ obj.addEventListener('message', function listener(event) {
+ if (event.data.id !== id) return;
+ obj.removeEventListener('message', listener);
+ resolve(event.data);
+ });
+ });
+}
+
+promise_test(async t => {
+ const scope = BASE_SCOPE + Math.random();
+ const reg = await setupRegistration(t, scope);
+ const iframe = await with_iframe(scope);
+ const w = iframe.contentWindow;
+
+ // Trigger a cross-origin range request using media
+ const url = "" URL('long-wav.py?action="" w.location);
+ url.hostname = REMOTE_HOST;
+ appendAudio(w.document, url);
+
+ // See rangeHeaderFilterTest in resources/range-sw.js
+ await fetch_tests_from_worker(reg.active);
+}, `Defer range header filter tests to service worker`);
+
+promise_test(async t => {
+ const scope = BASE_SCOPE + Math.random();
+ const reg = await setupRegistration(t, scope);
+ const iframe = await with_iframe(scope);
+ const w = iframe.contentWindow;
+
+ // Trigger a cross-origin range request using media
+ const url = "" URL('long-wav.py', w.location);
+ url.searchParams.set('action', 'range-header-passthrough-test');
+ url.searchParams.set('range-received-key', token());
+ url.hostname = REMOTE_HOST;
+ appendAudio(w.document, url);
+
+ // See rangeHeaderPassthroughTest in resources/range-sw.js
+ await fetch_tests_from_worker(reg.active);
+}, `Defer range header passthrough tests to service worker`);
+
+promise_test(async t => {
+ const scope = BASE_SCOPE + Math.random();
+ await setupRegistration(t, scope);
+ const iframe = await with_iframe(scope);
+ const w = iframe.contentWindow;
+ const id = Math.random() + '';
+ const storedRangeResponse = awaitMessage(w.navigator.serviceWorker, id);
+
+ // Trigger a cross-origin range request using media
+ const url = "" URL('partial-script.py', w.location);
+ url.searchParams.set('require-range', '1');
+ url.searchParams.set('action', 'store-ranged-response');
+ url.searchParams.set('id', id);
+ url.hostname = REMOTE_HOST;
+
+ appendAudio(w.document, url);
+
+ await storedRangeResponse;
+
+ // Fetching should reject
+ const fetchPromise = w.fetch('?action="" { mode: 'no-cors' });
+ promise_rejects(t, new TypeError(), fetchPromise);
+
+ // Script loading should error too
+ const loadScriptPromise = loadScript('?action="" { doc: w.document });
+ promise_rejects(t, new Error(), loadScriptPromise);
+
+ await loadScriptPromise.catch(() => {});
+
+ assert_false(!!w.scriptExecuted, `Partial response shouldn't be executed`);
+}, `Ranged response not allowed following no-cors ranged request`);
+
+promise_test(async t => {
+ const scope = BASE_SCOPE + Math.random();
+ await setupRegistration(t, scope);
+ const iframe = await with_iframe(scope);
+ const w = iframe.contentWindow;
+ const id = Math.random() + '';
+ const storedRangeResponse = awaitMessage(w.navigator.serviceWorker, id);
+
+ // Trigger a range request using media
+ const url = "" URL('partial-script.py', w.location);
+ url.searchParams.set('require-range', '1');
+ url.searchParams.set('action', 'store-ranged-response');
+ url.searchParams.set('id', id);
+
+ appendAudio(w.document, url);
+
+ await storedRangeResponse;
+
+ // This should not throw
+ await w.fetch('?action=""
+
+ // This shouldn't throw either
+ await loadScript('?action="" { doc: w.document });
+
+ assert_true(w.scriptExecuted, `Partial response should be executed`);
+}, `Non-opaque ranged response executed`);
+
+promise_test(async t => {
+ const scope = BASE_SCOPE + Math.random();
+ await setupRegistration(t, scope);
+ const iframe = await with_iframe(scope);
+ const w = iframe.contentWindow;
+ const fetchId = Math.random() + '';
+ const fetchBroadcast = awaitMessage(w.navigator.serviceWorker, fetchId);
+ const audioId = Math.random() + '';
+ const audioBroadcast = awaitMessage(w.navigator.serviceWorker, audioId);
+
+ const url = "" URL('long-wav.py', w.location);
+ url.searchParams.set('action', 'broadcast-accept-encoding');
+ url.searchParams.set('id', fetchId);
+
+ await w.fetch(url, {
+ headers: { Range: 'bytes=0-10' }
+ });
+
+ assert_equals((await fetchBroadcast).acceptEncoding, null, "Accept-Encoding should not be set for fetch");
+
+ url.searchParams.set('id', audioId);
+ appendAudio(w.document, url);
+
+ assert_equals((await audioBroadcast).acceptEncoding, null, "Accept-Encoding should not be set for media");
+}, `Accept-Encoding should not appear in a service worker`);
Added: trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/w3c-import.log (0 => 232571)
--- trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/w3c-import.log (rev 0)
+++ trunk/LayoutTests/imported/w3c/web-platform-tests/fetch/range/w3c-import.log 2018-06-07 04:03:31 UTC (rev 232571)
@@ -0,0 +1,19 @@
+The tests in this directory were imported from the W3C repository.
+Do NOT modify these tests directly in WebKit.
+Instead, create a pull request on the WPT github:
+ https://github.com/w3c/web-platform-tests
+
+Then run the Tools/Scripts/import-w3c-tests in WebKit to reimport
+
+Do NOT modify or remove this file.
+
+------------------------------------------------------------------------
+Properties requiring vendor prefixes:
+None
+Property values requiring vendor prefixes:
+None
+------------------------------------------------------------------------
+List of files:
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.any.js
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/general.window.js
+/LayoutTests/imported/w3c/web-platform-tests/fetch/range/sw.https.window.js
Modified: trunk/Source/WebCore/ChangeLog (232570 => 232571)
--- trunk/Source/WebCore/ChangeLog 2018-06-07 03:14:03 UTC (rev 232570)
+++ trunk/Source/WebCore/ChangeLog 2018-06-07 04:03:31 UTC (rev 232571)
@@ -1,3 +1,20 @@
+2018-06-06 Youenn Fablet <[email protected]>
+
+ Add Accept-Encoding: identity to Range requests
+ https://bugs.webkit.org/show_bug.cgi?id=186335
+ <rdar://problem/40837190>
+
+ Reviewed by Eric Carlson.
+
+ Tests: imported/w3c/web-platform-tests/fetch/range/general.any.html
+ imported/w3c/web-platform-tests/fetch/range/general.any.worker.html
+
+ * loader/cache/CachedResourceLoader.cpp:
+ (WebCore::CachedResourceLoader::updateHTTPRequestHeaders):
+ * loader/cache/CachedResourceRequest.cpp:
+ (WebCore::CachedResourceRequest::updateAcceptEncodingHeader):
+ * loader/cache/CachedResourceRequest.h:
+
2018-06-06 Per Arne Vollan <[email protected]>
Display links are sometimes not notifying WebCore when fired.
Modified: trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp (232570 => 232571)
--- trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp 2018-06-07 03:14:03 UTC (rev 232570)
+++ trunk/Source/WebCore/loader/cache/CachedResourceLoader.cpp 2018-06-07 04:03:31 UTC (rev 232571)
@@ -727,6 +727,7 @@
}
request.updateAccordingCacheMode();
+ request.updateAcceptEncodingHeader();
}
static FetchOptions::Destination destinationForType(CachedResource::Type type)
Modified: trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp (232570 => 232571)
--- trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp 2018-06-07 03:14:03 UTC (rev 232570)
+++ trunk/Source/WebCore/loader/cache/CachedResourceRequest.cpp 2018-06-07 04:03:31 UTC (rev 232571)
@@ -206,6 +206,17 @@
}
}
+void CachedResourceRequest::updateAcceptEncodingHeader()
+{
+ if (!m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::Range))
+ return;
+
+ // FIXME: rdar://problem/40879225. Media engines triggering the load should not set this Accept-Encoding header.
+ ASSERT(!m_resourceRequest.hasHTTPHeaderField(HTTPHeaderName::AcceptEncoding) || m_options.destination == FetchOptions::Destination::Audio || m_options.destination == FetchOptions::Destination::Video);
+
+ m_resourceRequest.addHTTPHeaderFieldIfNotPresent(HTTPHeaderName::AcceptEncoding, ASCIILiteral("identity"));
+}
+
void CachedResourceRequest::removeFragmentIdentifierIfNeeded()
{
URL url = ""
Modified: trunk/Source/WebCore/loader/cache/CachedResourceRequest.h (232570 => 232571)
--- trunk/Source/WebCore/loader/cache/CachedResourceRequest.h 2018-06-07 03:14:03 UTC (rev 232570)
+++ trunk/Source/WebCore/loader/cache/CachedResourceRequest.h 2018-06-07 04:03:31 UTC (rev 232571)
@@ -80,6 +80,8 @@
void upgradeInsecureRequestIfNeeded(Document&);
void setAcceptHeaderIfNone(CachedResource::Type);
void updateAccordingCacheMode();
+ void updateAcceptEncodingHeader();
+
void removeFragmentIdentifierIfNeeded();
#if ENABLE(CONTENT_EXTENSIONS)
void applyBlockedStatus(const ContentExtensions::BlockedStatus&, Page*);