Title: [232571] trunk
Revision
232571
Author
[email protected]
Date
2018-06-06 21:03:31 -0700 (Wed, 06 Jun 2018)

Log Message

Add Accept-Encoding: identity to Range requests
https://bugs.webkit.org/show_bug.cgi?id=186335
<rdar://problem/40837190>

Reviewed by Eric Carlson.

LayoutTests/imported/w3c:

* 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.

Source/WebCore:

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:

Modified Paths

Added Paths

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*);
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to