Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 22 additions & 10 deletions fetch/range/resources/partial-script.py
Original file line number Diff line number Diff line change
@@ -1,29 +1,41 @@
"""
This generates a partial response containing valid JavaScript.
This generates a partial response containing valid JavaScript or image data.
"""

def main(request, response):
require_range = request.GET.first(b'require-range', b'')
pretend_offset = int(request.GET.first(b'pretend-offset', b'0'))
range_not_satisfiable = request.GET.first(b'range-not-satisfiable', b'')
content_type = request.GET.first(b'type', b'text/plain')
range_header = request.headers.get(b'Range', b'')

if require_range and not range_header:
response.set_error(412, u"Range header required")
response.write()
return

response.headers.set(b"Content-Type", b"text/plain")
response.headers.set(b"Accept-Ranges", b"bytes")
response.headers.set(b"Cache-Control", b"no-cache")
response.status = 206
# 1x1 red PNG image (67 bytes)
png_data = b'\x89PNG\r\n\x1a\n\x00\x00\x00\rIHDR\x00\x00\x00\x01\x00\x00\x00\x01\x08\x02\x00\x00\x00\x90wS\xde\x00\x00\x00\x0cIDATx\x9cc\xf8\xcf\xc0\x00\x00\x00\x03\x00\x01\x00\x18\xdd\x8d\xb4\x00\x00\x00\x00IEND\xaeB`\x82'

to_send = b'self.scriptExecuted = true;'
length = len(to_send)
if content_type == b'image/png':
to_send = png_data
else:
to_send = b'self.scriptExecuted = true;'

content_range = b"bytes %d-%d/%d" % (
pretend_offset, pretend_offset + length - 1, pretend_offset + length)
length = len(to_send)

response.headers.set(b"Content-Range", content_range)
response.headers.set(b"Content-Type", content_type)
response.headers.set(b"Accept-Ranges", b"bytes")
response.headers.set(b"Cache-Control", b"no-cache")
response.headers.set(b"Content-Length", length)

if range_not_satisfiable:
response.status = 416
response.headers.set(b"Content-Range", b"bytes */%d" % (pretend_offset + length))
else:
response.status = 206
content_range = b"bytes %d-%d/%d" % (
pretend_offset, pretend_offset + length - 1, pretend_offset + length)
response.headers.set(b"Content-Range", content_range)

response.content = to_send
1 change: 0 additions & 1 deletion fetch/range/resources/range-sw.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,7 +144,6 @@ function storeRangedResponse(event) {
function useStoredRangeResponse(event) {
event.respondWith(async function() {
const response = await storedRangeResponseP;
if (!response) throw Error("Expected stored range response");
return response.clone();
}());
}
Expand Down
10 changes: 10 additions & 0 deletions fetch/range/resources/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,16 @@ function loadScript(url, { doc = document }={}) {
})
}

function loadImage(url, { doc = document }={}) {
return new Promise((resolve, reject) => {
const img = doc.createElement('img');
img.onload = () => resolve();
img.onerror = () => reject(Error("Image load failed"));
img.src = url;
doc.body.appendChild(img);
})
}

function preloadImage(url, { doc = document }={}) {
return new Promise((resolve, reject) => {
const preload = doc.createElement('link');
Expand Down
61 changes: 61 additions & 0 deletions fetch/range/sw-416.https.window.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// 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();
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);

const url = new URL('partial-script.py', w.location);
url.searchParams.set('require-range', '1');
url.searchParams.set('range-not-satisfiable', '1');
url.searchParams.set('type', 'image/png');
url.searchParams.set('action', 'store-ranged-response');
url.searchParams.set('id', id);
url.hostname = REMOTE_HOST;

appendAudio(w.document, url);

await storedRangeResponse;

const fetchPromise = w.fetch('?action=use-stored-ranged-response', { mode: 'no-cors' });
await promise_rejects_js(t, w.TypeError, fetchPromise);

const loadImagePromise = loadImage('?action=use-stored-ranged-response', { doc: w.document });
await promise_rejects_js(t, Error, loadImagePromise);
}, `416 response not allowed following no-cors ranged request`);
2 changes: 0 additions & 2 deletions fetch/range/sw.https.window.js
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,6 @@ promise_test(async t => {
const loadScriptPromise = loadScript('?action=use-stored-ranged-response', { doc: w.document });
await promise_rejects_js(t, Error, loadScriptPromise);

await loadScriptPromise.catch(() => {});

assert_false(!!w.scriptExecuted, `Partial response shouldn't be executed`);
}, `Ranged response not allowed following no-cors ranged request`);

Expand Down