file_bug1747033.sjs (2618B)
1 "use strict"; 2 3 const BOUNDARY = "BOUNDARY"; 4 5 // waitForPageShow should be false if this is for multipart/x-mixed-replace 6 // and it's not the last part, Gecko doesn't fire pageshow for those parts. 7 function documentString(waitForPageShow = true) { 8 return `<html> 9 <head> 10 <script> 11 let bc = new BroadcastChannel("bug1747033"); 12 bc.addEventListener("message", ({ data: { cmd, arg = undefined } }) => { 13 switch (cmd) { 14 case "load": 15 location.href = arg; 16 break; 17 case "replaceState": 18 history.replaceState({}, "Replaced state", arg); 19 bc.postMessage({ "historyLength": history.length, "location": location.href }); 20 break; 21 case "back": 22 history.back(); 23 break; 24 case "close": 25 close(); 26 break; 27 } 28 }); 29 30 function reply() { 31 bc.postMessage({ "historyLength": history.length, "location": location.href }); 32 } 33 34 ${waitForPageShow ? `addEventListener("pageshow", reply);` : "reply();"} 35 </script> 36 </head> 37 <body></body> 38 </html> 39 `; 40 } 41 42 function boundary(last = false) { 43 let b = `--${BOUNDARY}`; 44 if (last) { 45 b += "--"; 46 } 47 return b + "\n"; 48 } 49 50 function sendMultipart(response, last = false) { 51 setState("sendMore", ""); 52 53 response.write(`Content-Type: text/html 54 55 ${documentString(last)} 56 `); 57 response.write(boundary(last)); 58 } 59 60 function shouldSendMore() { 61 return new Promise(resolve => { 62 let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer); 63 timer.initWithCallback( 64 () => { 65 let sendMore = getState("sendMore"); 66 if (sendMore !== "") { 67 timer.cancel(); 68 resolve(sendMore); 69 } 70 }, 71 100, 72 Ci.nsITimer.TYPE_REPEATING_SLACK 73 ); 74 }); 75 } 76 77 async function handleRequest(request, response) { 78 if (request.queryString == "") { 79 // This is for non-multipart/x-mixed-replace loads. 80 response.write(documentString()); 81 return; 82 } 83 84 if (request.queryString == "sendNextPart") { 85 setState("sendMore", "next"); 86 return; 87 } 88 89 if (request.queryString == "sendLastPart") { 90 setState("sendMore", "last"); 91 return; 92 } 93 94 response.processAsync(); 95 96 response.setHeader( 97 "Content-Type", 98 `multipart/x-mixed-replace; boundary=${BOUNDARY}`, 99 false 100 ); 101 response.setStatusLine(request.httpVersion, 200, "OK"); 102 103 response.write(boundary()); 104 sendMultipart(response); 105 while ((await shouldSendMore("sendMore")) !== "last") { 106 sendMultipart(response); 107 } 108 sendMultipart(response, true); 109 response.finish(); 110 }