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