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.
8 const { HttpServer } = ChromeUtils.importESModule(
9 "resource://testing-common/httpd.sys.mjs"
11 const { Preferences } = ChromeUtils.importESModule(
12 "resource://gre/modules/Preferences.sys.mjs"
17 var sRedirectPromptPref;
19 const BUGID = "676059";
20 const OTHERBUGID = "696849";
22 ChromeUtils.defineLazyGetter(this, "pSame", function () {
23 return sSame.identity.primaryPort;
25 ChromeUtils.defineLazyGetter(this, "pOther", function () {
26 return sOther.identity.primaryPort;
29 function createXHR(async, method, path) {
30 var xhr = new XMLHttpRequest();
31 xhr.open(method, "http://localhost:" + pSame + path, async);
35 function checkResults(xhr, method, status, unsafe) {
37 if (sRedirectPromptPref) {
38 // The method is null if we prompt for unsafe redirects
41 // The status code is 200 when we don't prompt for unsafe redirects
46 if (xhr.readyState != 4) {
49 Assert.equal(xhr.status, status);
52 // if followed then check for echoed method name
53 Assert.equal(xhr.getResponseHeader("X-Received-Method"), method);
61 sSame = new HttpServer();
63 // same-origin redirects
64 sSame.registerPathHandler(
65 "/bug" + BUGID + "-redirect301",
68 sSame.registerPathHandler(
69 "/bug" + BUGID + "-redirect302",
72 sSame.registerPathHandler(
73 "/bug" + BUGID + "-redirect303",
76 sSame.registerPathHandler(
77 "/bug" + BUGID + "-redirect307",
80 sSame.registerPathHandler(
81 "/bug" + BUGID + "-redirect308",
85 // cross-origin redirects
86 sSame.registerPathHandler(
87 "/bug" + OTHERBUGID + "-redirect301",
90 sSame.registerPathHandler(
91 "/bug" + OTHERBUGID + "-redirect302",
94 sSame.registerPathHandler(
95 "/bug" + OTHERBUGID + "-redirect303",
98 sSame.registerPathHandler(
99 "/bug" + OTHERBUGID + "-redirect307",
102 sSame.registerPathHandler(
103 "/bug" + OTHERBUGID + "-redirect308",
107 // same-origin target
108 sSame.registerPathHandler("/bug" + BUGID + "-target", echoMethod);
111 // cross-origin target
112 sOther = new HttpServer();
113 sOther.registerPathHandler("/bug" + OTHERBUGID + "-target", echoMethod);
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
122 // Note that unsafe methods should not follow the redirect automatically
123 // Of the methods below, DELETE, POST and PUT are unsafe
125 sRedirectPromptPref = Preferences.get("network.http.prompt-temp-redirect");
126 // Following Bug 677754 we don't prompt for unsafe redirects
128 // same-origin variant
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],
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],
167 // cross-origin variant
168 var othertests = tests; // for now these have identical results
172 for (let i = 0; i < tests.length; ++i) {
173 dump("Testing " + tests[i] + "\n");
177 "/bug" + BUGID + "-redirect" + tests[i][0]
180 checkResults(xhr, tests[i][2], tests[i][3], tests[i][4]);
183 for (let i = 0; i < othertests.length; ++i) {
184 dump("Testing " + othertests[i] + " (cross-origin)\n");
188 "/bug" + OTHERBUGID + "-redirect" + othertests[i][0]
191 checkResults(xhr, othertests[i][2], tests[i][3], tests[i][4]);
194 sSame.stop(do_test_finished);
195 sOther.stop(do_test_finished);
198 function redirect(metadata, response, status, port, bugid) {
199 // set a proper reason string to avoid confusion when looking at the
203 reason = "Moved Permanently";
204 } else if (status == 302) {
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";
214 response.setStatusLine(metadata.httpVersion, status, reason);
217 "http://localhost:" + port + "/bug" + bugid + "-target"
221 // PATH HANDLER FOR /bug676059-redirect301
222 function bug676059redirect301(metadata, response) {
223 redirect(metadata, response, 301, pSame, BUGID);
226 // PATH HANDLER FOR /bug696849-redirect301
227 function bug696849redirect301(metadata, response) {
228 redirect(metadata, response, 301, pOther, OTHERBUGID);
231 // PATH HANDLER FOR /bug676059-redirect302
232 function bug676059redirect302(metadata, response) {
233 redirect(metadata, response, 302, pSame, BUGID);
236 // PATH HANDLER FOR /bug696849-redirect302
237 function bug696849redirect302(metadata, response) {
238 redirect(metadata, response, 302, pOther, OTHERBUGID);
241 // PATH HANDLER FOR /bug676059-redirect303
242 function bug676059redirect303(metadata, response) {
243 redirect(metadata, response, 303, pSame, BUGID);
246 // PATH HANDLER FOR /bug696849-redirect303
247 function bug696849redirect303(metadata, response) {
248 redirect(metadata, response, 303, pOther, OTHERBUGID);
251 // PATH HANDLER FOR /bug676059-redirect307
252 function bug676059redirect307(metadata, response) {
253 redirect(metadata, response, 307, pSame, BUGID);
256 // PATH HANDLER FOR /bug676059-redirect308
257 function bug676059redirect308(metadata, response) {
258 redirect(metadata, response, 308, pSame, BUGID);
261 // PATH HANDLER FOR /bug696849-redirect307
262 function bug696849redirect307(metadata, response) {
263 redirect(metadata, response, 307, pOther, OTHERBUGID);
266 // PATH HANDLER FOR /bug696849-redirect308
267 function bug696849redirect308(metadata, response) {
268 redirect(metadata, response, 308, pOther, OTHERBUGID);
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);