Bug 826086 - Handle errors in asyncOpen. r=gps
authorRichard Newman <rnewman@mozilla.com>
Wed, 02 Jan 2013 15:40:03 -0800
changeset 117369 c80bd4e618c88b2966b97f9c89fd8e4c858cced7
parent 117368 b29575b9f9dd0c8859fe68d88ebabd88c6da2e13
child 117370 6955309291ee4afe219fee09987f3838ccf5ac83
push id24098
push userrnewman@mozilla.com
push dateThu, 03 Jan 2013 03:39:06 +0000
treeherdermozilla-central@6955309291ee [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersgps
bugs826086
milestone20.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 826086 - Handle errors in asyncOpen. r=gps
services/common/rest.js
services/common/tests/unit/test_restrequest.js
services/sync/modules/resource.js
--- a/services/common/rest.js
+++ b/services/common/rest.js
@@ -319,17 +319,23 @@ RESTRequest.prototype = {
     // will always be 'PUT'. Yeah, I know.
     channel.requestMethod = method;
 
     // Before opening the channel, set the charset that serves as a hint
     // as to what the response might be encoded as.
     channel.contentCharset = this.charset;
 
     // Blast off!
-    channel.asyncOpen(this, null);
+    try {
+      channel.asyncOpen(this, null);
+    } catch (ex) {
+      // asyncOpen can throw in a bunch of cases -- e.g., a forbidden port.
+      this._log.warn("Caught an error in asyncOpen: " + CommonUtils.exceptionStr(ex));
+      CommonUtils.nextTick(onComplete.bind(this, ex));
+    }
     this.status = this.SENT;
     this.delayTimeout();
     return this;
   },
 
   /**
    * Create or push back the abort timer that kills this request.
    */
--- a/services/common/tests/unit/test_restrequest.js
+++ b/services/common/tests/unit/test_restrequest.js
@@ -85,16 +85,32 @@ add_test(function test_proxy_auth_redire
     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 uri = TEST_RESOURCE_URL;
   let request = new RESTRequest(uri).get(function (error) {
--- a/services/sync/modules/resource.js
+++ b/services/sync/modules/resource.js
@@ -215,17 +215,23 @@ AsyncResource.prototype = {
       channel.setUploadStream(stream, type, this._data.length);
     }
 
     // Setup a channel listener so that the actual network operation
     // is performed asynchronously.
     let listener = new ChannelListener(this._onComplete, this._onProgress,
                                        this._log, this.ABORT_TIMEOUT);
     channel.requestMethod = action;
-    channel.asyncOpen(listener, null);
+    try {
+      channel.asyncOpen(listener, null);
+    } catch (ex) {
+      // asyncOpen can throw in a bunch of cases -- e.g., a forbidden port.
+      this._log.warn("Caught an error in asyncOpen: " + CommonUtils.exceptionStr(ex));
+      CommonUtils.nextTick(callback.bind(this, ex));
+    }
   },
 
   _onComplete: function _onComplete(error, data, channel) {
     this._log.trace("In _onComplete. Error is " + error + ".");
 
     if (error) {
       this._callback(error);
       return;