tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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 }