tor-browser

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

test_content_length_underrun.js (9981B)


      1 /*
      2 * Test Content-Length underrun behavior
      3 */
      4 
      5 ////////////////////////////////////////////////////////////////////////////////
      6 // Test infrastructure
      7 
      8 "use strict";
      9 
     10 const { HttpServer } = ChromeUtils.importESModule(
     11  "resource://testing-common/httpd.sys.mjs"
     12 );
     13 
     14 ChromeUtils.defineLazyGetter(this, "URL", function () {
     15  return "http://localhost:" + httpserver.identity.primaryPort;
     16 });
     17 
     18 var httpserver = new HttpServer();
     19 var test_flags = [];
     20 var testPathBase = "/cl_hdrs";
     21 
     22 var prefs;
     23 var enforcePrefStrict;
     24 var enforcePrefSoft;
     25 var enforcePrefStrictChunked;
     26 
     27 Services.prefs.setBoolPref("security.allow_eval_with_system_principal", true);
     28 registerCleanupFunction(() => {
     29  Services.prefs.clearUserPref("security.allow_eval_with_system_principal");
     30 });
     31 
     32 function run_test() {
     33  prefs = Services.prefs;
     34  enforcePrefStrict = prefs.getBoolPref("network.http.enforce-framing.http1");
     35  enforcePrefSoft = prefs.getBoolPref("network.http.enforce-framing.soft");
     36  enforcePrefStrictChunked = prefs.getBoolPref(
     37    "network.http.enforce-framing.strict_chunked_encoding"
     38  );
     39 
     40  prefs.setBoolPref("network.http.enforce-framing.http1", true);
     41 
     42  httpserver.start(-1);
     43 
     44  do_test_pending();
     45  run_test_number(1);
     46 }
     47 
     48 function run_test_number(num) {
     49  let testPath = testPathBase + num;
     50  // eslint-disable-next-line no-eval
     51  httpserver.registerPathHandler(testPath, eval("handler" + num));
     52 
     53  var channel = setupChannel(testPath);
     54  let flags = test_flags[num]; // OK if flags undefined for test
     55  channel.asyncOpen(
     56    // eslint-disable-next-line no-eval
     57    new ChannelListener(eval("completeTest" + num), channel, flags)
     58  );
     59 }
     60 
     61 function run_gzip_test(num) {
     62  let testPath = testPathBase + num;
     63  // eslint-disable-next-line no-eval
     64  httpserver.registerPathHandler(testPath, eval("handler" + num));
     65 
     66  var channel = setupChannel(testPath);
     67 
     68  function StreamListener() {}
     69 
     70  StreamListener.prototype = {
     71    QueryInterface: ChromeUtils.generateQI([
     72      "nsIStreamListener",
     73      "nsIRequestObserver",
     74    ]),
     75 
     76    onStartRequest() {},
     77 
     78    onStopRequest(aRequest, aStatusCode) {
     79      // Make sure we catch the error NS_ERROR_NET_PARTIAL_TRANSFER here.
     80      Assert.equal(aStatusCode, Cr.NS_ERROR_NET_PARTIAL_TRANSFER);
     81      //  do_test_finished();
     82      endTests();
     83    },
     84 
     85    onDataAvailable() {},
     86  };
     87 
     88  let listener = new StreamListener();
     89 
     90  channel.asyncOpen(listener);
     91 }
     92 
     93 function setupChannel(url) {
     94  var chan = NetUtil.newChannel({
     95    uri: URL + url,
     96    loadUsingSystemPrincipal: true,
     97  });
     98  var httpChan = chan.QueryInterface(Ci.nsIHttpChannel);
     99  return httpChan;
    100 }
    101 
    102 function endTests() {
    103  // restore the prefs to pre-test values
    104  prefs.setBoolPref("network.http.enforce-framing.http1", enforcePrefStrict);
    105  prefs.setBoolPref("network.http.enforce-framing.soft", enforcePrefSoft);
    106  prefs.setBoolPref(
    107    "network.http.enforce-framing.strict_chunked_encoding",
    108    enforcePrefStrictChunked
    109  );
    110  httpserver.stop(do_test_finished);
    111 }
    112 
    113 ////////////////////////////////////////////////////////////////////////////////
    114 // Test 1: FAIL because of Content-Length underrun with HTTP 1.1
    115 test_flags[1] = CL_EXPECT_LATE_FAILURE;
    116 
    117 // eslint-disable-next-line no-unused-vars
    118 function handler1(metadata, response) {
    119  var body = "blablabla";
    120 
    121  response.seizePower();
    122  response.write("HTTP/1.1 200 OK\r\n");
    123  response.write("Content-Type: text/plain\r\n");
    124  response.write("Content-Length: 556677\r\n");
    125  response.write("\r\n");
    126  response.write(body);
    127  response.finish();
    128 }
    129 
    130 // eslint-disable-next-line no-unused-vars
    131 function completeTest1(request) {
    132  Assert.equal(request.status, Cr.NS_ERROR_NET_PARTIAL_TRANSFER);
    133 
    134  run_test_number(11);
    135 }
    136 
    137 ////////////////////////////////////////////////////////////////////////////////
    138 // Test 11: PASS because of Content-Length underrun with HTTP 1.1 but non 2xx
    139 test_flags[11] = CL_IGNORE_CL;
    140 
    141 // eslint-disable-next-line no-unused-vars
    142 function handler11(metadata, response) {
    143  var body = "blablabla";
    144 
    145  response.seizePower();
    146  response.write("HTTP/1.1 404 NotOK\r\n");
    147  response.write("Content-Type: text/plain\r\n");
    148  response.write("Content-Length: 556677\r\n");
    149  response.write("\r\n");
    150  response.write(body);
    151  response.finish();
    152 }
    153 
    154 // eslint-disable-next-line no-unused-vars
    155 function completeTest11(request) {
    156  Assert.equal(request.status, Cr.NS_OK);
    157  run_test_number(2);
    158 }
    159 
    160 ////////////////////////////////////////////////////////////////////////////////
    161 // Test 2: Succeed because Content-Length underrun is with HTTP 1.0
    162 
    163 test_flags[2] = CL_IGNORE_CL;
    164 
    165 // eslint-disable-next-line no-unused-vars
    166 function handler2(metadata, response) {
    167  var body = "short content";
    168 
    169  response.seizePower();
    170  response.write("HTTP/1.0 200 OK\r\n");
    171  response.write("Content-Type: text/plain\r\n");
    172  response.write("Content-Length: 12345678\r\n");
    173  response.write("\r\n");
    174  response.write(body);
    175  response.finish();
    176 }
    177 
    178 // eslint-disable-next-line no-unused-vars
    179 function completeTest2(request) {
    180  Assert.equal(request.status, Cr.NS_OK);
    181 
    182  // test 3 requires the enforce-framing prefs to be false
    183  prefs.setBoolPref("network.http.enforce-framing.http1", false);
    184  prefs.setBoolPref("network.http.enforce-framing.soft", false);
    185  prefs.setBoolPref(
    186    "network.http.enforce-framing.strict_chunked_encoding",
    187    false
    188  );
    189  run_test_number(3);
    190 }
    191 
    192 ////////////////////////////////////////////////////////////////////////////////
    193 // Test 3: SUCCEED with bad Content-Length because pref allows it
    194 test_flags[3] = CL_IGNORE_CL;
    195 
    196 // eslint-disable-next-line no-unused-vars
    197 function handler3(metadata, response) {
    198  var body = "blablabla";
    199 
    200  response.seizePower();
    201  response.write("HTTP/1.1 200 OK\r\n");
    202  response.write("Content-Type: text/plain\r\n");
    203  response.write("Content-Length: 556677\r\n");
    204  response.write("\r\n");
    205  response.write(body);
    206  response.finish();
    207 }
    208 
    209 // eslint-disable-next-line no-unused-vars
    210 function completeTest3(request) {
    211  Assert.equal(request.status, Cr.NS_OK);
    212  prefs.setBoolPref("network.http.enforce-framing.soft", true);
    213  run_test_number(4);
    214 }
    215 
    216 ////////////////////////////////////////////////////////////////////////////////
    217 // Test 4: Succeed because a cut off deflate stream can't be detected
    218 test_flags[4] = CL_IGNORE_CL;
    219 
    220 // eslint-disable-next-line no-unused-vars
    221 function handler4(metadata, response) {
    222  // this is the beginning of a deflate compressed response body
    223 
    224  var body =
    225    "\xcd\x57\xcd\x6e\x1b\x37\x10\xbe\x07\xc8\x3b\x0c\x36\x68\x72\xd1" +
    226    "\xbf\x92\x22\xb1\x57\x0a\x64\x4b\x6a\x0c\x28\xb6\x61\xa9\x41\x73" +
    227    "\x2a\xb8\xbb\x94\x44\x98\xfb\x03\x92\x92\xec\x06\x7d\x97\x1e\xeb" +
    228    "\xbe\x86\x5e\xac\xc3\x25\x97\xa2\x64\xb9\x75\x0b\x14\xe8\x69\x87" +
    229    "\x33\x9c\x1f\x7e\x33\x9c\xe1\x86\x9f\x66\x9f\x27\xfd\x97\x2f\x20" +
    230    "\xfc\x34\x1a\x0c\x35\x01\xa1\x62\x8a\xd3\xfe\xf5\xcd\xd5\xe5\xd5" +
    231    "\x6c\x54\x83\x49\xbe\x60\x31\xa3\x1c\x12\x0a\x0b\x2a\x15\xcb\x33" +
    232    "\x4d\xae\x19\x05\x19\xe7\x9c\x30\x41\x1b\x61\xd3\x28\x95\xfa\x29" +
    233    "\x55\x04\x32\x92\xd2\x5e\x90\x50\x19\x0b\x56\x68\x9d\x00\xe2\x3c" +
    234    "\x53\x34\x53\xbd\xc0\x99\x56\xf9\x4a\x51\xe0\x64\xcf\x18\x24\x24" +
    235    "\x93\xb0\xca\x40\xd2\x15\x07\x6e\xbd\x37\x60\x82\x3b\x8f\x86\x22" +
    236    "\x21\xcb\x15\x95\x35\x20\x91\xa4\x59\xac\xa9\x62\x95\x31\xed\x14" +
    237    "\xc9\x98\x2c\x19\x15\x3a\x62\x45\xef\x70\x1b\x50\x05\xa4\x28\xc4" +
    238    "\xf6\x21\x66\xa4\xdc\x83\x32\x09\x85\xc8\xe7\x54\xa2\x4b\x81\x74" +
    239    "\xbe\x12\xc0\x91\xb9\x7d\x50\x24\xe2\x0c\xd9\x29\x06\x2e\xdd\x79";
    240 
    241  response.seizePower();
    242  response.write("HTTP/1.1 200 OK\r\n");
    243  response.write("Content-Type: text/plain\r\n");
    244  response.write("Content-Length: 553677\r\n");
    245  response.write("Content-Encoding: deflate\r\n");
    246  response.write("\r\n");
    247  response.write(body);
    248  response.finish();
    249 }
    250 
    251 // eslint-disable-next-line no-unused-vars
    252 function completeTest4(request) {
    253  Assert.equal(request.status, Cr.NS_OK);
    254 
    255  prefs.setBoolPref("network.http.enforce-framing.http1", true);
    256  run_gzip_test(99);
    257 }
    258 
    259 ////////////////////////////////////////////////////////////////////////////////
    260 // Test 99: FAIL because a cut off gzip stream CAN be detected
    261 
    262 // Note that test 99 here is run completely different than the other tests in
    263 // this file so if you add more tests here, consider adding them before this.
    264 
    265 // eslint-disable-next-line no-unused-vars
    266 function handler99(metadata, response) {
    267  // this is the beginning of a gzip compressed response body
    268 
    269  var body =
    270    "\x1f\x8b\x08\x00\x80\xb9\x25\x53\x00\x03\xd4\xd9\x79\xb8\x8e\xe5" +
    271    "\xba\x00\xf0\x65\x19\x33\x24\x15\x29\xf3\x50\x52\xc6\xac\x85\x10" +
    272    "\x8b\x12\x22\x45\xe6\xb6\x21\x9a\x96\x84\x4c\x69\x32\xec\x84\x92" +
    273    "\xcc\x99\x6a\xd9\x32\xa5\xd0\x40\xd9\xc6\x14\x15\x95\x28\x62\x9b" +
    274    "\x09\xc9\x70\x4a\x25\x53\xec\x8e\x9c\xe5\x1c\x9d\xeb\xfe\x9d\x73" +
    275    "\x9d\x3f\xf6\x1f\xe7\xbd\xae\xcf\xf3\xbd\xbf\xef\x7e\x9f\xeb\x79" +
    276    "\xef\xf7\x99\xde\xe5\xee\x6e\xdd\x3b\x75\xeb\xd1\xb5\x6c\xb3\xd4" +
    277    "\x47\x1f\x48\xf8\x17\x1d\x15\xce\x1d\x55\x92\x93\xcf\x97\xe7\x8e" +
    278    "\x8b\xca\xe4\xca\x55\x92\x2a\x54\x4e\x4e\x4e\x4a\xa8\x78\x53\xa5" +
    279    "\x8a\x15\x2b\x55\x4a\xfa\xe3\x7b\x85\x8a\x37\x55\x48\xae\x92\x50" +
    280    "\xb4\xc2\xbf\xaa\x41\x17\x1f\xbd\x7b\xf6\xba\xaf\x47\xd1\xa2\x09" +
    281    "\x3d\xba\x75\xeb\xf5\x3f\xc5\xfd\x6f\xbf\xff\x3f\x3d\xfa\xd7\x6d" +
    282    "\x74\x7b\x62\x86\x0c\xff\x79\x9e\x98\x50\x33\xe1\x8f\xb3\x01\xef" +
    283    "\xb6\x38\x7f\x9e\x92\xee\xf9\xa7\xee\xcb\x74\x21\x26\x25\xa1\x6a" +
    284    "\x42\xf6\x73\xff\x96\x4c\x28\x91\x90\xe5\xdc\x79\xa6\x8b\xe2\x52" +
    285    "\xd2\xbf\x5d\x28\x2b\x24\x26\xfc\xa9\xcc\x96\x1e\x97\x31\xfd\xba" +
    286    "\xee\xe9\xde\x3d\x31\xe5\x4f\x65\xc1\xf4\xb8\x0b\x65\x86\x8b\xca";
    287  response.seizePower();
    288  response.write("HTTP/1.1 200 OK\r\n");
    289  response.write("Content-Type: text/plain\r\n");
    290  response.write("Content-Length: 553677\r\n");
    291  response.write("Content-Encoding: gzip\r\n");
    292  response.write("\r\n");
    293  response.write(body);
    294  response.finish();
    295 }