1.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 1.2 +++ b/services/common/tests/unit/test_restrequest.js Wed Dec 31 06:09:35 2014 +0100 1.3 @@ -0,0 +1,840 @@ 1.4 +/* Any copyright is dedicated to the Public Domain. 1.5 + http://creativecommons.org/publicdomain/zero/1.0/ */ 1.6 + 1.7 +"use strict"; 1.8 + 1.9 +Cu.import("resource://gre/modules/NetUtil.jsm"); 1.10 +Cu.import("resource://gre/modules/Log.jsm"); 1.11 +Cu.import("resource://services-common/rest.js"); 1.12 +Cu.import("resource://services-common/utils.js"); 1.13 + 1.14 +function run_test() { 1.15 + Log.repository.getLogger("Services.Common.RESTRequest").level = 1.16 + Log.Level.Trace; 1.17 + initTestLogging("Trace"); 1.18 + 1.19 + run_next_test(); 1.20 +} 1.21 + 1.22 +/** 1.23 + * Initializing a RESTRequest with an invalid URI throws 1.24 + * NS_ERROR_MALFORMED_URI. 1.25 + */ 1.26 +add_test(function test_invalid_uri() { 1.27 + do_check_throws(function() { 1.28 + new RESTRequest("an invalid URI"); 1.29 + }, Cr.NS_ERROR_MALFORMED_URI); 1.30 + run_next_test(); 1.31 +}); 1.32 + 1.33 +/** 1.34 + * Verify initial values for attributes. 1.35 + */ 1.36 +add_test(function test_attributes() { 1.37 + let uri = "http://foo.com/bar/baz"; 1.38 + let request = new RESTRequest(uri); 1.39 + 1.40 + do_check_true(request.uri instanceof Ci.nsIURI); 1.41 + do_check_eq(request.uri.spec, uri); 1.42 + do_check_eq(request.response, null); 1.43 + do_check_eq(request.status, request.NOT_SENT); 1.44 + let expectedLoadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE | 1.45 + Ci.nsIRequest.INHIBIT_CACHING | 1.46 + Ci.nsIRequest.LOAD_ANONYMOUS; 1.47 + do_check_eq(request.loadFlags, expectedLoadFlags); 1.48 + 1.49 + run_next_test(); 1.50 +}); 1.51 + 1.52 +/** 1.53 + * Verify that a proxy auth redirect doesn't break us. This has to be the first 1.54 + * request made in the file! 1.55 + */ 1.56 +add_test(function test_proxy_auth_redirect() { 1.57 + let pacFetched = false; 1.58 + function pacHandler(metadata, response) { 1.59 + pacFetched = true; 1.60 + let body = 'function FindProxyForURL(url, host) { return "DIRECT"; }'; 1.61 + response.setStatusLine(metadata.httpVersion, 200, "OK"); 1.62 + response.setHeader("Content-Type", "application/x-ns-proxy-autoconfig", false); 1.63 + response.bodyOutputStream.write(body, body.length); 1.64 + } 1.65 + 1.66 + let fetched = false; 1.67 + function original(metadata, response) { 1.68 + fetched = true; 1.69 + let body = "TADA!"; 1.70 + response.setStatusLine(metadata.httpVersion, 200, "OK"); 1.71 + response.bodyOutputStream.write(body, body.length); 1.72 + } 1.73 + 1.74 + let server = httpd_setup({ 1.75 + "/original": original, 1.76 + "/pac3": pacHandler 1.77 + }); 1.78 + PACSystemSettings.PACURI = server.baseURI + "/pac3"; 1.79 + installFakePAC(); 1.80 + 1.81 + let res = new RESTRequest(server.baseURI + "/original"); 1.82 + res.get(function (error) { 1.83 + do_check_true(pacFetched); 1.84 + do_check_true(fetched); 1.85 + do_check_true(!error); 1.86 + do_check_true(this.response.success); 1.87 + do_check_eq("TADA!", this.response.body); 1.88 + uninstallFakePAC(); 1.89 + server.stop(run_next_test); 1.90 + }); 1.91 +}); 1.92 + 1.93 +/** 1.94 + * Ensure that failures that cause asyncOpen to throw 1.95 + * result in callbacks being invoked. 1.96 + * Bug 826086. 1.97 + */ 1.98 +add_test(function test_forbidden_port() { 1.99 + let request = new RESTRequest("http://localhost:6000/"); 1.100 + request.get(function(error) { 1.101 + if (!error) { 1.102 + do_throw("Should have got an error."); 1.103 + } 1.104 + do_check_eq(error.result, Components.results.NS_ERROR_PORT_ACCESS_NOT_ALLOWED); 1.105 + run_next_test(); 1.106 + }); 1.107 +}); 1.108 + 1.109 +/** 1.110 + * Demonstrate API short-hand: create a request and dispatch it immediately. 1.111 + */ 1.112 +add_test(function test_simple_get() { 1.113 + let handler = httpd_handler(200, "OK", "Huzzah!"); 1.114 + let server = httpd_setup({"/resource": handler}); 1.115 + 1.116 + let request = new RESTRequest(server.baseURI + "/resource").get(function (error) { 1.117 + do_check_eq(error, null); 1.118 + 1.119 + do_check_eq(this.status, this.COMPLETED); 1.120 + do_check_true(this.response.success); 1.121 + do_check_eq(this.response.status, 200); 1.122 + do_check_eq(this.response.body, "Huzzah!"); 1.123 + 1.124 + server.stop(run_next_test); 1.125 + }); 1.126 + do_check_eq(request.status, request.SENT); 1.127 + do_check_eq(request.method, "GET"); 1.128 +}); 1.129 + 1.130 +/** 1.131 + * Test HTTP GET with all bells and whistles. 1.132 + */ 1.133 +add_test(function test_get() { 1.134 + let handler = httpd_handler(200, "OK", "Huzzah!"); 1.135 + let server = httpd_setup({"/resource": handler}); 1.136 + 1.137 + let request = new RESTRequest(server.baseURI + "/resource"); 1.138 + do_check_eq(request.status, request.NOT_SENT); 1.139 + 1.140 + request.onProgress = request.onComplete = function () { 1.141 + do_throw("This function should have been overwritten!"); 1.142 + }; 1.143 + 1.144 + let onProgress_called = false; 1.145 + function onProgress() { 1.146 + onProgress_called = true; 1.147 + do_check_eq(this.status, request.IN_PROGRESS); 1.148 + do_check_true(this.response.body.length > 0); 1.149 + 1.150 + do_check_true(!!(this.channel.loadFlags & Ci.nsIRequest.LOAD_BYPASS_CACHE)); 1.151 + do_check_true(!!(this.channel.loadFlags & Ci.nsIRequest.INHIBIT_CACHING)); 1.152 + }; 1.153 + 1.154 + function onComplete(error) { 1.155 + do_check_eq(error, null); 1.156 + 1.157 + do_check_eq(this.status, this.COMPLETED); 1.158 + do_check_true(this.response.success); 1.159 + do_check_eq(this.response.status, 200); 1.160 + do_check_eq(this.response.body, "Huzzah!"); 1.161 + do_check_eq(handler.request.method, "GET"); 1.162 + 1.163 + do_check_true(onProgress_called); 1.164 + CommonUtils.nextTick(function () { 1.165 + do_check_eq(request.onComplete, null); 1.166 + do_check_eq(request.onProgress, null); 1.167 + server.stop(run_next_test); 1.168 + }); 1.169 + }; 1.170 + 1.171 + do_check_eq(request.get(onComplete, onProgress), request); 1.172 + do_check_eq(request.status, request.SENT); 1.173 + do_check_eq(request.method, "GET"); 1.174 + do_check_throws(function () { 1.175 + request.get(); 1.176 + }); 1.177 +}); 1.178 + 1.179 +/** 1.180 + * Test HTTP GET with UTF-8 content, and custom Content-Type. 1.181 + */ 1.182 +add_test(function test_get_utf8() { 1.183 + let response = "Hello World or Καλημέρα κόσμε or こんにちは 世界"; 1.184 + 1.185 + let contentType = "text/plain"; 1.186 + let charset = true; 1.187 + let charsetSuffix = "; charset=UTF-8"; 1.188 + 1.189 + let server = httpd_setup({"/resource": function(req, res) { 1.190 + res.setStatusLine(req.httpVersion, 200, "OK"); 1.191 + res.setHeader("Content-Type", contentType + (charset ? charsetSuffix : "")); 1.192 + 1.193 + let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] 1.194 + .createInstance(Ci.nsIConverterOutputStream); 1.195 + converter.init(res.bodyOutputStream, "UTF-8", 0, 0x0000); 1.196 + converter.writeString(response); 1.197 + converter.close(); 1.198 + }}); 1.199 + 1.200 + // Check if charset in Content-Type is propertly interpreted. 1.201 + let request1 = new RESTRequest(server.baseURI + "/resource"); 1.202 + request1.get(function(error) { 1.203 + do_check_null(error); 1.204 + 1.205 + do_check_eq(request1.response.status, 200); 1.206 + do_check_eq(request1.response.body, response); 1.207 + do_check_eq(request1.response.headers["content-type"], 1.208 + contentType + charsetSuffix); 1.209 + 1.210 + // Check that we default to UTF-8 if Content-Type doesn't have a charset. 1.211 + charset = false; 1.212 + let request2 = new RESTRequest(server.baseURI + "/resource"); 1.213 + request2.get(function(error) { 1.214 + do_check_null(error); 1.215 + 1.216 + do_check_eq(request2.response.status, 200); 1.217 + do_check_eq(request2.response.body, response); 1.218 + do_check_eq(request2.response.headers["content-type"], contentType); 1.219 + do_check_eq(request2.response.charset, "utf-8"); 1.220 + 1.221 + server.stop(run_next_test); 1.222 + }); 1.223 + }); 1.224 +}); 1.225 + 1.226 +/** 1.227 + * Test more variations of charset handling. 1.228 + */ 1.229 +add_test(function test_charsets() { 1.230 + let response = "Hello World, I can't speak Russian"; 1.231 + 1.232 + let contentType = "text/plain"; 1.233 + let charset = true; 1.234 + let charsetSuffix = "; charset=us-ascii"; 1.235 + 1.236 + let server = httpd_setup({"/resource": function(req, res) { 1.237 + res.setStatusLine(req.httpVersion, 200, "OK"); 1.238 + res.setHeader("Content-Type", contentType + (charset ? charsetSuffix : "")); 1.239 + 1.240 + let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] 1.241 + .createInstance(Ci.nsIConverterOutputStream); 1.242 + converter.init(res.bodyOutputStream, "us-ascii", 0, 0x0000); 1.243 + converter.writeString(response); 1.244 + converter.close(); 1.245 + }}); 1.246 + 1.247 + // Check that provided charset overrides hint. 1.248 + let request1 = new RESTRequest(server.baseURI + "/resource"); 1.249 + request1.charset = "not-a-charset"; 1.250 + request1.get(function(error) { 1.251 + do_check_null(error); 1.252 + 1.253 + do_check_eq(request1.response.status, 200); 1.254 + do_check_eq(request1.response.body, response); 1.255 + do_check_eq(request1.response.headers["content-type"], 1.256 + contentType + charsetSuffix); 1.257 + do_check_eq(request1.response.charset, "us-ascii"); 1.258 + 1.259 + // Check that hint is used if Content-Type doesn't have a charset. 1.260 + charset = false; 1.261 + let request2 = new RESTRequest(server.baseURI + "/resource"); 1.262 + request2.charset = "us-ascii"; 1.263 + request2.get(function(error) { 1.264 + do_check_null(error); 1.265 + 1.266 + do_check_eq(request2.response.status, 200); 1.267 + do_check_eq(request2.response.body, response); 1.268 + do_check_eq(request2.response.headers["content-type"], contentType); 1.269 + do_check_eq(request2.response.charset, "us-ascii"); 1.270 + 1.271 + server.stop(run_next_test); 1.272 + }); 1.273 + }); 1.274 +}); 1.275 + 1.276 +/** 1.277 + * Test HTTP PUT with a simple string argument and default Content-Type. 1.278 + */ 1.279 +add_test(function test_put() { 1.280 + let handler = httpd_handler(200, "OK", "Got it!"); 1.281 + let server = httpd_setup({"/resource": handler}); 1.282 + 1.283 + let request = new RESTRequest(server.baseURI + "/resource"); 1.284 + do_check_eq(request.status, request.NOT_SENT); 1.285 + 1.286 + request.onProgress = request.onComplete = function () { 1.287 + do_throw("This function should have been overwritten!"); 1.288 + }; 1.289 + 1.290 + let onProgress_called = false; 1.291 + function onProgress() { 1.292 + onProgress_called = true; 1.293 + do_check_eq(this.status, request.IN_PROGRESS); 1.294 + do_check_true(this.response.body.length > 0); 1.295 + }; 1.296 + 1.297 + function onComplete(error) { 1.298 + do_check_eq(error, null); 1.299 + 1.300 + do_check_eq(this.status, this.COMPLETED); 1.301 + do_check_true(this.response.success); 1.302 + do_check_eq(this.response.status, 200); 1.303 + do_check_eq(this.response.body, "Got it!"); 1.304 + 1.305 + do_check_eq(handler.request.method, "PUT"); 1.306 + do_check_eq(handler.request.body, "Hullo?"); 1.307 + do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); 1.308 + 1.309 + do_check_true(onProgress_called); 1.310 + CommonUtils.nextTick(function () { 1.311 + do_check_eq(request.onComplete, null); 1.312 + do_check_eq(request.onProgress, null); 1.313 + server.stop(run_next_test); 1.314 + }); 1.315 + }; 1.316 + 1.317 + do_check_eq(request.put("Hullo?", onComplete, onProgress), request); 1.318 + do_check_eq(request.status, request.SENT); 1.319 + do_check_eq(request.method, "PUT"); 1.320 + do_check_throws(function () { 1.321 + request.put("Hai!"); 1.322 + }); 1.323 +}); 1.324 + 1.325 +/** 1.326 + * Test HTTP POST with a simple string argument and default Content-Type. 1.327 + */ 1.328 +add_test(function test_post() { 1.329 + let handler = httpd_handler(200, "OK", "Got it!"); 1.330 + let server = httpd_setup({"/resource": handler}); 1.331 + 1.332 + let request = new RESTRequest(server.baseURI + "/resource"); 1.333 + do_check_eq(request.status, request.NOT_SENT); 1.334 + 1.335 + request.onProgress = request.onComplete = function () { 1.336 + do_throw("This function should have been overwritten!"); 1.337 + }; 1.338 + 1.339 + let onProgress_called = false; 1.340 + function onProgress() { 1.341 + onProgress_called = true; 1.342 + do_check_eq(this.status, request.IN_PROGRESS); 1.343 + do_check_true(this.response.body.length > 0); 1.344 + }; 1.345 + 1.346 + function onComplete(error) { 1.347 + do_check_eq(error, null); 1.348 + 1.349 + do_check_eq(this.status, this.COMPLETED); 1.350 + do_check_true(this.response.success); 1.351 + do_check_eq(this.response.status, 200); 1.352 + do_check_eq(this.response.body, "Got it!"); 1.353 + 1.354 + do_check_eq(handler.request.method, "POST"); 1.355 + do_check_eq(handler.request.body, "Hullo?"); 1.356 + do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); 1.357 + 1.358 + do_check_true(onProgress_called); 1.359 + CommonUtils.nextTick(function () { 1.360 + do_check_eq(request.onComplete, null); 1.361 + do_check_eq(request.onProgress, null); 1.362 + server.stop(run_next_test); 1.363 + }); 1.364 + }; 1.365 + 1.366 + do_check_eq(request.post("Hullo?", onComplete, onProgress), request); 1.367 + do_check_eq(request.status, request.SENT); 1.368 + do_check_eq(request.method, "POST"); 1.369 + do_check_throws(function () { 1.370 + request.post("Hai!"); 1.371 + }); 1.372 +}); 1.373 + 1.374 +/** 1.375 + * Test HTTP DELETE. 1.376 + */ 1.377 +add_test(function test_delete() { 1.378 + let handler = httpd_handler(200, "OK", "Got it!"); 1.379 + let server = httpd_setup({"/resource": handler}); 1.380 + 1.381 + let request = new RESTRequest(server.baseURI + "/resource"); 1.382 + do_check_eq(request.status, request.NOT_SENT); 1.383 + 1.384 + request.onProgress = request.onComplete = function () { 1.385 + do_throw("This function should have been overwritten!"); 1.386 + }; 1.387 + 1.388 + let onProgress_called = false; 1.389 + function onProgress() { 1.390 + onProgress_called = true; 1.391 + do_check_eq(this.status, request.IN_PROGRESS); 1.392 + do_check_true(this.response.body.length > 0); 1.393 + }; 1.394 + 1.395 + function onComplete(error) { 1.396 + do_check_eq(error, null); 1.397 + 1.398 + do_check_eq(this.status, this.COMPLETED); 1.399 + do_check_true(this.response.success); 1.400 + do_check_eq(this.response.status, 200); 1.401 + do_check_eq(this.response.body, "Got it!"); 1.402 + do_check_eq(handler.request.method, "DELETE"); 1.403 + 1.404 + do_check_true(onProgress_called); 1.405 + CommonUtils.nextTick(function () { 1.406 + do_check_eq(request.onComplete, null); 1.407 + do_check_eq(request.onProgress, null); 1.408 + server.stop(run_next_test); 1.409 + }); 1.410 + }; 1.411 + 1.412 + do_check_eq(request.delete(onComplete, onProgress), request); 1.413 + do_check_eq(request.status, request.SENT); 1.414 + do_check_eq(request.method, "DELETE"); 1.415 + do_check_throws(function () { 1.416 + request.delete(); 1.417 + }); 1.418 +}); 1.419 + 1.420 +/** 1.421 + * Test an HTTP response with a non-200 status code. 1.422 + */ 1.423 +add_test(function test_get_404() { 1.424 + let handler = httpd_handler(404, "Not Found", "Cannae find it!"); 1.425 + let server = httpd_setup({"/resource": handler}); 1.426 + 1.427 + let request = new RESTRequest(server.baseURI + "/resource"); 1.428 + request.get(function (error) { 1.429 + do_check_eq(error, null); 1.430 + 1.431 + do_check_eq(this.status, this.COMPLETED); 1.432 + do_check_false(this.response.success); 1.433 + do_check_eq(this.response.status, 404); 1.434 + do_check_eq(this.response.body, "Cannae find it!"); 1.435 + 1.436 + server.stop(run_next_test); 1.437 + }); 1.438 +}); 1.439 + 1.440 +/** 1.441 + * The 'data' argument to PUT, if not a string already, is automatically 1.442 + * stringified as JSON. 1.443 + */ 1.444 +add_test(function test_put_json() { 1.445 + let handler = httpd_handler(200, "OK"); 1.446 + let server = httpd_setup({"/resource": handler}); 1.447 + 1.448 + let sample_data = { 1.449 + some: "sample_data", 1.450 + injson: "format", 1.451 + number: 42 1.452 + }; 1.453 + let request = new RESTRequest(server.baseURI + "/resource"); 1.454 + request.put(sample_data, function (error) { 1.455 + do_check_eq(error, null); 1.456 + 1.457 + do_check_eq(this.status, this.COMPLETED); 1.458 + do_check_true(this.response.success); 1.459 + do_check_eq(this.response.status, 200); 1.460 + do_check_eq(this.response.body, ""); 1.461 + 1.462 + do_check_eq(handler.request.method, "PUT"); 1.463 + do_check_eq(handler.request.body, JSON.stringify(sample_data)); 1.464 + do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); 1.465 + 1.466 + server.stop(run_next_test); 1.467 + }); 1.468 +}); 1.469 + 1.470 +/** 1.471 + * The 'data' argument to POST, if not a string already, is automatically 1.472 + * stringified as JSON. 1.473 + */ 1.474 +add_test(function test_post_json() { 1.475 + let handler = httpd_handler(200, "OK"); 1.476 + let server = httpd_setup({"/resource": handler}); 1.477 + 1.478 + let sample_data = { 1.479 + some: "sample_data", 1.480 + injson: "format", 1.481 + number: 42 1.482 + }; 1.483 + let request = new RESTRequest(server.baseURI + "/resource"); 1.484 + request.post(sample_data, function (error) { 1.485 + do_check_eq(error, null); 1.486 + 1.487 + do_check_eq(this.status, this.COMPLETED); 1.488 + do_check_true(this.response.success); 1.489 + do_check_eq(this.response.status, 200); 1.490 + do_check_eq(this.response.body, ""); 1.491 + 1.492 + do_check_eq(handler.request.method, "POST"); 1.493 + do_check_eq(handler.request.body, JSON.stringify(sample_data)); 1.494 + do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); 1.495 + 1.496 + server.stop(run_next_test); 1.497 + }); 1.498 +}); 1.499 + 1.500 +/** 1.501 + * HTTP PUT with a custom Content-Type header. 1.502 + */ 1.503 +add_test(function test_put_override_content_type() { 1.504 + let handler = httpd_handler(200, "OK"); 1.505 + let server = httpd_setup({"/resource": handler}); 1.506 + 1.507 + let request = new RESTRequest(server.baseURI + "/resource"); 1.508 + request.setHeader("Content-Type", "application/lolcat"); 1.509 + request.put("O HAI!!1!", function (error) { 1.510 + do_check_eq(error, null); 1.511 + 1.512 + do_check_eq(this.status, this.COMPLETED); 1.513 + do_check_true(this.response.success); 1.514 + do_check_eq(this.response.status, 200); 1.515 + do_check_eq(this.response.body, ""); 1.516 + 1.517 + do_check_eq(handler.request.method, "PUT"); 1.518 + do_check_eq(handler.request.body, "O HAI!!1!"); 1.519 + do_check_eq(handler.request.getHeader("Content-Type"), "application/lolcat"); 1.520 + 1.521 + server.stop(run_next_test); 1.522 + }); 1.523 +}); 1.524 + 1.525 +/** 1.526 + * HTTP POST with a custom Content-Type header. 1.527 + */ 1.528 +add_test(function test_post_override_content_type() { 1.529 + let handler = httpd_handler(200, "OK"); 1.530 + let server = httpd_setup({"/resource": handler}); 1.531 + 1.532 + let request = new RESTRequest(server.baseURI + "/resource"); 1.533 + request.setHeader("Content-Type", "application/lolcat"); 1.534 + request.post("O HAI!!1!", function (error) { 1.535 + do_check_eq(error, null); 1.536 + 1.537 + do_check_eq(this.status, this.COMPLETED); 1.538 + do_check_true(this.response.success); 1.539 + do_check_eq(this.response.status, 200); 1.540 + do_check_eq(this.response.body, ""); 1.541 + 1.542 + do_check_eq(handler.request.method, "POST"); 1.543 + do_check_eq(handler.request.body, "O HAI!!1!"); 1.544 + do_check_eq(handler.request.getHeader("Content-Type"), "application/lolcat"); 1.545 + 1.546 + server.stop(run_next_test); 1.547 + }); 1.548 +}); 1.549 + 1.550 +/** 1.551 + * No special headers are sent by default on a GET request. 1.552 + */ 1.553 +add_test(function test_get_no_headers() { 1.554 + let handler = httpd_handler(200, "OK"); 1.555 + let server = httpd_setup({"/resource": handler}); 1.556 + 1.557 + let ignore_headers = ["host", "user-agent", "accept", "accept-language", 1.558 + "accept-encoding", "accept-charset", "keep-alive", 1.559 + "connection", "pragma", "cache-control", 1.560 + "content-length"]; 1.561 + 1.562 + new RESTRequest(server.baseURI + "/resource").get(function (error) { 1.563 + do_check_eq(error, null); 1.564 + 1.565 + do_check_eq(this.response.status, 200); 1.566 + do_check_eq(this.response.body, ""); 1.567 + 1.568 + let server_headers = handler.request.headers; 1.569 + while (server_headers.hasMoreElements()) { 1.570 + let header = server_headers.getNext().toString(); 1.571 + if (ignore_headers.indexOf(header) == -1) { 1.572 + do_throw("Got unexpected header!"); 1.573 + } 1.574 + } 1.575 + 1.576 + server.stop(run_next_test); 1.577 + }); 1.578 +}); 1.579 + 1.580 +/** 1.581 + * Test changing the URI after having created the request. 1.582 + */ 1.583 +add_test(function test_changing_uri() { 1.584 + let handler = httpd_handler(200, "OK"); 1.585 + let server = httpd_setup({"/resource": handler}); 1.586 + 1.587 + let request = new RESTRequest("http://localhost:1234/the-wrong-resource"); 1.588 + request.uri = CommonUtils.makeURI(server.baseURI + "/resource"); 1.589 + request.get(function (error) { 1.590 + do_check_eq(error, null); 1.591 + do_check_eq(this.response.status, 200); 1.592 + server.stop(run_next_test); 1.593 + }); 1.594 +}); 1.595 + 1.596 +/** 1.597 + * Test setting HTTP request headers. 1.598 + */ 1.599 +add_test(function test_request_setHeader() { 1.600 + let handler = httpd_handler(200, "OK"); 1.601 + let server = httpd_setup({"/resource": handler}); 1.602 + 1.603 + let request = new RESTRequest(server.baseURI + "/resource"); 1.604 + 1.605 + request.setHeader("X-What-Is-Weave", "awesome"); 1.606 + request.setHeader("X-WHAT-is-Weave", "more awesomer"); 1.607 + request.setHeader("Another-Header", "Hello World"); 1.608 + 1.609 + request.get(function (error) { 1.610 + do_check_eq(error, null); 1.611 + 1.612 + do_check_eq(this.response.status, 200); 1.613 + do_check_eq(this.response.body, ""); 1.614 + 1.615 + do_check_eq(handler.request.getHeader("X-What-Is-Weave"), "more awesomer"); 1.616 + do_check_eq(handler.request.getHeader("another-header"), "Hello World"); 1.617 + 1.618 + server.stop(run_next_test); 1.619 + }); 1.620 +}); 1.621 + 1.622 +/** 1.623 + * Test receiving HTTP response headers. 1.624 + */ 1.625 +add_test(function test_response_headers() { 1.626 + function handler(request, response) { 1.627 + response.setHeader("X-What-Is-Weave", "awesome"); 1.628 + response.setHeader("Another-Header", "Hello World"); 1.629 + response.setStatusLine(request.httpVersion, 200, "OK"); 1.630 + } 1.631 + let server = httpd_setup({"/resource": handler}); 1.632 + let request = new RESTRequest(server.baseURI + "/resource"); 1.633 + 1.634 + request.get(function (error) { 1.635 + do_check_eq(error, null); 1.636 + 1.637 + do_check_eq(this.response.status, 200); 1.638 + do_check_eq(this.response.body, ""); 1.639 + 1.640 + do_check_eq(this.response.headers["x-what-is-weave"], "awesome"); 1.641 + do_check_eq(this.response.headers["another-header"], "Hello World"); 1.642 + 1.643 + server.stop(run_next_test); 1.644 + }); 1.645 +}); 1.646 + 1.647 +/** 1.648 + * The onComplete() handler gets called in case of any network errors 1.649 + * (e.g. NS_ERROR_CONNECTION_REFUSED). 1.650 + */ 1.651 +add_test(function test_connection_refused() { 1.652 + let request = new RESTRequest("http://localhost:1234/resource"); 1.653 + request.onProgress = function onProgress() { 1.654 + do_throw("Shouldn't have called request.onProgress()!"); 1.655 + }; 1.656 + request.get(function (error) { 1.657 + do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED); 1.658 + do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED"); 1.659 + do_check_eq(this.status, this.COMPLETED); 1.660 + run_next_test(); 1.661 + }); 1.662 + do_check_eq(request.status, request.SENT); 1.663 +}); 1.664 + 1.665 +/** 1.666 + * Abort a request that just sent off. 1.667 + */ 1.668 +add_test(function test_abort() { 1.669 + function handler() { 1.670 + do_throw("Shouldn't have gotten here!"); 1.671 + } 1.672 + let server = httpd_setup({"/resource": handler}); 1.673 + 1.674 + let request = new RESTRequest(server.baseURI + "/resource"); 1.675 + 1.676 + // Aborting a request that hasn't been sent yet is pointless and will throw. 1.677 + do_check_throws(function () { 1.678 + request.abort(); 1.679 + }); 1.680 + 1.681 + request.onProgress = request.onComplete = function () { 1.682 + do_throw("Shouldn't have gotten here!"); 1.683 + }; 1.684 + request.get(); 1.685 + request.abort(); 1.686 + 1.687 + // Aborting an already aborted request is pointless and will throw. 1.688 + do_check_throws(function () { 1.689 + request.abort(); 1.690 + }); 1.691 + 1.692 + do_check_eq(request.status, request.ABORTED); 1.693 + CommonUtils.nextTick(function () { 1.694 + server.stop(run_next_test); 1.695 + }); 1.696 +}); 1.697 + 1.698 +/** 1.699 + * A non-zero 'timeout' property specifies the amount of seconds to wait after 1.700 + * channel activity until the request is automatically canceled. 1.701 + */ 1.702 +add_test(function test_timeout() { 1.703 + let server = new HttpServer(); 1.704 + let server_connection; 1.705 + server._handler.handleResponse = function(connection) { 1.706 + // This is a handler that doesn't do anything, just keeps the connection 1.707 + // open, thereby mimicking a timing out connection. We keep a reference to 1.708 + // the open connection for later so it can be properly disposed of. That's 1.709 + // why you really only want to make one HTTP request to this server ever. 1.710 + server_connection = connection; 1.711 + }; 1.712 + server.start(); 1.713 + let identity = server.identity; 1.714 + let uri = identity.primaryScheme + "://" + identity.primaryHost + ":" + 1.715 + identity.primaryPort; 1.716 + 1.717 + let request = new RESTRequest(uri + "/resource"); 1.718 + request.timeout = 0.1; // 100 milliseconds 1.719 + request.get(function (error) { 1.720 + do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT); 1.721 + do_check_eq(this.status, this.ABORTED); 1.722 + 1.723 + // server_connection is undefined on the Android emulator for reasons 1.724 + // unknown. Yet, we still get here. If this test is refactored, we should 1.725 + // investigate the reason why the above callback is behaving differently. 1.726 + if (server_connection) { 1.727 + _("Closing connection."); 1.728 + server_connection.close(); 1.729 + } 1.730 + 1.731 + _("Shutting down server."); 1.732 + server.stop(run_next_test); 1.733 + }); 1.734 +}); 1.735 + 1.736 +/** 1.737 + * An exception thrown in 'onProgress' propagates to the 'onComplete' handler. 1.738 + */ 1.739 +add_test(function test_exception_in_onProgress() { 1.740 + let handler = httpd_handler(200, "OK", "Foobar"); 1.741 + let server = httpd_setup({"/resource": handler}); 1.742 + 1.743 + let request = new RESTRequest(server.baseURI + "/resource"); 1.744 + request.onProgress = function onProgress() { 1.745 + it.does.not.exist(); 1.746 + }; 1.747 + request.get(function onComplete(error) { 1.748 + do_check_eq(error, "ReferenceError: it is not defined"); 1.749 + do_check_eq(this.status, this.ABORTED); 1.750 + 1.751 + server.stop(run_next_test); 1.752 + }); 1.753 +}); 1.754 + 1.755 +add_test(function test_new_channel() { 1.756 + _("Ensure a redirect to a new channel is handled properly."); 1.757 + 1.758 + function checkUA(metadata) { 1.759 + let ua = metadata.getHeader("User-Agent"); 1.760 + _("User-Agent is " + ua); 1.761 + do_check_eq("foo bar", ua); 1.762 + } 1.763 + 1.764 + let redirectRequested = false; 1.765 + let redirectURL; 1.766 + function redirectHandler(metadata, response) { 1.767 + checkUA(metadata); 1.768 + redirectRequested = true; 1.769 + 1.770 + let body = "Redirecting"; 1.771 + response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT"); 1.772 + response.setHeader("Location", redirectURL); 1.773 + response.bodyOutputStream.write(body, body.length); 1.774 + } 1.775 + 1.776 + let resourceRequested = false; 1.777 + function resourceHandler(metadata, response) { 1.778 + checkUA(metadata); 1.779 + resourceRequested = true; 1.780 + 1.781 + let body = "Test"; 1.782 + response.setHeader("Content-Type", "text/plain"); 1.783 + response.bodyOutputStream.write(body, body.length); 1.784 + } 1.785 + 1.786 + let server1 = httpd_setup({"/redirect": redirectHandler}); 1.787 + let server2 = httpd_setup({"/resource": resourceHandler}); 1.788 + redirectURL = server2.baseURI + "/resource"; 1.789 + 1.790 + function advance() { 1.791 + server1.stop(function () { 1.792 + server2.stop(run_next_test); 1.793 + }); 1.794 + } 1.795 + 1.796 + let request = new RESTRequest(server1.baseURI + "/redirect"); 1.797 + request.setHeader("User-Agent", "foo bar"); 1.798 + 1.799 + // Swizzle in our own fakery, because this redirect is neither 1.800 + // internal nor URI-preserving. RESTRequest's policy is to only 1.801 + // copy headers under certain circumstances. 1.802 + let protoMethod = request.shouldCopyOnRedirect; 1.803 + request.shouldCopyOnRedirect = function wrapped(o, n, f) { 1.804 + // Check the default policy. 1.805 + do_check_false(protoMethod.call(this, o, n, f)); 1.806 + return true; 1.807 + }; 1.808 + 1.809 + request.get(function onComplete(error) { 1.810 + let response = this.response; 1.811 + 1.812 + do_check_eq(200, response.status); 1.813 + do_check_eq("Test", response.body); 1.814 + do_check_true(redirectRequested); 1.815 + do_check_true(resourceRequested); 1.816 + 1.817 + advance(); 1.818 + }); 1.819 +}); 1.820 + 1.821 +add_test(function test_not_sending_cookie() { 1.822 + function handler(metadata, response) { 1.823 + let body = "COOKIE!"; 1.824 + response.setStatusLine(metadata.httpVersion, 200, "OK"); 1.825 + response.bodyOutputStream.write(body, body.length); 1.826 + do_check_false(metadata.hasHeader("Cookie")); 1.827 + } 1.828 + let server = httpd_setup({"/test": handler}); 1.829 + 1.830 + let cookieSer = Cc["@mozilla.org/cookieService;1"] 1.831 + .getService(Ci.nsICookieService); 1.832 + let uri = CommonUtils.makeURI(server.baseURI); 1.833 + cookieSer.setCookieString(uri, null, "test=test; path=/;", null); 1.834 + 1.835 + let res = new RESTRequest(server.baseURI + "/test"); 1.836 + res.get(function (error) { 1.837 + do_check_null(error); 1.838 + do_check_true(this.response.success); 1.839 + do_check_eq("COOKIE!", this.response.body); 1.840 + server.stop(run_next_test); 1.841 + }); 1.842 +}); 1.843 +