diff options
Diffstat (limited to 'dom/serviceworkers/test/download_canceled/server-stream-download.sjs')
-rw-r--r-- | dom/serviceworkers/test/download_canceled/server-stream-download.sjs | 133 |
1 files changed, 133 insertions, 0 deletions
diff --git a/dom/serviceworkers/test/download_canceled/server-stream-download.sjs b/dom/serviceworkers/test/download_canceled/server-stream-download.sjs new file mode 100644 index 0000000000..f47e872feb --- /dev/null +++ b/dom/serviceworkers/test/download_canceled/server-stream-download.sjs @@ -0,0 +1,133 @@ +/* Any copyright is dedicated to the Public Domain. + * http://creativecommons.org/publicdomain/zero/1.0/ */ + +const { setInterval, clearInterval } = ChromeUtils.importESModule( + "resource://gre/modules/Timer.sys.mjs" +); + +// stolen from file_blocked_script.sjs +function setGlobalState(data, key) { + x = { + data, + QueryInterface(iid) { + return this; + }, + }; + x.wrappedJSObject = x; + setObjectState(key, x); +} + +function getGlobalState(key) { + var data; + getObjectState(key, function (x) { + data = x && x.wrappedJSObject.data; + }); + return data; +} + +/* + * We want to let the sw_download_canceled.js service worker know when the + * stream was canceled. To this end, we let it issue a monitor request which we + * fulfill when the stream has been canceled. In order to coordinate between + * multiple requests, we use the getObjectState/setObjectState mechanism that + * httpd.js exposes to let data be shared and/or persist between requests. We + * handle both possible orderings of the requests because we currently don't + * try and impose an ordering between the two requests as issued by the SW, and + * file_blocked_script.sjs encourages us to do this, but we probably could order + * them. + */ +const MONITOR_KEY = "stream-monitor"; +function completeMonitorResponse(response, data) { + response.write(JSON.stringify(data)); + response.finish(); +} +function handleMonitorRequest(request, response) { + response.setHeader("Content-Type", "application/json"); + response.setStatusLine(request.httpVersion, 200, "Found"); + + response.processAsync(); + // Necessary to cause the headers to be flushed; that or touching the + // bodyOutputStream getter. + response.write(""); + dump("server-stream-download.js: monitor headers issued\n"); + + const alreadyCompleted = getGlobalState(MONITOR_KEY); + if (alreadyCompleted) { + completeMonitorResponse(response, alreadyCompleted); + setGlobalState(null, MONITOR_KEY); + } else { + setGlobalState(response, MONITOR_KEY); + } +} + +const MAX_TICK_COUNT = 3000; +const TICK_INTERVAL = 2; +function handleStreamRequest(request, response) { + const name = "server-stream-download"; + + // Create some payload to send. + let strChunk = + "Static routes are the future of ServiceWorkers! So say we all!\n"; + while (strChunk.length < 1024) { + strChunk += strChunk; + } + + response.setHeader("Content-Disposition", `attachment; filename="${name}"`); + response.setHeader( + "Content-Type", + `application/octet-stream; name="${name}"` + ); + response.setHeader("Content-Length", `${strChunk.length * MAX_TICK_COUNT}`); + response.setStatusLine(request.httpVersion, 200, "Found"); + + response.processAsync(); + response.write(strChunk); + dump("server-stream-download.js: stream headers + first payload issued\n"); + + let count = 0; + let intervalId; + function closeStream(why, message) { + dump("server-stream-download.js: closing stream: " + why + "\n"); + clearInterval(intervalId); + response.finish(); + + const data = { why, message }; + const monitorResponse = getGlobalState(MONITOR_KEY); + if (monitorResponse) { + completeMonitorResponse(monitorResponse, data); + setGlobalState(null, MONITOR_KEY); + } else { + setGlobalState(data, MONITOR_KEY); + } + } + function tick() { + try { + // bound worst-case behavior. + if (count++ > MAX_TICK_COUNT) { + closeStream("timeout", "timeout"); + return; + } + response.write(strChunk); + } catch (e) { + closeStream("canceled", e.message); + } + } + intervalId = setInterval(tick, TICK_INTERVAL); +} + +Components.utils.importGlobalProperties(["URLSearchParams"]); +function handleRequest(request, response) { + dump( + "server-stream-download.js: processing request for " + + request.path + + "?" + + request.queryString + + "\n" + ); + const query = new URLSearchParams(request.queryString); + if (query.has("monitor")) { + handleMonitorRequest(request, response); + } else { + handleStreamRequest(request, response); + } +} |