tor-browser

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

send-redirect-post-upload.htm (6545B)


      1 <!DOCTYPE html>
      2 <html>
      3 <head>
      4    <link rel="help" href="https://xhr.spec.whatwg.org/#handler-xhr-onprogress" data-tested-assertations="../.." />
      5    <link rel="help" href="https://xhr.spec.whatwg.org/#event-xhr-progress" data-tested-assertations="../.." />
      6    <link rel="help" href="https://xhr.spec.whatwg.org/#the-send()-method" data-tested-assertations="following::dt[@id="dom-xmlhttprequest-send-bodyinit"]/following::dd[1]/p[2] following::ol[1]/li[9]//li[1] following::ol[1]/li[9]//li[2]" />
      7    <link rel="help" href="https://fetch.spec.whatwg.org/#http-fetch" data-tested-assertations="following::ol[1]/li[6]/dl/dd[1]//dd[3]" />
      8    <link rel="help" href="https://fetch.spec.whatwg.org/#concept-http-redirect-fetch" data-tested-assertations="following::li[16]" />
      9    <script src="/resources/testharness.js"></script>
     10    <script src="/resources/testharnessreport.js"></script>
     11    <title>XMLHttpRequest: The send() method: POSTing to URL that redirects</title>
     12 </head>
     13 
     14 <body>
     15    <div id="log"></div>
     16 
     17    <script type="text/javascript">
     18    function testRedirectPost(params) {
     19        var test = async_test(document.title + " (" + params.name + ")");
     20        var actual = [];
     21        // We check upload.onprogress with a boolean because it *might* fire more than once
     22        var progressFiredReadyState1 = false;
     23 
     24        var expectedHeaders, expectedEvents;
     25 
     26        // 307 redirects should resend the POST data, and events and headers will be a little different..
     27        if(params.expectResendPost) {
     28            expectedHeaders = {
     29                "X-Request-Content-Length": "12000",
     30                "X-Request-Content-Type": "text/plain;charset=UTF-8",
     31                "X-Request-Method": "POST",
     32                "X-Request-Query": "NO",
     33                "Content-Length": "12000"
     34            }
     35            expectedEvents = [
     36                "xhr onreadystatechange 1",
     37                "xhr loadstart 1",
     38                "upload loadstart 1",
     39                "upload loadend 1",
     40                "xhr onreadystatechange 2",
     41                "xhr onreadystatechange 3",
     42                "xhr onreadystatechange 4",
     43                "xhr load 4",
     44                "xhr loadend 4"
     45            ];
     46        } else {
     47            // setting the right expectations for POST resent as GET without request body
     48            expectedHeaders = {
     49                "X-Request-Content-Length": "NO",
     50                "X-Request-Content-Type": "NO",
     51                "X-Request-Method": "GET",
     52                "X-Request-Query": "NO"
     53            }
     54            expectedEvents = [
     55                "xhr onreadystatechange 1",
     56                "xhr loadstart 1",
     57                "upload loadstart 1",
     58                "upload loadend 1",
     59                "xhr onreadystatechange 2",
     60                /* we expect no onreadystatechange readyState=3 event because there is no loading content */
     61                "xhr onreadystatechange 4",
     62                "xhr load 4",
     63                "xhr loadend 4"
     64            ];
     65        }
     66        // Override expectations if provided.
     67        if(params.expectedContentType)
     68          expectedHeaders["X-Request-Content-Type"] = params.expectedContentType;
     69 
     70        test.step(function()
     71        {
     72            var xhr = new XMLHttpRequest();
     73 
     74            xhr.upload.onloadstart = test.step_func(function(e) {
     75                actual.push("upload loadstart " + xhr.readyState);
     76            });
     77            xhr.upload.onprogress = test.step_func(function(e) {
     78                // events every 50ms, one final when uploading is done
     79                if(xhr.readyState >= xhr.HEADERS_RECEIVED) {
     80                    assert_equals(xhr.status, 200, "JS never gets to see the 30x status code");
     81                }
     82                progressFiredReadyState1 = xhr.readyState === xhr.OPENED;
     83            });
     84            xhr.upload.onloadend = test.step_func(function() {
     85                actual.push("upload loadend " + xhr.readyState);
     86            });
     87            xhr.onloadstart = test.step_func(function() {
     88                actual.push("xhr loadstart " + xhr.readyState);
     89            });
     90            xhr.onreadystatechange = test.step_func(function() {
     91                if(xhr.readyState >= xhr.HEADERS_RECEIVED) {
     92                    assert_equals(xhr.status, 200, "JS never gets to see the 30x status code");
     93                }
     94 
     95                // The UA may fire multiple "readystatechange" events while in
     96                // the "loading" state.
     97                // https://xhr.spec.whatwg.org/#the-send()-method
     98                if (xhr.readyState === 3 && actual[actual.length - 1] === "xhr onreadystatechange 3") {
     99                    return;
    100                }
    101 
    102                actual.push("xhr onreadystatechange " + xhr.readyState);
    103            });
    104            xhr.onload = test.step_func(function(e)
    105            {
    106                actual.push("xhr load " + xhr.readyState);
    107            });
    108            xhr.onloadend = test.step_func(function(e)
    109            {
    110                actual.push("xhr loadend " + xhr.readyState);
    111 
    112                assert_true(progressFiredReadyState1, "One progress event should fire on xhr.upload when readyState is 1");
    113 
    114                // Headers will tell us if data was sent when expected
    115                for(var header in expectedHeaders) {
    116                    assert_equals(xhr.getResponseHeader(header), expectedHeaders[header], header);
    117                }
    118 
    119                assert_array_equals(actual, expectedEvents, "events firing in expected order and states");
    120                if (params.expectedBody)
    121                  assert_equals(xhr.response, params.expectedBody, 'request body was resent');
    122                test.done();
    123            });
    124 
    125            xhr.open("POST", "./resources/redirect.py?location=content.py&code=" + params.code, true);
    126            xhr.send(params.body);
    127        });
    128    }
    129 
    130    const stringBody = "Test Message".repeat(1000);
    131    const blobBody = new Blob(new Array(1000).fill("Test Message"));
    132 
    133    testRedirectPost({name: "301", code: 301, expectResendPost: false, body: stringBody});
    134    testRedirectPost({name: "302", code: 302, expectResendPost: false, body: stringBody});
    135    testRedirectPost({name: "303", code: 303, expectResendPost: false, body: stringBody});
    136    testRedirectPost({name: "307 (string)", code: 307, expectResendPost: true,  body: stringBody, expectedBody: stringBody });
    137    testRedirectPost({name: "307 (blob)", code: 307, expectResendPost: true, body: blobBody, expectedBody: stringBody, expectedContentType: "NO" });
    138    </script>
    139 </body>
    140 </html>