test_Fetch.js (11080B)
1 /* Any copyright is dedicated to the Public Domain. 2 http://creativecommons.org/publicdomain/zero/1.0/ */ 3 4 const { HttpServer } = ChromeUtils.importESModule( 5 "resource://testing-common/httpd.sys.mjs" 6 ); 7 8 const BinaryInputStream = Components.Constructor( 9 "@mozilla.org/binaryinputstream;1", 10 "nsIBinaryInputStream", 11 "setInputStream" 12 ); 13 14 var server; 15 16 function getBaseUrl() { 17 return "http://localhost:" + server.identity.primaryPort; 18 } 19 20 // a way to create some test defaults 21 function createTestData(testPath) { 22 return { 23 testPath, 24 request: { 25 headers: {}, 26 contentType: "application/json", 27 }, 28 response: { 29 headers: {}, 30 contentType: "application/json", 31 body: '{"Look": "Success!"}', 32 status: 200, 33 statusText: "OK", 34 }, 35 }; 36 } 37 38 // read body and content type information from a request 39 function readDataFromRequest(aRequest) { 40 let requestData = {}; 41 if (aRequest.method == "POST" || aRequest.method == "PUT") { 42 if (aRequest.bodyInputStream) { 43 let inputStream = new BinaryInputStream(aRequest.bodyInputStream); 44 let bytes = []; 45 let available; 46 47 while ((available = inputStream.available()) > 0) { 48 Array.prototype.push.apply(bytes, inputStream.readByteArray(available)); 49 } 50 51 requestData.body = String.fromCharCode.apply(null, bytes); 52 requestData.contentType = aRequest.getHeader("Content-Type"); 53 } 54 } 55 return requestData; 56 } 57 58 // write status information, content type information and body to a response 59 function writeDataToResponse(aData, aResponse) { 60 aResponse.setStatusLine(null, aData.status, aData.statusText); 61 aResponse.setHeader("Content-Type", aData.contentType); 62 for (let header in aData.headers) { 63 aResponse.setHeader(header, aData.headers[header]); 64 } 65 aResponse.write(aData.body); 66 } 67 68 // test some GET functionality 69 add_test(function test_GetData() { 70 do_test_pending(); 71 72 let testData = createTestData("/getData"); 73 74 // set up some headers to test 75 let headerNames = ["x-test-header", "x-other-test-header"]; 76 for (let headerName of headerNames) { 77 testData.request.headers[headerName] = "test-value-for-" + headerName; 78 } 79 80 server.registerPathHandler(testData.testPath, function (aRequest, aResponse) { 81 try { 82 // check our request headers made it OK 83 for (let headerName of headerNames) { 84 Assert.equal( 85 testData.request.headers[headerName], 86 aRequest.getHeader(headerName) 87 ); 88 } 89 90 // send a response 91 writeDataToResponse(testData.response, aResponse); 92 } catch (e) { 93 do_report_unexpected_exception(e); 94 } 95 }); 96 97 // fetch, via GET, with some request headers set 98 fetch(getBaseUrl() + testData.testPath, { headers: testData.request.headers }) 99 .then(function (response) { 100 // check response looks as expected 101 Assert.ok(response.ok); 102 Assert.equal(response.status, testData.response.status); 103 Assert.equal(response.statusText, testData.response.statusText); 104 105 // check a response header looks OK: 106 Assert.equal( 107 response.headers.get("Content-Type"), 108 testData.response.contentType 109 ); 110 111 // ... and again to check header names are case insensitive 112 Assert.equal( 113 response.headers.get("content-type"), 114 testData.response.contentType 115 ); 116 117 // ensure response.text() returns a promise that resolves appropriately 118 response.text().then(function (text) { 119 Assert.equal(text, testData.response.body); 120 do_test_finished(); 121 run_next_test(); 122 }); 123 }) 124 .catch(function (e) { 125 do_report_unexpected_exception(e); 126 do_test_finished(); 127 run_next_test(); 128 }); 129 }); 130 131 // test a GET with no init 132 add_test(function test_GetDataNoInit() { 133 do_test_pending(); 134 135 let testData = createTestData("/getData"); 136 137 server.registerPathHandler(testData.testPath, function (aRequest, aResponse) { 138 try { 139 // send a response 140 writeDataToResponse(testData.response, aResponse); 141 } catch (e) { 142 do_report_unexpected_exception(e); 143 } 144 }); 145 146 fetch(getBaseUrl() + testData.testPath, { headers: testData.request.headers }) 147 .then(function (response) { 148 // check response looks as expected 149 Assert.ok(response.ok); 150 Assert.equal(response.status, testData.response.status); 151 152 // ensure response.text() returns a promise that resolves appropriately 153 response.text().then(function (text) { 154 Assert.equal(text, testData.response.body); 155 do_test_finished(); 156 run_next_test(); 157 }); 158 }) 159 .catch(function (e) { 160 do_report_unexpected_exception(e); 161 do_test_finished(); 162 run_next_test(); 163 }); 164 }); 165 166 // test some error responses 167 add_test(function test_get40x() { 168 do_test_pending(); 169 170 // prepare a response with some 40x error - a 404 will do 171 let notFoundData = createTestData("/getNotFound"); 172 notFoundData.response.status = 404; 173 notFoundData.response.statusText = "Not found"; 174 notFoundData.response.body = null; 175 176 // No need to register a path handler - httpd will return 404 anyway. 177 // Fetch, via GET, the resource that doesn't exist 178 fetch(getBaseUrl() + notFoundData.testPath).then(function (response) { 179 Assert.equal(response.status, 404); 180 do_test_finished(); 181 run_next_test(); 182 }); 183 }); 184 185 add_test(function test_get50x() { 186 do_test_pending(); 187 188 // prepare a response with some server error - a 500 will do 189 let serverErrorData = createTestData("/serverError"); 190 serverErrorData.response.status = 500; 191 serverErrorData.response.statusText = "The server broke"; 192 serverErrorData.response.body = null; 193 194 server.registerPathHandler( 195 serverErrorData.testPath, 196 function (aRequest, aResponse) { 197 try { 198 // send the error response 199 writeDataToResponse(serverErrorData.response, aResponse); 200 } catch (e) { 201 do_report_unexpected_exception(e); 202 } 203 } 204 ); 205 206 // fetch, via GET, the resource that creates a server error 207 fetch(getBaseUrl() + serverErrorData.testPath).then(function (response) { 208 Assert.equal(response.status, 500); 209 do_test_finished(); 210 run_next_test(); 211 }); 212 }); 213 214 // test a failure to connect 215 add_test(function test_getTestFailedConnect() { 216 do_test_pending(); 217 // try a server that's not there 218 fetch("http://localhost:4/should/fail") 219 .then(() => { 220 do_throw("Request should not succeed"); 221 }) 222 .catch(err => { 223 Assert.equal(true, err instanceof TypeError); 224 do_test_finished(); 225 run_next_test(); 226 }); 227 }); 228 229 add_test(function test_mozError() { 230 do_test_pending(); 231 // try a server that's not there 232 fetch("http://localhost:4/should/fail", { mozErrors: true }) 233 .then(() => { 234 do_throw("Request should not succeed"); 235 }) 236 .catch(err => { 237 Assert.equal(err.result, Cr.NS_ERROR_CONNECTION_REFUSED); 238 do_test_finished(); 239 run_next_test(); 240 }); 241 }); 242 243 add_test(function test_request_mozError() { 244 do_test_pending(); 245 // try a server that's not there 246 const r = new Request("http://localhost:4/should/fail", { mozErrors: true }); 247 fetch(r) 248 .then(() => { 249 do_throw("Request should not succeed"); 250 }) 251 .catch(err => { 252 Assert.equal(err.result, Cr.NS_ERROR_CONNECTION_REFUSED); 253 do_test_finished(); 254 run_next_test(); 255 }); 256 }); 257 258 // test POSTing some JSON data 259 add_test(function test_PostJSONData() { 260 do_test_pending(); 261 262 let testData = createTestData("/postJSONData"); 263 testData.request.body = '{"foo": "bar"}'; 264 265 server.registerPathHandler(testData.testPath, function (aRequest, aResponse) { 266 try { 267 let requestData = readDataFromRequest(aRequest); 268 269 // Check the request body is OK 270 Assert.equal(requestData.body, testData.request.body); 271 272 // Check the content type is as expected 273 Assert.equal(requestData.contentType, testData.request.contentType); 274 275 writeDataToResponse(testData.response, aResponse); 276 } catch (e) { 277 Assert.ok(false); 278 } 279 }); 280 281 fetch(getBaseUrl() + testData.testPath, { 282 method: "POST", 283 body: testData.request.body, 284 headers: { 285 "Content-Type": "application/json", 286 }, 287 }) 288 .then(function (aResponse) { 289 Assert.ok(aResponse.ok); 290 Assert.equal(aResponse.status, testData.response.status); 291 Assert.equal(aResponse.statusText, testData.response.statusText); 292 293 do_test_finished(); 294 run_next_test(); 295 }) 296 .catch(function (e) { 297 do_report_unexpected_exception(e); 298 do_test_finished(); 299 run_next_test(); 300 }); 301 }); 302 303 // test POSTing some text 304 add_test(function test_PostTextData() { 305 do_test_pending(); 306 307 let testData = createTestData("/postTextData"); 308 testData.request.body = "A plain text body"; 309 testData.request.contentType = "text/plain"; 310 let responseHeaderName = "some-response-header"; 311 testData.response.headers[responseHeaderName] = "some header value"; 312 313 server.registerPathHandler(testData.testPath, function (aRequest, aResponse) { 314 try { 315 let requestData = readDataFromRequest(aRequest); 316 317 // Check the request body is OK 318 Assert.equal(requestData.body, testData.request.body); 319 320 // Check the content type is as expected 321 Assert.equal(requestData.contentType, testData.request.contentType); 322 323 writeDataToResponse(testData.response, aResponse); 324 } catch (e) { 325 Assert.ok(false); 326 } 327 }); 328 329 fetch(getBaseUrl() + testData.testPath, { 330 method: "POST", 331 body: testData.request.body, 332 headers: { 333 "Content-Type": testData.request.contentType, 334 }, 335 }) 336 .then(function (aResponse) { 337 Assert.ok(aResponse.ok); 338 Assert.equal(aResponse.status, testData.response.status); 339 Assert.equal(aResponse.statusText, testData.response.statusText); 340 341 // check the response header is set OK 342 Assert.equal( 343 aResponse.headers.get(responseHeaderName), 344 testData.response.headers[responseHeaderName] 345 ); 346 347 do_test_finished(); 348 run_next_test(); 349 }) 350 .catch(function (e) { 351 do_report_unexpected_exception(e); 352 do_test_finished(); 353 run_next_test(); 354 }); 355 }); 356 357 add_test(async function test_https() { 358 do_test_pending(); 359 360 const { NodeHTTP2Server } = ChromeUtils.importESModule( 361 "resource://testing-common/NodeServer.sys.mjs" 362 ); 363 let h2server = new NodeHTTP2Server(); 364 await h2server.start(); 365 await h2server.registerPathHandler("/test", (req, resp) => { 366 resp.writeHead(200); 367 resp.end("done"); 368 }); 369 370 fetch(`${h2server.origin()}/test`) 371 .then(async response => { 372 Assert.equal(await response.text(), "done"); 373 }) 374 .catch(e => { 375 Assert.ok(false, `Fetch failed ${e}`); 376 }) 377 .finally(async () => { 378 await h2server.stop(); 379 do_test_finished(); 380 run_next_test(); 381 }); 382 }); 383 384 function run_test() { 385 do_get_profile(); // So certificate installation works. 386 // Set up an HTTP Server 387 server = new HttpServer(); 388 server.start(-1); 389 390 run_next_test(); 391 392 registerCleanupFunction(function () { 393 server.stop(function () {}); 394 }); 395 }