michael@0: /* Any copyright is dedicated to the Public Domain. michael@0: http://creativecommons.org/publicdomain/zero/1.0/ */ michael@0: michael@0: "use strict"; michael@0: michael@0: Cu.import("resource://gre/modules/NetUtil.jsm"); michael@0: Cu.import("resource://gre/modules/Log.jsm"); michael@0: Cu.import("resource://services-common/rest.js"); michael@0: Cu.import("resource://services-common/utils.js"); michael@0: michael@0: function run_test() { michael@0: Log.repository.getLogger("Services.Common.RESTRequest").level = michael@0: Log.Level.Trace; michael@0: initTestLogging("Trace"); michael@0: michael@0: run_next_test(); michael@0: } michael@0: michael@0: /** michael@0: * Initializing a RESTRequest with an invalid URI throws michael@0: * NS_ERROR_MALFORMED_URI. michael@0: */ michael@0: add_test(function test_invalid_uri() { michael@0: do_check_throws(function() { michael@0: new RESTRequest("an invalid URI"); michael@0: }, Cr.NS_ERROR_MALFORMED_URI); michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify initial values for attributes. michael@0: */ michael@0: add_test(function test_attributes() { michael@0: let uri = "http://foo.com/bar/baz"; michael@0: let request = new RESTRequest(uri); michael@0: michael@0: do_check_true(request.uri instanceof Ci.nsIURI); michael@0: do_check_eq(request.uri.spec, uri); michael@0: do_check_eq(request.response, null); michael@0: do_check_eq(request.status, request.NOT_SENT); michael@0: let expectedLoadFlags = Ci.nsIRequest.LOAD_BYPASS_CACHE | michael@0: Ci.nsIRequest.INHIBIT_CACHING | michael@0: Ci.nsIRequest.LOAD_ANONYMOUS; michael@0: do_check_eq(request.loadFlags, expectedLoadFlags); michael@0: michael@0: run_next_test(); michael@0: }); michael@0: michael@0: /** michael@0: * Verify that a proxy auth redirect doesn't break us. This has to be the first michael@0: * request made in the file! michael@0: */ michael@0: add_test(function test_proxy_auth_redirect() { michael@0: let pacFetched = false; michael@0: function pacHandler(metadata, response) { michael@0: pacFetched = true; michael@0: let body = 'function FindProxyForURL(url, host) { return "DIRECT"; }'; michael@0: response.setStatusLine(metadata.httpVersion, 200, "OK"); michael@0: response.setHeader("Content-Type", "application/x-ns-proxy-autoconfig", false); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: michael@0: let fetched = false; michael@0: function original(metadata, response) { michael@0: fetched = true; michael@0: let body = "TADA!"; michael@0: response.setStatusLine(metadata.httpVersion, 200, "OK"); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: michael@0: let server = httpd_setup({ michael@0: "/original": original, michael@0: "/pac3": pacHandler michael@0: }); michael@0: PACSystemSettings.PACURI = server.baseURI + "/pac3"; michael@0: installFakePAC(); michael@0: michael@0: let res = new RESTRequest(server.baseURI + "/original"); michael@0: res.get(function (error) { michael@0: do_check_true(pacFetched); michael@0: do_check_true(fetched); michael@0: do_check_true(!error); michael@0: do_check_true(this.response.success); michael@0: do_check_eq("TADA!", this.response.body); michael@0: uninstallFakePAC(); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Ensure that failures that cause asyncOpen to throw michael@0: * result in callbacks being invoked. michael@0: * Bug 826086. michael@0: */ michael@0: add_test(function test_forbidden_port() { michael@0: let request = new RESTRequest("http://localhost:6000/"); michael@0: request.get(function(error) { michael@0: if (!error) { michael@0: do_throw("Should have got an error."); michael@0: } michael@0: do_check_eq(error.result, Components.results.NS_ERROR_PORT_ACCESS_NOT_ALLOWED); michael@0: run_next_test(); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Demonstrate API short-hand: create a request and dispatch it immediately. michael@0: */ michael@0: add_test(function test_simple_get() { michael@0: let handler = httpd_handler(200, "OK", "Huzzah!"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource").get(function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, "Huzzah!"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: do_check_eq(request.status, request.SENT); michael@0: do_check_eq(request.method, "GET"); michael@0: }); michael@0: michael@0: /** michael@0: * Test HTTP GET with all bells and whistles. michael@0: */ michael@0: add_test(function test_get() { michael@0: let handler = httpd_handler(200, "OK", "Huzzah!"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: do_check_eq(request.status, request.NOT_SENT); michael@0: michael@0: request.onProgress = request.onComplete = function () { michael@0: do_throw("This function should have been overwritten!"); michael@0: }; michael@0: michael@0: let onProgress_called = false; michael@0: function onProgress() { michael@0: onProgress_called = true; michael@0: do_check_eq(this.status, request.IN_PROGRESS); michael@0: do_check_true(this.response.body.length > 0); michael@0: michael@0: do_check_true(!!(this.channel.loadFlags & Ci.nsIRequest.LOAD_BYPASS_CACHE)); michael@0: do_check_true(!!(this.channel.loadFlags & Ci.nsIRequest.INHIBIT_CACHING)); michael@0: }; michael@0: michael@0: function onComplete(error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, "Huzzah!"); michael@0: do_check_eq(handler.request.method, "GET"); michael@0: michael@0: do_check_true(onProgress_called); michael@0: CommonUtils.nextTick(function () { michael@0: do_check_eq(request.onComplete, null); michael@0: do_check_eq(request.onProgress, null); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }; michael@0: michael@0: do_check_eq(request.get(onComplete, onProgress), request); michael@0: do_check_eq(request.status, request.SENT); michael@0: do_check_eq(request.method, "GET"); michael@0: do_check_throws(function () { michael@0: request.get(); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test HTTP GET with UTF-8 content, and custom Content-Type. michael@0: */ michael@0: add_test(function test_get_utf8() { michael@0: let response = "Hello World or Καλημέρα κόσμε or こんにちは 世界"; michael@0: michael@0: let contentType = "text/plain"; michael@0: let charset = true; michael@0: let charsetSuffix = "; charset=UTF-8"; michael@0: michael@0: let server = httpd_setup({"/resource": function(req, res) { michael@0: res.setStatusLine(req.httpVersion, 200, "OK"); michael@0: res.setHeader("Content-Type", contentType + (charset ? charsetSuffix : "")); michael@0: michael@0: let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] michael@0: .createInstance(Ci.nsIConverterOutputStream); michael@0: converter.init(res.bodyOutputStream, "UTF-8", 0, 0x0000); michael@0: converter.writeString(response); michael@0: converter.close(); michael@0: }}); michael@0: michael@0: // Check if charset in Content-Type is propertly interpreted. michael@0: let request1 = new RESTRequest(server.baseURI + "/resource"); michael@0: request1.get(function(error) { michael@0: do_check_null(error); michael@0: michael@0: do_check_eq(request1.response.status, 200); michael@0: do_check_eq(request1.response.body, response); michael@0: do_check_eq(request1.response.headers["content-type"], michael@0: contentType + charsetSuffix); michael@0: michael@0: // Check that we default to UTF-8 if Content-Type doesn't have a charset. michael@0: charset = false; michael@0: let request2 = new RESTRequest(server.baseURI + "/resource"); michael@0: request2.get(function(error) { michael@0: do_check_null(error); michael@0: michael@0: do_check_eq(request2.response.status, 200); michael@0: do_check_eq(request2.response.body, response); michael@0: do_check_eq(request2.response.headers["content-type"], contentType); michael@0: do_check_eq(request2.response.charset, "utf-8"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test more variations of charset handling. michael@0: */ michael@0: add_test(function test_charsets() { michael@0: let response = "Hello World, I can't speak Russian"; michael@0: michael@0: let contentType = "text/plain"; michael@0: let charset = true; michael@0: let charsetSuffix = "; charset=us-ascii"; michael@0: michael@0: let server = httpd_setup({"/resource": function(req, res) { michael@0: res.setStatusLine(req.httpVersion, 200, "OK"); michael@0: res.setHeader("Content-Type", contentType + (charset ? charsetSuffix : "")); michael@0: michael@0: let converter = Cc["@mozilla.org/intl/converter-output-stream;1"] michael@0: .createInstance(Ci.nsIConverterOutputStream); michael@0: converter.init(res.bodyOutputStream, "us-ascii", 0, 0x0000); michael@0: converter.writeString(response); michael@0: converter.close(); michael@0: }}); michael@0: michael@0: // Check that provided charset overrides hint. michael@0: let request1 = new RESTRequest(server.baseURI + "/resource"); michael@0: request1.charset = "not-a-charset"; michael@0: request1.get(function(error) { michael@0: do_check_null(error); michael@0: michael@0: do_check_eq(request1.response.status, 200); michael@0: do_check_eq(request1.response.body, response); michael@0: do_check_eq(request1.response.headers["content-type"], michael@0: contentType + charsetSuffix); michael@0: do_check_eq(request1.response.charset, "us-ascii"); michael@0: michael@0: // Check that hint is used if Content-Type doesn't have a charset. michael@0: charset = false; michael@0: let request2 = new RESTRequest(server.baseURI + "/resource"); michael@0: request2.charset = "us-ascii"; michael@0: request2.get(function(error) { michael@0: do_check_null(error); michael@0: michael@0: do_check_eq(request2.response.status, 200); michael@0: do_check_eq(request2.response.body, response); michael@0: do_check_eq(request2.response.headers["content-type"], contentType); michael@0: do_check_eq(request2.response.charset, "us-ascii"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test HTTP PUT with a simple string argument and default Content-Type. michael@0: */ michael@0: add_test(function test_put() { michael@0: let handler = httpd_handler(200, "OK", "Got it!"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: do_check_eq(request.status, request.NOT_SENT); michael@0: michael@0: request.onProgress = request.onComplete = function () { michael@0: do_throw("This function should have been overwritten!"); michael@0: }; michael@0: michael@0: let onProgress_called = false; michael@0: function onProgress() { michael@0: onProgress_called = true; michael@0: do_check_eq(this.status, request.IN_PROGRESS); michael@0: do_check_true(this.response.body.length > 0); michael@0: }; michael@0: michael@0: function onComplete(error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, "Got it!"); michael@0: michael@0: do_check_eq(handler.request.method, "PUT"); michael@0: do_check_eq(handler.request.body, "Hullo?"); michael@0: do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); michael@0: michael@0: do_check_true(onProgress_called); michael@0: CommonUtils.nextTick(function () { michael@0: do_check_eq(request.onComplete, null); michael@0: do_check_eq(request.onProgress, null); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }; michael@0: michael@0: do_check_eq(request.put("Hullo?", onComplete, onProgress), request); michael@0: do_check_eq(request.status, request.SENT); michael@0: do_check_eq(request.method, "PUT"); michael@0: do_check_throws(function () { michael@0: request.put("Hai!"); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test HTTP POST with a simple string argument and default Content-Type. michael@0: */ michael@0: add_test(function test_post() { michael@0: let handler = httpd_handler(200, "OK", "Got it!"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: do_check_eq(request.status, request.NOT_SENT); michael@0: michael@0: request.onProgress = request.onComplete = function () { michael@0: do_throw("This function should have been overwritten!"); michael@0: }; michael@0: michael@0: let onProgress_called = false; michael@0: function onProgress() { michael@0: onProgress_called = true; michael@0: do_check_eq(this.status, request.IN_PROGRESS); michael@0: do_check_true(this.response.body.length > 0); michael@0: }; michael@0: michael@0: function onComplete(error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, "Got it!"); michael@0: michael@0: do_check_eq(handler.request.method, "POST"); michael@0: do_check_eq(handler.request.body, "Hullo?"); michael@0: do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); michael@0: michael@0: do_check_true(onProgress_called); michael@0: CommonUtils.nextTick(function () { michael@0: do_check_eq(request.onComplete, null); michael@0: do_check_eq(request.onProgress, null); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }; michael@0: michael@0: do_check_eq(request.post("Hullo?", onComplete, onProgress), request); michael@0: do_check_eq(request.status, request.SENT); michael@0: do_check_eq(request.method, "POST"); michael@0: do_check_throws(function () { michael@0: request.post("Hai!"); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test HTTP DELETE. michael@0: */ michael@0: add_test(function test_delete() { michael@0: let handler = httpd_handler(200, "OK", "Got it!"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: do_check_eq(request.status, request.NOT_SENT); michael@0: michael@0: request.onProgress = request.onComplete = function () { michael@0: do_throw("This function should have been overwritten!"); michael@0: }; michael@0: michael@0: let onProgress_called = false; michael@0: function onProgress() { michael@0: onProgress_called = true; michael@0: do_check_eq(this.status, request.IN_PROGRESS); michael@0: do_check_true(this.response.body.length > 0); michael@0: }; michael@0: michael@0: function onComplete(error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, "Got it!"); michael@0: do_check_eq(handler.request.method, "DELETE"); michael@0: michael@0: do_check_true(onProgress_called); michael@0: CommonUtils.nextTick(function () { michael@0: do_check_eq(request.onComplete, null); michael@0: do_check_eq(request.onProgress, null); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }; michael@0: michael@0: do_check_eq(request.delete(onComplete, onProgress), request); michael@0: do_check_eq(request.status, request.SENT); michael@0: do_check_eq(request.method, "DELETE"); michael@0: do_check_throws(function () { michael@0: request.delete(); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test an HTTP response with a non-200 status code. michael@0: */ michael@0: add_test(function test_get_404() { michael@0: let handler = httpd_handler(404, "Not Found", "Cannae find it!"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: request.get(function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_false(this.response.success); michael@0: do_check_eq(this.response.status, 404); michael@0: do_check_eq(this.response.body, "Cannae find it!"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * The 'data' argument to PUT, if not a string already, is automatically michael@0: * stringified as JSON. michael@0: */ michael@0: add_test(function test_put_json() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let sample_data = { michael@0: some: "sample_data", michael@0: injson: "format", michael@0: number: 42 michael@0: }; michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: request.put(sample_data, function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: do_check_eq(handler.request.method, "PUT"); michael@0: do_check_eq(handler.request.body, JSON.stringify(sample_data)); michael@0: do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * The 'data' argument to POST, if not a string already, is automatically michael@0: * stringified as JSON. michael@0: */ michael@0: add_test(function test_post_json() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let sample_data = { michael@0: some: "sample_data", michael@0: injson: "format", michael@0: number: 42 michael@0: }; michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: request.post(sample_data, function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: do_check_eq(handler.request.method, "POST"); michael@0: do_check_eq(handler.request.body, JSON.stringify(sample_data)); michael@0: do_check_eq(handler.request.getHeader("Content-Type"), "text/plain"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * HTTP PUT with a custom Content-Type header. michael@0: */ michael@0: add_test(function test_put_override_content_type() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: request.setHeader("Content-Type", "application/lolcat"); michael@0: request.put("O HAI!!1!", function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: do_check_eq(handler.request.method, "PUT"); michael@0: do_check_eq(handler.request.body, "O HAI!!1!"); michael@0: do_check_eq(handler.request.getHeader("Content-Type"), "application/lolcat"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * HTTP POST with a custom Content-Type header. michael@0: */ michael@0: add_test(function test_post_override_content_type() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: request.setHeader("Content-Type", "application/lolcat"); michael@0: request.post("O HAI!!1!", function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: do_check_true(this.response.success); michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: do_check_eq(handler.request.method, "POST"); michael@0: do_check_eq(handler.request.body, "O HAI!!1!"); michael@0: do_check_eq(handler.request.getHeader("Content-Type"), "application/lolcat"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * No special headers are sent by default on a GET request. michael@0: */ michael@0: add_test(function test_get_no_headers() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let ignore_headers = ["host", "user-agent", "accept", "accept-language", michael@0: "accept-encoding", "accept-charset", "keep-alive", michael@0: "connection", "pragma", "cache-control", michael@0: "content-length"]; michael@0: michael@0: new RESTRequest(server.baseURI + "/resource").get(function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: let server_headers = handler.request.headers; michael@0: while (server_headers.hasMoreElements()) { michael@0: let header = server_headers.getNext().toString(); michael@0: if (ignore_headers.indexOf(header) == -1) { michael@0: do_throw("Got unexpected header!"); michael@0: } michael@0: } michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test changing the URI after having created the request. michael@0: */ michael@0: add_test(function test_changing_uri() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest("http://localhost:1234/the-wrong-resource"); michael@0: request.uri = CommonUtils.makeURI(server.baseURI + "/resource"); michael@0: request.get(function (error) { michael@0: do_check_eq(error, null); michael@0: do_check_eq(this.response.status, 200); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test setting HTTP request headers. michael@0: */ michael@0: add_test(function test_request_setHeader() { michael@0: let handler = httpd_handler(200, "OK"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: michael@0: request.setHeader("X-What-Is-Weave", "awesome"); michael@0: request.setHeader("X-WHAT-is-Weave", "more awesomer"); michael@0: request.setHeader("Another-Header", "Hello World"); michael@0: michael@0: request.get(function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: do_check_eq(handler.request.getHeader("X-What-Is-Weave"), "more awesomer"); michael@0: do_check_eq(handler.request.getHeader("another-header"), "Hello World"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * Test receiving HTTP response headers. michael@0: */ michael@0: add_test(function test_response_headers() { michael@0: function handler(request, response) { michael@0: response.setHeader("X-What-Is-Weave", "awesome"); michael@0: response.setHeader("Another-Header", "Hello World"); michael@0: response.setStatusLine(request.httpVersion, 200, "OK"); michael@0: } michael@0: let server = httpd_setup({"/resource": handler}); michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: michael@0: request.get(function (error) { michael@0: do_check_eq(error, null); michael@0: michael@0: do_check_eq(this.response.status, 200); michael@0: do_check_eq(this.response.body, ""); michael@0: michael@0: do_check_eq(this.response.headers["x-what-is-weave"], "awesome"); michael@0: do_check_eq(this.response.headers["another-header"], "Hello World"); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * The onComplete() handler gets called in case of any network errors michael@0: * (e.g. NS_ERROR_CONNECTION_REFUSED). michael@0: */ michael@0: add_test(function test_connection_refused() { michael@0: let request = new RESTRequest("http://localhost:1234/resource"); michael@0: request.onProgress = function onProgress() { michael@0: do_throw("Shouldn't have called request.onProgress()!"); michael@0: }; michael@0: request.get(function (error) { michael@0: do_check_eq(error.result, Cr.NS_ERROR_CONNECTION_REFUSED); michael@0: do_check_eq(error.message, "NS_ERROR_CONNECTION_REFUSED"); michael@0: do_check_eq(this.status, this.COMPLETED); michael@0: run_next_test(); michael@0: }); michael@0: do_check_eq(request.status, request.SENT); michael@0: }); michael@0: michael@0: /** michael@0: * Abort a request that just sent off. michael@0: */ michael@0: add_test(function test_abort() { michael@0: function handler() { michael@0: do_throw("Shouldn't have gotten here!"); michael@0: } michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: michael@0: // Aborting a request that hasn't been sent yet is pointless and will throw. michael@0: do_check_throws(function () { michael@0: request.abort(); michael@0: }); michael@0: michael@0: request.onProgress = request.onComplete = function () { michael@0: do_throw("Shouldn't have gotten here!"); michael@0: }; michael@0: request.get(); michael@0: request.abort(); michael@0: michael@0: // Aborting an already aborted request is pointless and will throw. michael@0: do_check_throws(function () { michael@0: request.abort(); michael@0: }); michael@0: michael@0: do_check_eq(request.status, request.ABORTED); michael@0: CommonUtils.nextTick(function () { michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * A non-zero 'timeout' property specifies the amount of seconds to wait after michael@0: * channel activity until the request is automatically canceled. michael@0: */ michael@0: add_test(function test_timeout() { michael@0: let server = new HttpServer(); michael@0: let server_connection; michael@0: server._handler.handleResponse = function(connection) { michael@0: // This is a handler that doesn't do anything, just keeps the connection michael@0: // open, thereby mimicking a timing out connection. We keep a reference to michael@0: // the open connection for later so it can be properly disposed of. That's michael@0: // why you really only want to make one HTTP request to this server ever. michael@0: server_connection = connection; michael@0: }; michael@0: server.start(); michael@0: let identity = server.identity; michael@0: let uri = identity.primaryScheme + "://" + identity.primaryHost + ":" + michael@0: identity.primaryPort; michael@0: michael@0: let request = new RESTRequest(uri + "/resource"); michael@0: request.timeout = 0.1; // 100 milliseconds michael@0: request.get(function (error) { michael@0: do_check_eq(error.result, Cr.NS_ERROR_NET_TIMEOUT); michael@0: do_check_eq(this.status, this.ABORTED); michael@0: michael@0: // server_connection is undefined on the Android emulator for reasons michael@0: // unknown. Yet, we still get here. If this test is refactored, we should michael@0: // investigate the reason why the above callback is behaving differently. michael@0: if (server_connection) { michael@0: _("Closing connection."); michael@0: server_connection.close(); michael@0: } michael@0: michael@0: _("Shutting down server."); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: /** michael@0: * An exception thrown in 'onProgress' propagates to the 'onComplete' handler. michael@0: */ michael@0: add_test(function test_exception_in_onProgress() { michael@0: let handler = httpd_handler(200, "OK", "Foobar"); michael@0: let server = httpd_setup({"/resource": handler}); michael@0: michael@0: let request = new RESTRequest(server.baseURI + "/resource"); michael@0: request.onProgress = function onProgress() { michael@0: it.does.not.exist(); michael@0: }; michael@0: request.get(function onComplete(error) { michael@0: do_check_eq(error, "ReferenceError: it is not defined"); michael@0: do_check_eq(this.status, this.ABORTED); michael@0: michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_new_channel() { michael@0: _("Ensure a redirect to a new channel is handled properly."); michael@0: michael@0: function checkUA(metadata) { michael@0: let ua = metadata.getHeader("User-Agent"); michael@0: _("User-Agent is " + ua); michael@0: do_check_eq("foo bar", ua); michael@0: } michael@0: michael@0: let redirectRequested = false; michael@0: let redirectURL; michael@0: function redirectHandler(metadata, response) { michael@0: checkUA(metadata); michael@0: redirectRequested = true; michael@0: michael@0: let body = "Redirecting"; michael@0: response.setStatusLine(metadata.httpVersion, 307, "TEMPORARY REDIRECT"); michael@0: response.setHeader("Location", redirectURL); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: michael@0: let resourceRequested = false; michael@0: function resourceHandler(metadata, response) { michael@0: checkUA(metadata); michael@0: resourceRequested = true; michael@0: michael@0: let body = "Test"; michael@0: response.setHeader("Content-Type", "text/plain"); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: } michael@0: michael@0: let server1 = httpd_setup({"/redirect": redirectHandler}); michael@0: let server2 = httpd_setup({"/resource": resourceHandler}); michael@0: redirectURL = server2.baseURI + "/resource"; michael@0: michael@0: function advance() { michael@0: server1.stop(function () { michael@0: server2.stop(run_next_test); michael@0: }); michael@0: } michael@0: michael@0: let request = new RESTRequest(server1.baseURI + "/redirect"); michael@0: request.setHeader("User-Agent", "foo bar"); michael@0: michael@0: // Swizzle in our own fakery, because this redirect is neither michael@0: // internal nor URI-preserving. RESTRequest's policy is to only michael@0: // copy headers under certain circumstances. michael@0: let protoMethod = request.shouldCopyOnRedirect; michael@0: request.shouldCopyOnRedirect = function wrapped(o, n, f) { michael@0: // Check the default policy. michael@0: do_check_false(protoMethod.call(this, o, n, f)); michael@0: return true; michael@0: }; michael@0: michael@0: request.get(function onComplete(error) { michael@0: let response = this.response; michael@0: michael@0: do_check_eq(200, response.status); michael@0: do_check_eq("Test", response.body); michael@0: do_check_true(redirectRequested); michael@0: do_check_true(resourceRequested); michael@0: michael@0: advance(); michael@0: }); michael@0: }); michael@0: michael@0: add_test(function test_not_sending_cookie() { michael@0: function handler(metadata, response) { michael@0: let body = "COOKIE!"; michael@0: response.setStatusLine(metadata.httpVersion, 200, "OK"); michael@0: response.bodyOutputStream.write(body, body.length); michael@0: do_check_false(metadata.hasHeader("Cookie")); michael@0: } michael@0: let server = httpd_setup({"/test": handler}); michael@0: michael@0: let cookieSer = Cc["@mozilla.org/cookieService;1"] michael@0: .getService(Ci.nsICookieService); michael@0: let uri = CommonUtils.makeURI(server.baseURI); michael@0: cookieSer.setCookieString(uri, null, "test=test; path=/;", null); michael@0: michael@0: let res = new RESTRequest(server.baseURI + "/test"); michael@0: res.get(function (error) { michael@0: do_check_null(error); michael@0: do_check_true(this.response.success); michael@0: do_check_eq("COOKIE!", this.response.body); michael@0: server.stop(run_next_test); michael@0: }); michael@0: }); michael@0: