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