tor-browser

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

test_XHR_redirects.js (8106B)


      1 // This file tests whether XmlHttpRequests correctly handle redirects,
      2 // including rewriting POSTs to GETs (on 301/302/303), as well as
      3 // prompting for redirects of other unsafe methods (such as PUTs, DELETEs,
      4 // etc--see HttpBaseChannel::IsSafeMethod).  Since no prompting is possible
      5 // in xpcshell, we get an error for prompts, and the request fails.
      6 "use strict";
      7 
      8 const { HttpServer } = ChromeUtils.importESModule(
      9  "resource://testing-common/httpd.sys.mjs"
     10 );
     11 const { Preferences } = ChromeUtils.importESModule(
     12  "resource://gre/modules/Preferences.sys.mjs"
     13 );
     14 
     15 var sSame;
     16 var sOther;
     17 var sRedirectPromptPref;
     18 
     19 const BUGID = "676059";
     20 const OTHERBUGID = "696849";
     21 
     22 ChromeUtils.defineLazyGetter(this, "pSame", function () {
     23  return sSame.identity.primaryPort;
     24 });
     25 ChromeUtils.defineLazyGetter(this, "pOther", function () {
     26  return sOther.identity.primaryPort;
     27 });
     28 
     29 function createXHR(async, method, path) {
     30  var xhr = new XMLHttpRequest();
     31  xhr.open(method, "http://localhost:" + pSame + path, async);
     32  return xhr;
     33 }
     34 
     35 function checkResults(xhr, method, status, unsafe) {
     36  if (unsafe) {
     37    if (sRedirectPromptPref) {
     38      // The method is null if we prompt for unsafe redirects
     39      method = null;
     40    } else {
     41      // The status code is 200 when we don't prompt for unsafe redirects
     42      status = 200;
     43    }
     44  }
     45 
     46  if (xhr.readyState != 4) {
     47    return false;
     48  }
     49  Assert.equal(xhr.status, status);
     50 
     51  if (status == 200) {
     52    // if followed then check for echoed method name
     53    Assert.equal(xhr.getResponseHeader("X-Received-Method"), method);
     54  }
     55 
     56  return true;
     57 }
     58 
     59 function run_test() {
     60  // start servers
     61  sSame = new HttpServer();
     62 
     63  // same-origin redirects
     64  sSame.registerPathHandler(
     65    "/bug" + BUGID + "-redirect301",
     66    bug676059redirect301
     67  );
     68  sSame.registerPathHandler(
     69    "/bug" + BUGID + "-redirect302",
     70    bug676059redirect302
     71  );
     72  sSame.registerPathHandler(
     73    "/bug" + BUGID + "-redirect303",
     74    bug676059redirect303
     75  );
     76  sSame.registerPathHandler(
     77    "/bug" + BUGID + "-redirect307",
     78    bug676059redirect307
     79  );
     80  sSame.registerPathHandler(
     81    "/bug" + BUGID + "-redirect308",
     82    bug676059redirect308
     83  );
     84 
     85  // cross-origin redirects
     86  sSame.registerPathHandler(
     87    "/bug" + OTHERBUGID + "-redirect301",
     88    bug696849redirect301
     89  );
     90  sSame.registerPathHandler(
     91    "/bug" + OTHERBUGID + "-redirect302",
     92    bug696849redirect302
     93  );
     94  sSame.registerPathHandler(
     95    "/bug" + OTHERBUGID + "-redirect303",
     96    bug696849redirect303
     97  );
     98  sSame.registerPathHandler(
     99    "/bug" + OTHERBUGID + "-redirect307",
    100    bug696849redirect307
    101  );
    102  sSame.registerPathHandler(
    103    "/bug" + OTHERBUGID + "-redirect308",
    104    bug696849redirect308
    105  );
    106 
    107  // same-origin target
    108  sSame.registerPathHandler("/bug" + BUGID + "-target", echoMethod);
    109  sSame.start(-1);
    110 
    111  // cross-origin target
    112  sOther = new HttpServer();
    113  sOther.registerPathHandler("/bug" + OTHERBUGID + "-target", echoMethod);
    114  sOther.start(-1);
    115 
    116  // format: redirectType, methodToSend, redirectedMethod, finalStatus
    117  //   redirectType sets the URI the initial request goes to
    118  //   methodToSend is the HTTP method to send
    119  //   redirectedMethod is the method to use for the redirect, if any
    120  //   finalStatus is 200 when the redirect takes place, redirectType otherwise
    121 
    122  // Note that unsafe methods should not follow the redirect automatically
    123  // Of the methods below, DELETE, POST and PUT are unsafe
    124 
    125  sRedirectPromptPref = Preferences.get("network.http.prompt-temp-redirect");
    126  // Following Bug 677754 we don't prompt for unsafe redirects
    127 
    128  // same-origin variant
    129  var tests = [
    130    // 301: rewrite just POST
    131    [301, "DELETE", "DELETE", 301, true],
    132    [301, "GET", "GET", 200, false],
    133    [301, "HEAD", "HEAD", 200, false],
    134    [301, "POST", "GET", 200, false],
    135    [301, "PUT", "PUT", 301, true],
    136    [301, "PROPFIND", "PROPFIND", 200, false],
    137    // 302: see 301
    138    [302, "DELETE", "DELETE", 302, true],
    139    [302, "GET", "GET", 200, false],
    140    [302, "HEAD", "HEAD", 200, false],
    141    [302, "POST", "GET", 200, false],
    142    [302, "PUT", "PUT", 302, true],
    143    [302, "PROPFIND", "PROPFIND", 200, false],
    144    // 303: rewrite to GET except HEAD
    145    [303, "DELETE", "GET", 200, false],
    146    [303, "GET", "GET", 200, false],
    147    [303, "HEAD", "HEAD", 200, false],
    148    [303, "POST", "GET", 200, false],
    149    [303, "PUT", "GET", 200, false],
    150    [303, "PROPFIND", "GET", 200, false],
    151    // 307: never rewrite
    152    [307, "DELETE", "DELETE", 307, true],
    153    [307, "GET", "GET", 200, false],
    154    [307, "HEAD", "HEAD", 200, false],
    155    [307, "POST", "POST", 307, true],
    156    [307, "PUT", "PUT", 307, true],
    157    [307, "PROPFIND", "PROPFIND", 200, false],
    158    // 308: never rewrite
    159    [308, "DELETE", "DELETE", 308, true],
    160    [308, "GET", "GET", 200, false],
    161    [308, "HEAD", "HEAD", 200, false],
    162    [308, "POST", "POST", 308, true],
    163    [308, "PUT", "PUT", 308, true],
    164    [308, "PROPFIND", "PROPFIND", 200, false],
    165  ];
    166 
    167  // cross-origin variant
    168  var othertests = tests; // for now these have identical results
    169 
    170  var xhr;
    171 
    172  for (let i = 0; i < tests.length; ++i) {
    173    dump("Testing " + tests[i] + "\n");
    174    xhr = createXHR(
    175      false,
    176      tests[i][1],
    177      "/bug" + BUGID + "-redirect" + tests[i][0]
    178    );
    179    xhr.send(null);
    180    checkResults(xhr, tests[i][2], tests[i][3], tests[i][4]);
    181  }
    182 
    183  for (let i = 0; i < othertests.length; ++i) {
    184    dump("Testing " + othertests[i] + " (cross-origin)\n");
    185    xhr = createXHR(
    186      false,
    187      othertests[i][1],
    188      "/bug" + OTHERBUGID + "-redirect" + othertests[i][0]
    189    );
    190    xhr.send(null);
    191    checkResults(xhr, othertests[i][2], tests[i][3], tests[i][4]);
    192  }
    193 
    194  sSame.stop(do_test_finished);
    195  sOther.stop(do_test_finished);
    196 }
    197 
    198 function redirect(metadata, response, status, port, bugid) {
    199  // set a proper reason string to avoid confusion when looking at the
    200  // HTTP messages
    201  var reason;
    202  if (status == 301) {
    203    reason = "Moved Permanently";
    204  } else if (status == 302) {
    205    reason = "Found";
    206  } else if (status == 303) {
    207    reason = "See Other";
    208  } else if (status == 307) {
    209    reason = "Temporary Redirect";
    210  } else if (status == 308) {
    211    reason = "Permanent Redirect";
    212  }
    213 
    214  response.setStatusLine(metadata.httpVersion, status, reason);
    215  response.setHeader(
    216    "Location",
    217    "http://localhost:" + port + "/bug" + bugid + "-target"
    218  );
    219 }
    220 
    221 // PATH HANDLER FOR /bug676059-redirect301
    222 function bug676059redirect301(metadata, response) {
    223  redirect(metadata, response, 301, pSame, BUGID);
    224 }
    225 
    226 // PATH HANDLER FOR /bug696849-redirect301
    227 function bug696849redirect301(metadata, response) {
    228  redirect(metadata, response, 301, pOther, OTHERBUGID);
    229 }
    230 
    231 // PATH HANDLER FOR /bug676059-redirect302
    232 function bug676059redirect302(metadata, response) {
    233  redirect(metadata, response, 302, pSame, BUGID);
    234 }
    235 
    236 // PATH HANDLER FOR /bug696849-redirect302
    237 function bug696849redirect302(metadata, response) {
    238  redirect(metadata, response, 302, pOther, OTHERBUGID);
    239 }
    240 
    241 // PATH HANDLER FOR /bug676059-redirect303
    242 function bug676059redirect303(metadata, response) {
    243  redirect(metadata, response, 303, pSame, BUGID);
    244 }
    245 
    246 // PATH HANDLER FOR /bug696849-redirect303
    247 function bug696849redirect303(metadata, response) {
    248  redirect(metadata, response, 303, pOther, OTHERBUGID);
    249 }
    250 
    251 // PATH HANDLER FOR /bug676059-redirect307
    252 function bug676059redirect307(metadata, response) {
    253  redirect(metadata, response, 307, pSame, BUGID);
    254 }
    255 
    256 // PATH HANDLER FOR /bug676059-redirect308
    257 function bug676059redirect308(metadata, response) {
    258  redirect(metadata, response, 308, pSame, BUGID);
    259 }
    260 
    261 // PATH HANDLER FOR /bug696849-redirect307
    262 function bug696849redirect307(metadata, response) {
    263  redirect(metadata, response, 307, pOther, OTHERBUGID);
    264 }
    265 
    266 // PATH HANDLER FOR /bug696849-redirect308
    267 function bug696849redirect308(metadata, response) {
    268  redirect(metadata, response, 308, pOther, OTHERBUGID);
    269 }
    270 
    271 // Echo the request method in "X-Received-Method" header field
    272 function echoMethod(metadata, response) {
    273  response.setStatusLine(metadata.httpVersion, 200, "OK");
    274  response.setHeader("X-Received-Method", metadata.method);
    275 }