tor-browser

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

test_xhr_progressevents.html (11075B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <title>Test for XMLHttpRequest Progress Events</title>
      5  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      6  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      7 </head>
      8 <body onload="gen.next();">
      9 <pre id=l></pre>
     10 <script type="application/javascript">
     11 SimpleTest.waitForExplicitFinish();
     12 
     13 var gen = runTests();
     14 
     15 function log() {
     16  // Uncomment these to get debugging information
     17  /*
     18  document.getElementById("l").textContent += s + "\n";
     19  dump(s + "\n");
     20  */
     21 }
     22 
     23 function getEvent(e) {
     24  log("got event: " + e.type + " (" + e.target.readyState + ")");
     25  gen.next(e);
     26 }
     27 
     28 function startsWith(a, b) {
     29  return a.substr(0, b.length) === b;
     30 }
     31 
     32 function updateProgress(e, data, testName) {
     33  var test = " while running " + testName;
     34  is(e.type, "progress", "event type" + test);
     35 
     36  let response;
     37  if (data.nodata) {
     38    is(e.target.response, null, "response should be null" + test);
     39    response = null;
     40  }
     41  else if (data.text) {
     42    is(typeof e.target.response, "string", "response should be a string" + test);
     43    response = e.target.response;
     44  }
     45  else if (data.blob) {
     46    ok(e.target.response instanceof Blob, "response should be a Blob" + test);
     47    response = e.target.response;
     48  }
     49  else {
     50    ok(e.target.response instanceof ArrayBuffer, "response should be an ArrayBuffer" + test);
     51    response = bufferToString(e.target.response);
     52  }
     53  is(e.target.response, e.target.response, "reflexivity should hold" + test);
     54 
     55  if (!data.nodata && !data.encoded) {
     56    if (data.blob) {
     57      is(e.loaded, response.size, "event.loaded matches response size" + test);
     58    }
     59    else {
     60      is(e.loaded, response.length, "event.loaded matches response size" + test);
     61    }
     62  }
     63  ok(e.loaded > data.receivedBytes, "event.loaded increased" + test);
     64  ok(e.loaded - data.receivedBytes <= data.pendingBytes,
     65     "event.loaded didn't increase too much" + test);
     66 
     67  if (!data.nodata && !data.blob) {
     68    var newData;
     69    ok(startsWith(response, data.receivedResult),
     70       "response strictly grew" + test);
     71    newData = response.substr(data.receivedResult.length);
     72 
     73    if (!data.encoded) {
     74      ok(newData.length, "sanity check for progress" + test);
     75    }
     76    ok(startsWith(data.pendingResult, newData), "new data matches expected" + test);
     77  }
     78 
     79  is(e.lengthComputable, "total" in data, "lengthComputable" + test);
     80  if ("total" in data) {
     81    is(e.total, data.total, "total" + test);
     82  }
     83 
     84  if (!data.nodata && !data.blob) {
     85    data.pendingResult = data.pendingResult.substr(newData.length);
     86  }
     87  data.pendingBytes -= e.loaded - data.receivedBytes;
     88  data.receivedResult = response;
     89  data.receivedBytes = e.loaded;
     90 }
     91 
     92 function sendData(s) {
     93  var xhr = new XMLHttpRequest();
     94  xhr.open("POST", "progressserver.sjs?send");
     95  // The Blob constructor encodes String elements as UTF-8;
     96  // for straight bytes, manually convert to ArrayBuffer first
     97  var buffer = new Uint8Array(s.length);
     98  for (var i = 0; i < s.length; ++i) {
     99    buffer[i] = s.charCodeAt(i) & 0xff;
    100  };
    101  xhr.send(new Blob([buffer]));
    102 }
    103 
    104 function closeConn() {
    105  log("in closeConn");
    106  var xhr = new XMLHttpRequest();
    107  xhr.open("POST", "progressserver.sjs?close");
    108  xhr.send();
    109  return xhr;
    110 }
    111 
    112 var longString = "long";
    113 while(longString.length < 65536)
    114  longString += longString;
    115 
    116 function utf8encode(s) {
    117  return unescape(encodeURIComponent(s));
    118 }
    119 
    120 function bufferToString(buffer) {
    121  return String.fromCharCode.apply(String, new Uint8Array(buffer));
    122 }
    123 
    124 function* runTests() {
    125  var xhr = new XMLHttpRequest();
    126  xhr.onprogress = xhr.onload = xhr.onerror = xhr.onreadystatechange = xhr.onloadend = getEvent;
    127 
    128  var responseTypes = [{ type: "text", text: true },
    129                       { type: "arraybuffer", text: false, nodata: true },
    130                       { type: "blob", text: false, nodata: true, blob: true },
    131                       { type: "document", text: true, nodata: true },
    132                       { type: "json", text: true, nodata: true },
    133                       { type: "", text: true },
    134                      ];
    135  var responseType;
    136  var fileExpectedResult = "";
    137  for (let i = 0; i < 65536; i++) {
    138    fileExpectedResult += String.fromCharCode(i & 255);
    139  }
    140  while ((responseType = responseTypes.shift())) {
    141    let tests = [{ open: "Content-Type=text/plain", name: "simple test" },
    142                 { data: "hello world" },
    143                 { data: "\u0000\u0001\u0002\u0003" },
    144                 { data: longString },
    145                 { data: "x" },
    146                 { close: true },
    147                 { open: "Content-Type=text/plain&Content-Length=20", name: "with length", total: 20 },
    148                 // 5 bytes from the "ready" in the open step
    149                 { data: "abcde" },
    150                 { data: "0123456789" },
    151                 { close: true },
    152                 { open: "Content-Type=application/xml", name: "without length, as xml" },
    153                 { data: "<out>" },
    154                 { data: "text" },
    155                 { data: "</foo>invalid" },
    156                 { close: true },
    157                 { open: "Content-Type=text/plain;charset%3dutf-8", name: "utf8 data", encoded: true },
    158                 { data: utf8encode("räksmörgås"), utf16: "räksmörgås" },
    159                 { data: utf8encode("Å").substr(0,1), utf16: "" },
    160                 { data: utf8encode("Å").substr(1), utf16: "Å" },
    161                 { data: utf8encode("aöb").substr(0,2), utf16: "a" },
    162                 { data: utf8encode("aöb").substr(2), utf16: "öb" },
    163                 { data: utf8encode("a\u867Eb").substr(0,3), utf16: "a" },
    164                 { data: utf8encode("a\u867Eb").substr(3,1), utf16: "\u867E" },
    165                 { data: utf8encode("a\u867Eb").substr(4), utf16: "b" },
    166                 { close: true },
    167                 ];
    168    if (responseType.blob) {
    169      tests.push({ file: "file_XHR_binary2.bin", name: "cacheable data", total: 65536 },
    170                 { close: true },
    171                 { file: "file_XHR_binary2.bin", name: "cached data", total: 65536 },
    172                 { close: true });
    173    }
    174    let testState = { index: 0 };
    175 
    176    for (let i = 0; i < tests.length; ++i) {
    177      let test = tests[i];
    178      testState.index++;
    179      if ("open" in test || "file" in test) {
    180        log("opening " + testState.name);
    181        testState = { name: test.name + " for " + responseType.type,
    182                      index: 0,
    183                      pendingResult: "ready",
    184                      pendingBytes: 5,
    185                      receivedResult: "",
    186                      receivedBytes: 0,
    187                      total: test.total,
    188                      encoded: test.encoded,
    189                      nodata: responseType.nodata,
    190                      text: responseType.text,
    191                      blob: responseType.blob,
    192                      file: test.file };
    193 
    194        xhr.onreadystatechange = null;
    195        if (testState.file)
    196          xhr.open("GET", test.file);
    197        else
    198          xhr.open("POST", "progressserver.sjs?open&" + test.open);
    199        xhr.responseType = responseType.type;
    200        xhr.send("ready");
    201        xhr.onreadystatechange = getEvent;
    202 
    203        let e = yield undefined;
    204        is(e.type, "readystatechange", "should readystate to headers-received starting " + testState.name);
    205        is(xhr.readyState, xhr.HEADERS_RECEIVED, "should be in state HEADERS_RECEIVED starting " + testState.name);
    206 
    207        e = yield undefined;
    208        is(e.type, "readystatechange", "should readystate to loading starting " + testState.name);
    209        is(xhr.readyState, xhr.LOADING, "should be in state LOADING starting " + testState.name);
    210        if (typeof testState.total == "undefined")
    211          delete testState.total;
    212      }
    213      if ("file" in test) {
    214        testState.pendingBytes = testState.total;
    215        testState.pendingResult = fileExpectedResult;
    216      }
    217      if ("close" in test) {
    218        log("closing");
    219        let xhrClose;
    220        if (!testState.file)
    221          xhrClose = closeConn();
    222 
    223        let e = yield undefined;
    224        is(e.type, "readystatechange", "should readystate to done closing " + testState.name);
    225        is(xhr.readyState, xhr.DONE, "should be in state DONE closing " + testState.name);
    226        log("readystate to 4");
    227 
    228        e = yield undefined;
    229        is(e.type, "load", "should fire load closing " + testState.name);
    230        is(e.lengthComputable, e.total != 0, "length should " + (e.total == 0 ? "not " : "") + "be computable during load closing " + testState.name);
    231        log("got load");
    232 
    233        e = yield undefined;
    234        is(e.type, "loadend", "should fire loadend closing " + testState.name);
    235        is(e.lengthComputable, e.total != 0, "length should " + (e.total == 0 ? "not " : "") + "be computable during loadend closing " + testState.name);
    236        log("got loadend");
    237 
    238        // if we closed the connection using an explicit request, make sure that goes through before
    239        // running the next test in order to avoid reordered requests from closing the wrong
    240        // connection.
    241        if (xhrClose && xhrClose.readyState != xhrClose.DONE) {
    242          log("wait for closeConn to finish");
    243          xhrClose.onloadend = getEvent;
    244          yield undefined;
    245          is(xhrClose.readyState, xhrClose.DONE, "closeConn finished");
    246        }
    247 
    248        if (!testState.nodata && !responseType.blob) {
    249          // This branch intentionally left blank
    250          // Under these conditions we check the response during updateProgress
    251        }
    252        else if (responseType.type === "arraybuffer") {
    253          is(bufferToString(xhr.response), testState.pendingResult,
    254             "full response for " + testState.name);
    255        }
    256        else if (responseType.blob) {
    257          let reader = new FileReader;
    258          reader.readAsBinaryString(xhr.response);
    259          reader.onloadend = getEvent;
    260          yield undefined;
    261 
    262          is(reader.result, testState.pendingResult,
    263             "full response in blob for " + testState.name);
    264        }
    265 
    266        testState.name = "";
    267      }
    268      if ("data" in test) {
    269        log("sending");
    270        if (responseType.text) {
    271          testState.pendingResult += "utf16" in test ? test.utf16 : test.data;
    272        }
    273        else {
    274          testState.pendingResult += test.data;
    275        }
    276        testState.pendingBytes = test.data.length;
    277        sendData(test.data);
    278      }
    279 
    280      while(testState.pendingBytes) {
    281        log("waiting for more bytes: " + testState.pendingBytes);
    282        let e = yield undefined;
    283        // Readystate can fire several times between each progress event.
    284        if (e.type === "readystatechange")
    285          continue;
    286 
    287        updateProgress(e, testState, "data for " + testState.name + "[" + testState.index + "]");
    288      }
    289 
    290      if (!testState.nodata && !testState.blob) {
    291        is(testState.pendingResult, "",
    292           "should have consumed the expected result");
    293      }
    294 
    295      log("done with this test");
    296    }
    297 
    298    is(testState.name, "", "forgot to close last test");
    299  }
    300 
    301  SimpleTest.finish();
    302 }
    303 
    304 </script>
    305 
    306 </body>
    307 </html>