summaryrefslogtreecommitdiffstats
path: root/docshell/test/mochitest/file_bug1747033.sjs
blob: 14401101b260f8a4c8b20f30c6811536b8c3f794 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
"use strict";

const BOUNDARY = "BOUNDARY";

// waitForPageShow should be false if this is for multipart/x-mixed-replace
// and it's not the last part, Gecko doesn't fire pageshow for those parts.
function documentString(waitForPageShow = true) {
  return `<html>
  <head>
    <script>
      let bc = new BroadcastChannel("bug1747033");
      bc.addEventListener("message", ({ data: { cmd, arg = undefined } }) => {
        switch (cmd) {
          case "load":
            location.href = arg;
            break;
          case "replaceState":
            history.replaceState({}, "Replaced state", arg);
            bc.postMessage({ "historyLength": history.length, "location": location.href });
            break;
          case "back":
            history.back();
            break;
          case "close":
            close();
            break;
          }
      });

      function reply() {
        bc.postMessage({ "historyLength": history.length, "location": location.href });
      }

      ${waitForPageShow ? `addEventListener("pageshow", reply);` : "reply();"}
    </script>
  </head>
  <body></body>
</html>
`;
}

function boundary(last = false) {
  let b = `--${BOUNDARY}`;
  if (last) {
    b += "--";
  }
  return b + "\n";
}

function sendMultipart(response, last = false) {
  setState("sendMore", "");

  response.write(`Content-Type: text/html

${documentString(last)}
`);
  response.write(boundary(last));
}

function shouldSendMore() {
  return new Promise(resolve => {
    let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
    timer.initWithCallback(
      () => {
        let sendMore = getState("sendMore");
        if (sendMore !== "") {
          timer.cancel();
          resolve(sendMore);
        }
      },
      100,
      Ci.nsITimer.TYPE_REPEATING_SLACK
    );
  });
}

async function handleRequest(request, response) {
  if (request.queryString == "") {
    // This is for non-multipart/x-mixed-replace loads.
    response.write(documentString());
    return;
  }

  if (request.queryString == "sendNextPart") {
    setState("sendMore", "next");
    return;
  }

  if (request.queryString == "sendLastPart") {
    setState("sendMore", "last");
    return;
  }

  response.processAsync();

  response.setHeader(
    "Content-Type",
    `multipart/x-mixed-replace; boundary=${BOUNDARY}`,
    false
  );
  response.setStatusLine(request.httpVersion, 200, "OK");

  response.write(boundary());
  sendMultipart(response);
  while ((await shouldSendMore("sendMore")) !== "last") {
    sendMultipart(response);
  }
  sendMultipart(response, true);
  response.finish();
}