summaryrefslogtreecommitdiffstats
path: root/testing/mochitest/document-builder.sjs
blob: b8c9ef21e7e9a67b063c05ca73207007ecb2c409 (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
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

"use strict";

const { NetUtil } = ChromeUtils.import("resource://gre/modules/NetUtil.jsm");
Cu.importGlobalProperties(["URLSearchParams"]);

function loadHTMLFromFile(path) {
  // Load the HTML to return in the response from file.
  // Since it's relative to the cwd of the test runner, we start there and
  // append to get to the actual path of the file.
  const testHTMLFile =
    // eslint-disable-next-line mozilla/use-services
    Cc["@mozilla.org/file/directory_service;1"]
      .getService(Ci.nsIProperties)
      .get("CurWorkD", Ci.nsIFile);
  const dirs = path.split("/");
  for (let i = 0; i < dirs.length; i++) {
    testHTMLFile.append(dirs[i]);
  }

  const testHTMLFileStream = Cc[
    "@mozilla.org/network/file-input-stream;1"
  ].createInstance(Ci.nsIFileInputStream);
  testHTMLFileStream.init(testHTMLFile, -1, 0, 0);
  const testHTML = NetUtil.readInputStreamToString(
    testHTMLFileStream,
    testHTMLFileStream.available()
  );

  return testHTML;
}

/**
 * document-builder.sjs can be used to dynamically build documents that will be used in
 * mochitests. It does handle the following GET parameters:
 * - file: The path to an (X)HTML file whose content will be used as a response.
 *        Example: document-builder.sjs?file=/tests/dom/security/test/csp/file_web_manifest_mixed_content.html
 * - html: A string representation of the HTML document you want to get.
 *        Example: document-builder.sjs?html=<h1>Hello</h1>
 * - headers: A <key:value> string representation of headers that will be set on the response
 *            This is only applied when the html GET parameter is passed as well
 *        Example: document-builder.sjs?headers=Cross-Origin-Opener-Policy:same-origin&html=<h1>Hello</h1>
 *                 document-builder.sjs?headers=X-Header1:a&headers=X-Header2:b&html=<h1>Multiple headers</h1>
 * - delay: Delay the response by X millisecond.
 */
async function handleRequest(request, response) {
  response.processAsync();

  const queryString = new URLSearchParams(request.queryString);
  const html = queryString.get("html");
  const delay = queryString.get("delay");

  if (delay) {
    await new Promise(resolve => {
      let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
      timer.initWithCallback(
        () => {
          // to avoid garbage collection
          timer = null;
          resolve();
        },
        delay,
        Ci.nsITimer.TYPE_ONE_SHOT
      );
    });
  }

  response.setHeader("Cache-Control", "no-cache", false);
  if (html) {
    response.setHeader("Content-Type", "text/html", false);

    if (queryString.has("headers")) {
      for (const header of queryString.getAll("headers")) {
        const [key, value] = header.split(":");
        response.setHeader(key, value, false);
      }
    }

    response.write(html);
  } else {
    const path = queryString.get("file");
    const doc = loadHTMLFromFile(path);
    response.setHeader(
      "Content-Type",
      path.endsWith(".xhtml") ? "application/xhtml+xml" : "text/html",
      false
    );
    // This is a hack to set the correct id for the content document that is to be
    // loaded in the iframe.
    response.write(doc.replace(`id="body"`, `id="default-iframe-body-id"`));
  }

  response.finish();
}