Skip to content

Commit dce6506

Browse files
jakearchibaldjgraham
authored andcommitted
Bug 1452562 [wpt PR 10348] - Allow range headers to pass through a service worker, a=testonly
Automatic update from web-platform-testsAllow range headers to pass through a service worker (#10348) Tests for whatwg/fetch#560 -- wpt-commits: fb6d16d92af29262b6137b79e61f0c4b136c6ac1 wpt-pr: 10348
1 parent 71986e7 commit dce6506

File tree

11 files changed

+592
-4
lines changed

11 files changed

+592
-4
lines changed

testing/web-platform/meta/MANIFEST.json

+89-1
Original file line numberDiff line numberDiff line change
@@ -273616,6 +273616,36 @@
273616273616
{}
273617273617
]
273618273618
],
273619+
"fetch/range/resources/basic.html": [
273620+
[
273621+
{}
273622+
]
273623+
],
273624+
"fetch/range/resources/long-wav.py": [
273625+
[
273626+
{}
273627+
]
273628+
],
273629+
"fetch/range/resources/partial-script.py": [
273630+
[
273631+
{}
273632+
]
273633+
],
273634+
"fetch/range/resources/range-sw.js": [
273635+
[
273636+
{}
273637+
]
273638+
],
273639+
"fetch/range/resources/stash-take.py": [
273640+
[
273641+
{}
273642+
]
273643+
],
273644+
"fetch/range/resources/utils.js": [
273645+
[
273646+
{}
273647+
]
273648+
],
273619273649
"fetch/sec-metadata/README.md": [
273620273650
[
273621273651
{}
@@ -330610,6 +330640,28 @@
330610330640
{}
330611330641
]
330612330642
],
330643+
"fetch/range/general.any.js": [
330644+
[
330645+
"/fetch/range/general.any.html",
330646+
{}
330647+
],
330648+
[
330649+
"/fetch/range/general.any.worker.html",
330650+
{}
330651+
]
330652+
],
330653+
"fetch/range/partial-script.window.js": [
330654+
[
330655+
"/fetch/range/partial-script.window.html",
330656+
{}
330657+
]
330658+
],
330659+
"fetch/range/sw.https.window.js": [
330660+
[
330661+
"/fetch/range/sw.https.window.html",
330662+
{}
330663+
]
330664+
],
330613330665
"fetch/sec-metadata/fetch.tentative.https.sub.html": [
330614330666
[
330615330667
"/fetch/sec-metadata/fetch.tentative.https.sub.html",
@@ -559765,6 +559817,42 @@
559765559817
"bb002c0d5d4d46f426462f776cff00cf600f5a4a",
559766559818
"support"
559767559819
],
559820+
"fetch/range/general.any.js": [
559821+
"2c16c0398373fca53ae80aae1107868c8cdeb6b4",
559822+
"testharness"
559823+
],
559824+
"fetch/range/partial-script.window.js": [
559825+
"1352080860b8671290919ab0d09cb41f4100763e",
559826+
"testharness"
559827+
],
559828+
"fetch/range/resources/basic.html": [
559829+
"51a23151c28992fe062b36914463de216bd55fbe",
559830+
"support"
559831+
],
559832+
"fetch/range/resources/long-wav.py": [
559833+
"a9bdaefeb4e9cefd4bb678832d7ffcbe1b3167f7",
559834+
"support"
559835+
],
559836+
"fetch/range/resources/partial-script.py": [
559837+
"d74bf301d56ad7d5ae4067e8e27ec544a21aa2ed",
559838+
"support"
559839+
],
559840+
"fetch/range/resources/range-sw.js": [
559841+
"1ec66e1dd8bf9a11b058b90e32ca7caab2233d4d",
559842+
"support"
559843+
],
559844+
"fetch/range/resources/stash-take.py": [
559845+
"9d29b6276fa690d6acb366bdb4d60a12bc57ea52",
559846+
"support"
559847+
],
559848+
"fetch/range/resources/utils.js": [
559849+
"81cc493a76265cc64408fc2d41a67434ec99391a",
559850+
"support"
559851+
],
559852+
"fetch/range/sw.https.window.js": [
559853+
"5bf1ebc9ce82990013831f2f7f55589e29a69bde",
559854+
"testharness"
559855+
],
559768559856
"fetch/sec-metadata/README.md": [
559769559857
"75d58b35c1e5572d02dd3ad90ac65301e35c4bc7",
559770559858
"support"
@@ -603486,7 +603574,7 @@
603486603574
"support"
603487603575
],
603488603576
"service-workers/service-worker/resources/test-helpers.sub.js": [
603489-
"74ea529125a5e2c5cd3d350f7c56ae614f82010d",
603577+
"079d31394903266dddb067f8f4dba5a94e522bdc",
603490603578
"support"
603491603579
],
603492603580
"service-workers/service-worker/resources/testharness-helpers.js": [
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Helpers that return headers objects with a particular guard
2+
function headersGuardNone(fill) {
3+
if (fill) return new Headers(fill);
4+
return new Headers();
5+
}
6+
7+
function headersGuardResponse(fill) {
8+
const opts = {};
9+
if (fill) opts.headers = fill;
10+
return new Response('', opts).headers;
11+
}
12+
13+
function headersGuardRequest(fill) {
14+
const opts = {};
15+
if (fill) opts.headers = fill;
16+
return new Request('./', opts).headers;
17+
}
18+
19+
function headersGuardRequestNoCors(fill) {
20+
const opts = { mode: 'no-cors' };
21+
if (fill) opts.headers = fill;
22+
return new Request('./', opts).headers;
23+
}
24+
25+
const headerGuardTypes = [
26+
['none', headersGuardNone],
27+
['response', headersGuardResponse],
28+
['request', headersGuardRequest]
29+
];
30+
31+
for (const [guardType, createHeaders] of headerGuardTypes) {
32+
test(() => {
33+
// There are three ways to set headers.
34+
// Filling, appending, and setting. Test each:
35+
let headers = createHeaders({ Range: 'foo' });
36+
assert_equals(headers.get('Range'), 'foo');
37+
38+
headers = createHeaders();
39+
headers.append('Range', 'foo');
40+
assert_equals(headers.get('Range'), 'foo');
41+
42+
headers = createHeaders();
43+
headers.set('Range', 'foo');
44+
assert_equals(headers.get('Range'), 'foo');
45+
}, `Range header setting allowed for guard type: ${guardType}`);
46+
}
47+
48+
test(() => {
49+
let headers = headersGuardRequestNoCors({ Range: 'foo' });
50+
assert_false(headers.has('Range'));
51+
52+
headers = headersGuardRequestNoCors();
53+
headers.append('Range', 'foo');
54+
assert_false(headers.has('Range'));
55+
56+
headers = headersGuardRequestNoCors();
57+
headers.set('Range', 'foo');
58+
assert_false(headers.has('Range'));
59+
}, `Privileged header not allowed for guard type: request-no-cors`);
60+
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
// META: script=resources/utils.js
2+
3+
// It's weird that browsers do this, but it should continue to work.
4+
promise_test(async t => {
5+
await loadScript('resources/partial-script.py?pretend-offset=90000');
6+
assert_true(self.scriptExecuted);
7+
}, `Script executed from partial response`);
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<!DOCTYPE html>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
"""
2+
This generates a 30 minute silent wav, and is capable of
3+
responding to Range requests.
4+
"""
5+
import time
6+
import re
7+
import struct
8+
9+
10+
def create_wav_header(sample_rate, bit_depth, channels, duration):
11+
bytes_per_sample = bit_depth / 8
12+
block_align = bytes_per_sample * channels
13+
byte_rate = sample_rate * block_align
14+
sub_chunk_2_size = duration * byte_rate
15+
16+
data = b''
17+
# ChunkID
18+
data += b'RIFF'
19+
# ChunkSize
20+
data += struct.pack('<L', 36 + sub_chunk_2_size)
21+
# Format
22+
data += b'WAVE'
23+
# Subchunk1ID
24+
data += b'fmt '
25+
# Subchunk1Size
26+
data += struct.pack('<L', 16)
27+
# AudioFormat
28+
data += struct.pack('<H', 1)
29+
# NumChannels
30+
data += struct.pack('<H', channels)
31+
# SampleRate
32+
data += struct.pack('<L', sample_rate)
33+
# ByteRate
34+
data += struct.pack('<L', byte_rate)
35+
# BlockAlign
36+
data += struct.pack('<H', block_align)
37+
# BitsPerSample
38+
data += struct.pack('<H', bit_depth)
39+
# Subchunk2ID
40+
data += b'data'
41+
# Subchunk2Size
42+
data += struct.pack('<L', sub_chunk_2_size)
43+
44+
return data
45+
46+
47+
def main(request, response):
48+
response.headers.set("Content-Type", "audio/wav")
49+
response.headers.set("Accept-Ranges", "bytes")
50+
response.headers.set("Cache-Control", "no-cache")
51+
52+
range_header = request.headers.get('Range', '')
53+
range_received_key = request.GET.first('range-received-key', '')
54+
55+
if range_received_key and range_header:
56+
# This is later collected using stash-take.py
57+
request.stash.put(range_received_key, 'range-header-received', '/fetch/range/')
58+
59+
# Audio details
60+
sample_rate = 8000
61+
bit_depth = 8
62+
channels = 1
63+
duration = 60 * 5
64+
65+
total_length = (sample_rate * bit_depth * channels * duration) / 8
66+
bytes_remaining_to_send = total_length
67+
initial_write = ''
68+
69+
if range_header:
70+
response.status = 206
71+
start, end = re.search(r'^bytes=(\d*)-(\d*)$', range_header).groups()
72+
73+
start = int(start)
74+
end = int(end) if end else 0
75+
76+
if end:
77+
bytes_remaining_to_send = (end + 1) - start
78+
else:
79+
bytes_remaining_to_send = total_length - start
80+
81+
wav_header = create_wav_header(sample_rate, bit_depth, channels, duration)
82+
83+
if start < len(wav_header):
84+
initial_write = wav_header[start:]
85+
86+
if bytes_remaining_to_send < len(initial_write):
87+
initial_write = initial_write[0:bytes_remaining_to_send]
88+
89+
content_range = "bytes {}-{}/{}".format(start, end or total_length - 1, total_length)
90+
91+
response.headers.set("Content-Range", content_range)
92+
else:
93+
initial_write = create_wav_header(sample_rate, bit_depth, channels, duration)
94+
95+
response.headers.set("Content-Length", bytes_remaining_to_send)
96+
97+
response.write_status_headers()
98+
response.writer.write(initial_write)
99+
100+
bytes_remaining_to_send -= len(initial_write)
101+
102+
while bytes_remaining_to_send > 0:
103+
if not response.writer.flush():
104+
break
105+
106+
to_send = b'\x00' * min(bytes_remaining_to_send, sample_rate)
107+
bytes_remaining_to_send -= len(to_send)
108+
109+
response.writer.write(to_send)
110+
# Throttle the stream
111+
time.sleep(0.5)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
"""
2+
This generates a partial response containing valid JavaScript.
3+
"""
4+
5+
6+
def main(request, response):
7+
require_range = request.GET.first('require-range', '')
8+
pretend_offset = int(request.GET.first('pretend-offset', '0'))
9+
range_header = request.headers.get('Range', '')
10+
11+
if require_range and not range_header:
12+
response.set_error(412, "Range header required")
13+
response.write()
14+
return
15+
16+
response.headers.set("Content-Type", "text/plain")
17+
response.headers.set("Accept-Ranges", "bytes")
18+
response.headers.set("Cache-Control", "no-cache")
19+
response.status = 206
20+
21+
to_send = 'self.scriptExecuted = true;'
22+
length = len(to_send)
23+
24+
content_range = "bytes {}-{}/{}".format(
25+
pretend_offset, pretend_offset + length - 1, pretend_offset + length)
26+
27+
response.headers.set("Content-Range", content_range)
28+
response.headers.set("Content-Length", length)
29+
30+
response.content = to_send

0 commit comments

Comments
 (0)