tor-browser

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

test_Fetch.js (11080B)


      1 /* Any copyright is dedicated to the Public Domain.
      2   http://creativecommons.org/publicdomain/zero/1.0/ */
      3 
      4 const { HttpServer } = ChromeUtils.importESModule(
      5  "resource://testing-common/httpd.sys.mjs"
      6 );
      7 
      8 const BinaryInputStream = Components.Constructor(
      9  "@mozilla.org/binaryinputstream;1",
     10  "nsIBinaryInputStream",
     11  "setInputStream"
     12 );
     13 
     14 var server;
     15 
     16 function getBaseUrl() {
     17  return "http://localhost:" + server.identity.primaryPort;
     18 }
     19 
     20 // a way to create some test defaults
     21 function createTestData(testPath) {
     22  return {
     23    testPath,
     24    request: {
     25      headers: {},
     26      contentType: "application/json",
     27    },
     28    response: {
     29      headers: {},
     30      contentType: "application/json",
     31      body: '{"Look": "Success!"}',
     32      status: 200,
     33      statusText: "OK",
     34    },
     35  };
     36 }
     37 
     38 // read body and content type information from a request
     39 function readDataFromRequest(aRequest) {
     40  let requestData = {};
     41  if (aRequest.method == "POST" || aRequest.method == "PUT") {
     42    if (aRequest.bodyInputStream) {
     43      let inputStream = new BinaryInputStream(aRequest.bodyInputStream);
     44      let bytes = [];
     45      let available;
     46 
     47      while ((available = inputStream.available()) > 0) {
     48        Array.prototype.push.apply(bytes, inputStream.readByteArray(available));
     49      }
     50 
     51      requestData.body = String.fromCharCode.apply(null, bytes);
     52      requestData.contentType = aRequest.getHeader("Content-Type");
     53    }
     54  }
     55  return requestData;
     56 }
     57 
     58 // write status information, content type information and body to a response
     59 function writeDataToResponse(aData, aResponse) {
     60  aResponse.setStatusLine(null, aData.status, aData.statusText);
     61  aResponse.setHeader("Content-Type", aData.contentType);
     62  for (let header in aData.headers) {
     63    aResponse.setHeader(header, aData.headers[header]);
     64  }
     65  aResponse.write(aData.body);
     66 }
     67 
     68 // test some GET functionality
     69 add_test(function test_GetData() {
     70  do_test_pending();
     71 
     72  let testData = createTestData("/getData");
     73 
     74  // set up some headers to test
     75  let headerNames = ["x-test-header", "x-other-test-header"];
     76  for (let headerName of headerNames) {
     77    testData.request.headers[headerName] = "test-value-for-" + headerName;
     78  }
     79 
     80  server.registerPathHandler(testData.testPath, function (aRequest, aResponse) {
     81    try {
     82      // check our request headers made it OK
     83      for (let headerName of headerNames) {
     84        Assert.equal(
     85          testData.request.headers[headerName],
     86          aRequest.getHeader(headerName)
     87        );
     88      }
     89 
     90      // send a response
     91      writeDataToResponse(testData.response, aResponse);
     92    } catch (e) {
     93      do_report_unexpected_exception(e);
     94    }
     95  });
     96 
     97  // fetch, via GET, with some request headers set
     98  fetch(getBaseUrl() + testData.testPath, { headers: testData.request.headers })
     99    .then(function (response) {
    100      // check response looks as expected
    101      Assert.ok(response.ok);
    102      Assert.equal(response.status, testData.response.status);
    103      Assert.equal(response.statusText, testData.response.statusText);
    104 
    105      // check a response header looks OK:
    106      Assert.equal(
    107        response.headers.get("Content-Type"),
    108        testData.response.contentType
    109      );
    110 
    111      // ... and again to check header names are case insensitive
    112      Assert.equal(
    113        response.headers.get("content-type"),
    114        testData.response.contentType
    115      );
    116 
    117      // ensure response.text() returns a promise that resolves appropriately
    118      response.text().then(function (text) {
    119        Assert.equal(text, testData.response.body);
    120        do_test_finished();
    121        run_next_test();
    122      });
    123    })
    124    .catch(function (e) {
    125      do_report_unexpected_exception(e);
    126      do_test_finished();
    127      run_next_test();
    128    });
    129 });
    130 
    131 // test a GET with no init
    132 add_test(function test_GetDataNoInit() {
    133  do_test_pending();
    134 
    135  let testData = createTestData("/getData");
    136 
    137  server.registerPathHandler(testData.testPath, function (aRequest, aResponse) {
    138    try {
    139      // send a response
    140      writeDataToResponse(testData.response, aResponse);
    141    } catch (e) {
    142      do_report_unexpected_exception(e);
    143    }
    144  });
    145 
    146  fetch(getBaseUrl() + testData.testPath, { headers: testData.request.headers })
    147    .then(function (response) {
    148      // check response looks as expected
    149      Assert.ok(response.ok);
    150      Assert.equal(response.status, testData.response.status);
    151 
    152      // ensure response.text() returns a promise that resolves appropriately
    153      response.text().then(function (text) {
    154        Assert.equal(text, testData.response.body);
    155        do_test_finished();
    156        run_next_test();
    157      });
    158    })
    159    .catch(function (e) {
    160      do_report_unexpected_exception(e);
    161      do_test_finished();
    162      run_next_test();
    163    });
    164 });
    165 
    166 // test some error responses
    167 add_test(function test_get40x() {
    168  do_test_pending();
    169 
    170  // prepare a response with some 40x error - a 404 will do
    171  let notFoundData = createTestData("/getNotFound");
    172  notFoundData.response.status = 404;
    173  notFoundData.response.statusText = "Not found";
    174  notFoundData.response.body = null;
    175 
    176  // No need to register a path handler - httpd will return 404 anyway.
    177  // Fetch, via GET, the resource that doesn't exist
    178  fetch(getBaseUrl() + notFoundData.testPath).then(function (response) {
    179    Assert.equal(response.status, 404);
    180    do_test_finished();
    181    run_next_test();
    182  });
    183 });
    184 
    185 add_test(function test_get50x() {
    186  do_test_pending();
    187 
    188  // prepare a response with some server error - a 500 will do
    189  let serverErrorData = createTestData("/serverError");
    190  serverErrorData.response.status = 500;
    191  serverErrorData.response.statusText = "The server broke";
    192  serverErrorData.response.body = null;
    193 
    194  server.registerPathHandler(
    195    serverErrorData.testPath,
    196    function (aRequest, aResponse) {
    197      try {
    198        // send the error response
    199        writeDataToResponse(serverErrorData.response, aResponse);
    200      } catch (e) {
    201        do_report_unexpected_exception(e);
    202      }
    203    }
    204  );
    205 
    206  // fetch, via GET, the resource that creates a server error
    207  fetch(getBaseUrl() + serverErrorData.testPath).then(function (response) {
    208    Assert.equal(response.status, 500);
    209    do_test_finished();
    210    run_next_test();
    211  });
    212 });
    213 
    214 // test a failure to connect
    215 add_test(function test_getTestFailedConnect() {
    216  do_test_pending();
    217  // try a server that's not there
    218  fetch("http://localhost:4/should/fail")
    219    .then(() => {
    220      do_throw("Request should not succeed");
    221    })
    222    .catch(err => {
    223      Assert.equal(true, err instanceof TypeError);
    224      do_test_finished();
    225      run_next_test();
    226    });
    227 });
    228 
    229 add_test(function test_mozError() {
    230  do_test_pending();
    231  // try a server that's not there
    232  fetch("http://localhost:4/should/fail", { mozErrors: true })
    233    .then(() => {
    234      do_throw("Request should not succeed");
    235    })
    236    .catch(err => {
    237      Assert.equal(err.result, Cr.NS_ERROR_CONNECTION_REFUSED);
    238      do_test_finished();
    239      run_next_test();
    240    });
    241 });
    242 
    243 add_test(function test_request_mozError() {
    244  do_test_pending();
    245  // try a server that's not there
    246  const r = new Request("http://localhost:4/should/fail", { mozErrors: true });
    247  fetch(r)
    248    .then(() => {
    249      do_throw("Request should not succeed");
    250    })
    251    .catch(err => {
    252      Assert.equal(err.result, Cr.NS_ERROR_CONNECTION_REFUSED);
    253      do_test_finished();
    254      run_next_test();
    255    });
    256 });
    257 
    258 // test POSTing some JSON data
    259 add_test(function test_PostJSONData() {
    260  do_test_pending();
    261 
    262  let testData = createTestData("/postJSONData");
    263  testData.request.body = '{"foo": "bar"}';
    264 
    265  server.registerPathHandler(testData.testPath, function (aRequest, aResponse) {
    266    try {
    267      let requestData = readDataFromRequest(aRequest);
    268 
    269      // Check the request body is OK
    270      Assert.equal(requestData.body, testData.request.body);
    271 
    272      // Check the content type is as expected
    273      Assert.equal(requestData.contentType, testData.request.contentType);
    274 
    275      writeDataToResponse(testData.response, aResponse);
    276    } catch (e) {
    277      Assert.ok(false);
    278    }
    279  });
    280 
    281  fetch(getBaseUrl() + testData.testPath, {
    282    method: "POST",
    283    body: testData.request.body,
    284    headers: {
    285      "Content-Type": "application/json",
    286    },
    287  })
    288    .then(function (aResponse) {
    289      Assert.ok(aResponse.ok);
    290      Assert.equal(aResponse.status, testData.response.status);
    291      Assert.equal(aResponse.statusText, testData.response.statusText);
    292 
    293      do_test_finished();
    294      run_next_test();
    295    })
    296    .catch(function (e) {
    297      do_report_unexpected_exception(e);
    298      do_test_finished();
    299      run_next_test();
    300    });
    301 });
    302 
    303 // test POSTing some text
    304 add_test(function test_PostTextData() {
    305  do_test_pending();
    306 
    307  let testData = createTestData("/postTextData");
    308  testData.request.body = "A plain text body";
    309  testData.request.contentType = "text/plain";
    310  let responseHeaderName = "some-response-header";
    311  testData.response.headers[responseHeaderName] = "some header value";
    312 
    313  server.registerPathHandler(testData.testPath, function (aRequest, aResponse) {
    314    try {
    315      let requestData = readDataFromRequest(aRequest);
    316 
    317      // Check the request body is OK
    318      Assert.equal(requestData.body, testData.request.body);
    319 
    320      // Check the content type is as expected
    321      Assert.equal(requestData.contentType, testData.request.contentType);
    322 
    323      writeDataToResponse(testData.response, aResponse);
    324    } catch (e) {
    325      Assert.ok(false);
    326    }
    327  });
    328 
    329  fetch(getBaseUrl() + testData.testPath, {
    330    method: "POST",
    331    body: testData.request.body,
    332    headers: {
    333      "Content-Type": testData.request.contentType,
    334    },
    335  })
    336    .then(function (aResponse) {
    337      Assert.ok(aResponse.ok);
    338      Assert.equal(aResponse.status, testData.response.status);
    339      Assert.equal(aResponse.statusText, testData.response.statusText);
    340 
    341      // check the response header is set OK
    342      Assert.equal(
    343        aResponse.headers.get(responseHeaderName),
    344        testData.response.headers[responseHeaderName]
    345      );
    346 
    347      do_test_finished();
    348      run_next_test();
    349    })
    350    .catch(function (e) {
    351      do_report_unexpected_exception(e);
    352      do_test_finished();
    353      run_next_test();
    354    });
    355 });
    356 
    357 add_test(async function test_https() {
    358  do_test_pending();
    359 
    360  const { NodeHTTP2Server } = ChromeUtils.importESModule(
    361    "resource://testing-common/NodeServer.sys.mjs"
    362  );
    363  let h2server = new NodeHTTP2Server();
    364  await h2server.start();
    365  await h2server.registerPathHandler("/test", (req, resp) => {
    366    resp.writeHead(200);
    367    resp.end("done");
    368  });
    369 
    370  fetch(`${h2server.origin()}/test`)
    371    .then(async response => {
    372      Assert.equal(await response.text(), "done");
    373    })
    374    .catch(e => {
    375      Assert.ok(false, `Fetch failed ${e}`);
    376    })
    377    .finally(async () => {
    378      await h2server.stop();
    379      do_test_finished();
    380      run_next_test();
    381    });
    382 });
    383 
    384 function run_test() {
    385  do_get_profile(); // So certificate installation works.
    386  // Set up an HTTP Server
    387  server = new HttpServer();
    388  server.start(-1);
    389 
    390  run_next_test();
    391 
    392  registerCleanupFunction(function () {
    393    server.stop(function () {});
    394  });
    395 }