Bug 949667 - Crash in mozilla::net::HttpChannelParent::OnStartRequest, fail redirect to unsupported protocol on child process. r=jduell, a=lsblakk
authorHonza Bambas <honzab.moz@firemni.cz>
Tue, 14 Jan 2014 15:59:00 +0100
changeset 174833 17e6923abc9f04e8c725b03055dc158f7c882891
parent 174832 b15a92ca0ec4ceff19ab9af1c1da068c5f9b2c8c
child 174834 990a21978a2dfc03bca8af57fe1843c0fe674518
push id3224
push userlsblakk@mozilla.com
push dateTue, 04 Feb 2014 01:06:49 +0000
treeherdermozilla-beta@60c04d0987f1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, lsblakk
bugs949667
milestone28.0a2
Bug 949667 - Crash in mozilla::net::HttpChannelParent::OnStartRequest, fail redirect to unsupported protocol on child process. r=jduell, a=lsblakk
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParentListener.cpp
netwerk/test/unit/test_redirect_different-protocol.js
netwerk/test/unit/xpcshell.ini
netwerk/test/unit_ipc/test_redirect_different-protocol_wrap.js
netwerk/test/unit_ipc/xpcshell.ini
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -739,23 +739,25 @@ HttpChannelChild::Redirect1Begin(const u
     // Veto redirect.  nsHttpChannel decides to cancel or continue.
     OnRedirectVerifyCallback(rv);
     return;
   }
 
   mRedirectChannelChild = do_QueryInterface(newChannel);
   if (mRedirectChannelChild) {
     mRedirectChannelChild->ConnectParent(newChannelId);
+    rv = gHttpHandler->AsyncOnChannelRedirect(this,
+                                              newChannel,
+                                              redirectFlags);
   } else {
-    NS_ERROR("Redirecting to a protocol that doesn't support universal protocol redirect");
+    LOG(("  redirecting to a protocol that doesn't implement"
+         " nsIChildChannel"));
+    rv = NS_ERROR_FAILURE;
   }
 
-  rv = gHttpHandler->AsyncOnChannelRedirect(this,
-                                            newChannel,
-                                            redirectFlags);
   if (NS_FAILED(rv))
     OnRedirectVerifyCallback(rv);
 }
 
 class Redirect3Event : public ChannelEvent
 {
  public:
   Redirect3Event(HttpChannelChild* child) : mChild(child) {}
--- a/netwerk/protocol/http/HttpChannelParentListener.cpp
+++ b/netwerk/protocol/http/HttpChannelParentListener.cpp
@@ -180,16 +180,20 @@ HttpChannelParentListener::OnRedirectRes
 
     // Release all previously registered channels, they are no longer need to be
     // kept in the registrar from this moment.
     registrar->DeregisterChannels(mRedirectChannelId);
 
     mRedirectChannelId = 0;
   }
 
+  if (!redirectChannel) {
+    succeeded = false;
+  }
+
   nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
       do_QueryInterface(mActiveChannel);
   MOZ_ASSERT(activeRedirectingChannel,
     "Channel finished a redirect response, but doesn't implement "
     "nsIParentRedirectingChannel to complete it.");
 
   activeRedirectingChannel->CompleteRedirect(succeeded);
 
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_redirect_different-protocol.js
@@ -0,0 +1,58 @@
+Cu.import("resource://testing-common/httpd.js");
+
+XPCOMUtils.defineLazyGetter(this, "URL", function() {
+  return "http://localhost:" + httpServer.identity.primaryPort;
+});
+
+var httpServer = null;
+// Need to randomize, because apparently no one clears our cache
+var randomPath = "/redirect/" + Math.random();
+
+XPCOMUtils.defineLazyGetter(this, "randomURI", function() {
+  return URL + randomPath;
+});
+
+function inChildProcess() {
+  return Cc["@mozilla.org/xre/app-info;1"]
+           .getService(Ci.nsIXULRuntime)
+           .processType != Ci.nsIXULRuntime.PROCESS_TYPE_DEFAULT;
+}
+
+function make_channel(url, callback, ctx) {
+  var ios = Cc["@mozilla.org/network/io-service;1"].
+            getService(Ci.nsIIOService);
+  return ios.newChannel(url, "", null);
+}
+
+const redirectTargetBody = "response body";
+const response301Body = "redirect body";
+
+function redirectHandler(metadata, response)
+{
+  response.setStatusLine(metadata.httpVersion, 301, "Moved");
+  response.bodyOutputStream.write(response301Body, response301Body.length);
+  response.setHeader("Location", "data:text/plain," + redirectTargetBody, false);
+}
+
+function finish_test(request, buffer)
+{
+  if (inChildProcess()) {
+    // redirects to protocols other than http/ftp will fail until bug 590682 is fixed.
+    do_check_eq(buffer, response301Body);
+  } else {
+    do_check_eq(buffer, redirectTargetBody);
+  }
+
+  httpServer.stop(do_test_finished);
+}
+
+function run_test()
+{
+  httpServer = new HttpServer();
+  httpServer.registerPathHandler(randomPath, redirectHandler);
+  httpServer.start(-1);
+
+  var chan = make_channel(randomURI);
+  chan.asyncOpen(new ChannelListener(finish_test, null, 0), null);
+  do_test_pending();
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -252,16 +252,17 @@ fail-if = os == "android"
 [test_redirect_canceled.js]
 [test_redirect_failure.js]
 # Bug 675039: test fails consistently on Android
 fail-if = os == "android"
 [test_redirect_from_script.js]
 [test_redirect_passing.js]
 [test_redirect_loop.js]
 [test_redirect_baduri.js]
+[test_redirect_different-protocol.js]
 [test_reentrancy.js]
 [test_reopen.js]
 [test_resumable_channel.js]
 [test_resumable_truncate.js]
 [test_safeoutputstream.js]
 [test_simple.js]
 [test_sockettransportsvc_available.js]
 [test_socks.js]
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit_ipc/test_redirect_different-protocol_wrap.js
@@ -0,0 +1,7 @@
+//
+// Run test script in content process instead of chrome (xpcshell's default)
+//
+
+function run_test() {
+  run_test_in_child("../unit/test_redirect_different-protocol.js");
+}
--- a/netwerk/test/unit_ipc/xpcshell.ini
+++ b/netwerk/test/unit_ipc/xpcshell.ini
@@ -21,13 +21,14 @@ support-files = disabled_test_bug528292_
 [test_redirect-caching_failure_wrap.js]
 [test_redirect-caching_passing_wrap.js]
 [test_redirect_canceled_wrap.js]
 [test_redirect_failure_wrap.js]
 # Do not test the channel.redirectTo() API under e10s until 827269 is resolved
 [test_redirect_from_script_wrap.js]
 skip-if = true
 [test_redirect_passing_wrap.js]
+[test_redirect_different-protocol_wrap.js]
 [test_reentrancy_wrap.js]
 [test_resumable_channel_wrap.js]
 [test_simple_wrap.js]
 [test_xmlhttprequest_wrap.js]
 [test_XHR_redirects.js]