Bug 591707 - e10s: handle redirects from HTTP to a different protocol, r=jduell, a=blocking-fennec2.0b3+
authorHonza Bambas <honzab.moz@firemni.cz>
Tue, 23 Nov 2010 23:56:06 +0100
changeset 58111 33c8fcb13a996977987bc9e6f505c8fae2a5ca8c
parent 58110 3492dbd5ff507a0dbb3f318f61717ef752d6e1f4
child 58112 cf61e6916004b57f47ad001034757fe3a7df6d53
push id17160
push userhonzab.moz@firemni.cz
push dateTue, 23 Nov 2010 22:57:29 +0000
treeherdermozilla-central@33c8fcb13a99 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, blocking-fennec2.0b3
bugs591707
milestone2.0b8pre
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 591707 - e10s: handle redirects from HTTP to a different protocol, r=jduell, a=blocking-fennec2.0b3+
netwerk/base/public/Makefile.in
netwerk/base/public/nsIChildChannel.idl
netwerk/base/public/nsIParentChannel.idl
netwerk/base/public/nsIParentRedirectingChannel.idl
netwerk/base/public/nsIRedirectChannelRegistrar.idl
netwerk/base/public/nsNetUtil.h
netwerk/base/src/Makefile.in
netwerk/base/src/RedirectChannelRegistrar.cpp
netwerk/base/src/RedirectChannelRegistrar.h
netwerk/build/nsNetCID.h
netwerk/build/nsNetModule.cpp
netwerk/protocol/ftp/FTPChannelChild.cpp
netwerk/protocol/ftp/FTPChannelChild.h
netwerk/protocol/ftp/FTPChannelParent.cpp
netwerk/protocol/ftp/FTPChannelParent.h
netwerk/protocol/ftp/PFTPChannel.ipdl
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelChild.h
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/HttpChannelParentListener.cpp
netwerk/protocol/http/HttpChannelParentListener.h
netwerk/protocol/http/Makefile.in
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/nsIHttpChannelChild.idl
--- a/netwerk/base/public/Makefile.in
+++ b/netwerk/base/public/Makefile.in
@@ -140,16 +140,24 @@ XPIDLSRCS	= \
 		nsIStrictTransportSecurityService.idl \
 		nsIURIWithPrincipal.idl \
 		nsIURIClassifier.idl \
 		nsIRedirectResultListener.idl \
 		mozIThirdPartyUtil.idl \
 		nsISerializationHelper.idl \
 		$(NULL)
 
+ifdef MOZ_IPC
+XPIDLSRCS	+= \
+		nsIChildChannel.idl \
+		nsIParentChannel.idl \
+		nsIParentRedirectingChannel.idl \
+		nsIRedirectChannelRegistrar.idl
+endif
+
 ifdef MOZ_TOOLKIT_SEARCH
 XPIDLSRCS	+= nsIBrowserSearchService.idl
 endif
 
 EXPORTS		= \
 		netCore.h \
 		nsNetError.h \
 		nsNetUtil.h \
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIChildChannel.idl
@@ -0,0 +1,67 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIStreamListener;
+
+/**
+ * Implemented by content side of IPC protocols.
+ */
+
+[scriptable, uuid(c45b92ae-4f07-41dd-b0ef-aa044eeabb1e)]
+interface nsIChildChannel : nsISupports
+{
+  /**
+   * Create the chrome side of the IPC protocol and join an existing 'real'
+   * channel on the parent process.  The id is provided by
+   * nsIRedirectChannelRegistrar on the chrome process and pushed to the child
+   * protocol as an argument to event starting a redirect.
+   *
+   * Primarilly used in HttpChannelChild::Redirect1Begin on a newly created
+   * child channel, where the new channel is intended to be created on the
+   * child process.
+   */
+  void connectParent(in PRUint32 id);
+
+  /**
+   * As AsyncOpen is called on the chrome process for redirect target channels,
+   * we have to inform the child side of the protocol of that fact by a special
+   * method.
+   */
+  void completeRedirectSetup(in nsIStreamListener aListener,
+                             in nsISupports aContext);
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIParentChannel.idl
@@ -0,0 +1,52 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIStreamListener.idl"
+
+interface nsITabParent;
+
+/**
+ * Implemented by chrome side of IPC protocols.
+ */
+
+[scriptable, uuid(723188c3-fff8-4d27-b657-a256e7209be0)]
+interface nsIParentChannel : nsIStreamListener
+{
+  /**
+   * Called to invoke deletion of the IPC protocol.
+   */
+  void delete();
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIParentRedirectingChannel.idl
@@ -0,0 +1,78 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsIParentChannel.idl"
+
+interface nsITabParent;
+interface nsIChannel;
+interface nsIAsyncVerifyRedirectCallback;
+
+/**
+ * Implemented by chrome side of IPC protocols that support redirect responses.
+ */
+
+[scriptable, uuid(cb7edc1c-096f-44de-957c-cb93de1545f6)]
+interface nsIParentRedirectingChannel : nsIParentChannel
+{
+  /**
+   * Called when the channel got a response that redirects it to a different
+   * URI.  The implementation is responsible for calling the redirect observers
+   * on the child process and provide the decision result to the callback.
+   *
+   * @param newChannelId
+   *    id of the redirect channel obtained from nsIRedirectChannelRegistrar.
+   * @param newURI
+   *    the URI we redirect to
+   * @param callback
+   *    redirect result callback, usage is compatible with how
+   *    nsIChannelEventSink defines it
+   */
+  void startRedirect(in PRUint32 newChannelId,
+                     in nsIChannel newChannel,
+                     in PRUint32 redirectFlags,
+                     in nsIAsyncVerifyRedirectCallback callback);
+
+  /**
+   * Called after we are done with redirecting process and we know if to
+   * redirect or not.  Forward the redirect result to the child process.  From
+   * that moment the nsIParentChannel implementation expects it will be
+   * forwarded all notifications from the 'real' channel.
+   *
+   * Primarilly used by HttpChannelParentListener::OnRedirectResult and kept
+   * as mActiveChannel and mRedirectChannel in that class.
+   */
+  void completeRedirect(in PRBool succeeded);
+};
new file mode 100644
--- /dev/null
+++ b/netwerk/base/public/nsIRedirectChannelRegistrar.idl
@@ -0,0 +1,104 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+interface nsIChannel;
+interface nsIParentChannel;
+
+/**
+ * Used on the chrome process as a service to join channel implementation
+ * and parent IPC protocol side under a unique id.  Provides this way a generic
+ * communication while redirecting to various protocols.
+ *
+ * See also nsIChildChannel and nsIParentChannel.
+ */
+
+[scriptable, uuid (efa36ea2-5b07-46fc-9534-a5acb8b77b72)]
+interface nsIRedirectChannelRegistrar : nsISupports
+{
+  /**
+   * Register the redirect target channel and obtain a unique ID for that
+   * channel.
+   *
+   * Primarily used in HttpChannelParentListener::AsyncOnChannelRedirect to get
+   * a channel id sent to the HttpChannelChild being redirected.
+   */
+  PRUint32 registerChannel(in nsIChannel channel);
+
+  /**
+   * First, search for the channel registered under the id.  If found return
+   * it.  Then, register under the same id the parent side of IPC protocol
+   * to let it be later grabbed back by the originator of the redirect and
+   * notifications from the real channel could be forwarded to this parent
+   * channel.
+   *
+   * Primarily used in parent side of an IPC protocol implementation
+   * in reaction to nsIChildChannel.connectParent(id) called from the child
+   * process.
+   */
+  nsIChannel linkChannels(in PRUint32 id, in nsIParentChannel channel);
+
+  /**
+   * Returns back the channel previously registered under the ID with
+   * registerChannel method.
+   *
+   * Primarilly used in chrome IPC side of protocols when attaching a redirect
+   * target channel to an existing 'real' channel implementation.
+   */
+  nsIChannel getRegisteredChannel(in PRUint32 id);
+
+  /**
+   * Returns the stream listener that shall be attached to the redirect target
+   * channel, all notification from the redirect target channel will be
+   * forwarded to this stream listener.
+   *
+   * Primarilly used in HttpChannelParentListener::OnRedirectResult callback
+   * to grab the created parent side of the channel and forward notifications
+   * to it.
+   */
+  nsIParentChannel getParentChannel(in PRUint32 id);
+
+  /**
+   * To not force all channel implementations to support weak reference
+   * consumers of this service must ensure release of registered channels them
+   * self.  This releases both the real and parent channel registered under
+   * the id.
+   *
+   * Primarilly used in HttpChannelParentListener::OnRedirectResult callback.
+   */
+  void deregisterChannels(in PRUint32 id);
+};
--- a/netwerk/base/public/nsNetUtil.h
+++ b/netwerk/base/public/nsNetUtil.h
@@ -102,16 +102,17 @@
 #include "nsIMutable.h"
 #include "nsIPropertyBag2.h"
 #include "nsIWritablePropertyBag2.h"
 #include "nsIIDNService.h"
 #include "nsIChannelEventSink.h"
 #include "nsIChannelPolicy.h"
 #include "nsISocketProviderService.h"
 #include "nsISocketProvider.h"
+#include "nsIRedirectChannelRegistrar.h"
 #include "mozilla/Services.h"
 
 #ifdef MOZILLA_INTERNAL_API
 
 inline already_AddRefed<nsIIOService>
 do_GetIOService(nsresult* error = 0)
 {
     already_AddRefed<nsIIOService> ret = mozilla::services::GetIOService();
@@ -1775,16 +1776,32 @@ NS_IsInternalSameURIRedirect(nsIChannel 
   if (!oldURI || !newURI) {
     return PR_FALSE;
   }
 
   PRBool res;
   return NS_SUCCEEDED(oldURI->Equals(newURI, &res)) && res;
 }
 
+inline nsresult
+NS_LinkRedirectChannels(PRUint32 channelId,
+                        nsIParentChannel *parentChannel,
+                        nsIChannel** _result)
+{
+  nsresult rv;
+
+  nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
+      do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
+
+  return registrar->LinkChannels(channelId,
+                                 parentChannel,
+                                 _result);
+}
+
 /**
  * Helper function to create a random URL string that's properly formed
  * but guaranteed to be invalid.
  */  
 #define NS_FAKE_SCHEME "http://"
 #define NS_FAKE_TLD ".invalid"
 inline nsresult
 NS_MakeRandomInvalidURLString(nsCString& result)
--- a/netwerk/base/src/Makefile.in
+++ b/netwerk/base/src/Makefile.in
@@ -89,16 +89,20 @@ CPPSRCS		= \
 		nsURLHelper.cpp \
 		nsURLParsers.cpp \
 		nsNetStrings.cpp \
 		nsBase64Encoder.cpp \
 		nsSerializationHelper.cpp \
 		nsDNSPrefetch.cpp \
 		$(NULL)
 
+ifdef MOZ_IPC
+	CPPSRCS += RedirectChannelRegistrar.cpp
+endif
+
 ifeq ($(MOZ_WIDGET_TOOLKIT),os2)
 	CPPSRCS += nsURLHelperOS2.cpp
 else
 ifeq ($(MOZ_WIDGET_TOOLKIT),windows)
 	CPPSRCS += nsURLHelperWin.cpp
 	CPPSRCS += nsNativeConnectionHelper.cpp
 ifneq ($(OS_ARCH), WINCE)
 	CPPSRCS += nsAutodialWin.cpp
new file mode 100644
--- /dev/null
+++ b/netwerk/base/src/RedirectChannelRegistrar.cpp
@@ -0,0 +1,127 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "RedirectChannelRegistrar.h"
+
+namespace mozilla {
+namespace net {
+
+template<class KeyClass, class T>
+PRBool
+RedirectChannelRegistrar::nsCOMPtrHashtable<KeyClass,T>::Get(KeyType aKey, T** retVal) const
+{
+  typename base_type::EntryType* ent = this->GetEntry(aKey);
+
+  if (ent) {
+    if (retVal)
+      NS_IF_ADDREF(*retVal = ent->mData);
+
+    return PR_TRUE;
+  }
+
+  if (retVal)
+    *retVal = nsnull;
+
+  return PR_FALSE;
+}
+
+NS_IMPL_ISUPPORTS1(RedirectChannelRegistrar, nsIRedirectChannelRegistrar)
+
+RedirectChannelRegistrar::RedirectChannelRegistrar()
+  : mId(1)
+{
+  mRealChannels.Init(64);
+  mParentChannels.Init(64);
+}
+
+NS_IMETHODIMP
+RedirectChannelRegistrar::RegisterChannel(nsIChannel *channel,
+                                          PRUint32 *_retval NS_OUTPARAM)
+{
+  mRealChannels.Put(mId, channel);
+  *_retval = mId;
+
+  ++mId;
+
+  // Ensure we always provide positive ids
+  if (!mId)
+    mId = 1;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RedirectChannelRegistrar::GetRegisteredChannel(PRUint32 id,
+                                               nsIChannel **_retval NS_OUTPARAM)
+{
+  if (!mRealChannels.Get(id, _retval))
+    return NS_ERROR_NOT_AVAILABLE;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RedirectChannelRegistrar::LinkChannels(PRUint32 id,
+                                       nsIParentChannel *channel,
+                                       nsIChannel** _retval)
+{
+  if (!mRealChannels.Get(id, _retval))
+    return NS_ERROR_NOT_AVAILABLE;
+
+  mParentChannels.Put(id, channel);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RedirectChannelRegistrar::GetParentChannel(PRUint32 id,
+                                           nsIParentChannel **_retval NS_OUTPARAM)
+{
+  if (!mParentChannels.Get(id, _retval))
+    return NS_ERROR_NOT_AVAILABLE;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+RedirectChannelRegistrar::DeregisterChannels(PRUint32 id)
+{
+  mRealChannels.Remove(id);
+  mParentChannels.Remove(id);
+  return NS_OK;
+}
+
+}
+}
new file mode 100644
--- /dev/null
+++ b/netwerk/base/src/RedirectChannelRegistrar.h
@@ -0,0 +1,82 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is mozilla.org code.
+ *
+ * The Initial Developer of the Original Code is Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#ifndef RedirectChannelRegistrar_h__
+#define RedirectChannelRegistrar_h__
+
+#include "nsIRedirectChannelRegistrar.h"
+
+#include "nsIChannel.h"
+#include "nsIParentChannel.h"
+#include "nsClassHashtable.h"
+
+namespace mozilla {
+namespace net {
+
+class RedirectChannelRegistrar : public nsIRedirectChannelRegistrar
+{
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREDIRECTCHANNELREGISTRAR
+
+  RedirectChannelRegistrar();
+
+protected:
+  template<class KeyClass, class T>
+  class nsCOMPtrHashtable :
+    public nsBaseHashtable< KeyClass, nsCOMPtr<T>, T* >
+  {
+  public:
+    typedef typename KeyClass::KeyType KeyType;
+    typedef T* UserDataType;
+    typedef nsBaseHashtable< KeyClass, nsCOMPtr<T>, T* > base_type;
+
+    PRBool Get(KeyType aKey, UserDataType* pData) const;
+  };
+
+  typedef nsCOMPtrHashtable<nsUint32HashKey, nsIChannel>
+          ChannelHashtable;
+  typedef nsCOMPtrHashtable<nsUint32HashKey, nsIParentChannel>
+          ParentChannelHashtable;
+
+  ChannelHashtable mRealChannels;
+  ParentChannelHashtable mParentChannels;
+  PRUint32 mId;
+};
+
+}
+}
+
+#endif
--- a/netwerk/build/nsNetCID.h
+++ b/netwerk/build/nsNetCID.h
@@ -478,16 +478,27 @@
 
 /**
  * Contract ID for a service implementing nsIURIClassifier that identifies
  * phishing and malware sites.
  */
 #define NS_URICLASSIFIERSERVICE_CONTRACTID \
     "@mozilla.org/uriclassifierservice"
 
+// Redirect channel registrar used for redirect to various protocols
+#define NS_REDIRECTCHANNELREGISTRAR_CONTRACTID \
+    "@mozilla.org/redirectchannelregistrar;1"
+#define NS_REDIRECTCHANNELREGISTRAR_CID \
+{ /* {b69043a6-8929-4d60-8d17-a27e44a8393e} */ \
+    0xb69043a6, \
+    0x8929, \
+    0x4d60, \
+    { 0x8d, 0x17, 0xa2, 0x7e, 0x44, 0xa8, 0x39, 0x3e } \
+}
+
 /******************************************************************************
  * netwerk/cache/ classes
  */
 
 // service implementing nsICacheService.
 #define NS_CACHESERVICE_CLASSNAME \
     "nsCacheService"
 #define NS_CACHESERVICE_CONTRACTID \
--- a/netwerk/build/nsNetModule.cpp
+++ b/netwerk/build/nsNetModule.cpp
@@ -122,16 +122,22 @@ NS_GENERIC_FACTORY_CONSTRUCTOR(nsSafeFil
 NS_GENERIC_AGGREGATED_CONSTRUCTOR_INIT(nsLoadGroup, Init)
 
 #include "nsEffectiveTLDService.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR_INIT(nsEffectiveTLDService, Init)
 
 #include "nsSerializationHelper.h"
 NS_GENERIC_FACTORY_CONSTRUCTOR(nsSerializationHelper)
 
+#ifdef MOZ_IPC
+#include "RedirectChannelRegistrar.h"
+typedef mozilla::net::RedirectChannelRegistrar RedirectChannelRegistrar;
+NS_GENERIC_FACTORY_CONSTRUCTOR(RedirectChannelRegistrar)
+#endif
+
 ///////////////////////////////////////////////////////////////////////////////
 
 extern nsresult
 net_NewIncrementalDownload(nsISupports *, const nsIID &, void **);
 
 #define NS_INCREMENTALDOWNLOAD_CLASSNAME \
     "nsIncrementalDownload"
 #define NS_INCREMENTALDOWNLOAD_CID \
@@ -740,16 +746,19 @@ NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERV
 #elif defined(MOZ_WIDGET_COCOA)
 NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID);
 #elif defined(MOZ_ENABLE_LIBCONIC)
 NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID);
 #elif defined(MOZ_ENABLE_QTNETWORK)
 NS_DEFINE_NAMED_CID(NS_NETWORK_LINK_SERVICE_CID);
 #endif
 NS_DEFINE_NAMED_CID(NS_SERIALIZATION_HELPER_CID);
+#ifdef MOZ_IPC
+NS_DEFINE_NAMED_CID(NS_REDIRECTCHANNELREGISTRAR_CID);
+#endif
 
 static const mozilla::Module::CIDEntry kNeckoCIDs[] = {
     { &kNS_IOSERVICE_CID, false, NULL, nsIOServiceConstructor },
     { &kNS_STREAMTRANSPORTSERVICE_CID, false, NULL, nsStreamTransportServiceConstructor },
     { &kNS_SOCKETTRANSPORTSERVICE_CID, false, NULL, nsSocketTransportServiceConstructor },
     { &kNS_SERVERSOCKET_CID, false, NULL, nsServerSocketConstructor },
     { &kNS_SOCKETPROVIDERSERVICE_CID, false, NULL, nsSocketProviderService::Create },
     { &kNS_DNSSERVICE_CID, false, NULL, nsDNSServiceConstructor },
@@ -866,16 +875,19 @@ static const mozilla::Module::CIDEntry k
 #elif defined(MOZ_WIDGET_COCOA)
     { &kNS_NETWORK_LINK_SERVICE_CID, false, NULL, nsNetworkLinkServiceConstructor },
 #elif defined(MOZ_ENABLE_LIBCONIC)
     { &kNS_NETWORK_LINK_SERVICE_CID, false, NULL, nsMaemoNetworkLinkServiceConstructor },
 #elif defined(MOZ_ENABLE_QTNETWORK)
     { &kNS_NETWORK_LINK_SERVICE_CID, false, NULL, nsQtNetworkLinkServiceConstructor },
 #endif
     { &kNS_SERIALIZATION_HELPER_CID, false, NULL, nsSerializationHelperConstructor },
+#ifdef MOZ_IPC
+    { &kNS_REDIRECTCHANNELREGISTRAR_CID, false, NULL, RedirectChannelRegistrarConstructor },
+#endif
     { NULL }
 };
 
 static const mozilla::Module::ContractIDEntry kNeckoContracts[] = {
     { NS_IOSERVICE_CONTRACTID, &kNS_IOSERVICE_CID },
     { NS_NETUTIL_CONTRACTID, &kNS_IOSERVICE_CID },
     { NS_STREAMTRANSPORTSERVICE_CONTRACTID, &kNS_STREAMTRANSPORTSERVICE_CID },
     { NS_SOCKETTRANSPORTSERVICE_CONTRACTID, &kNS_SOCKETTRANSPORTSERVICE_CID },
@@ -999,16 +1011,19 @@ static const mozilla::Module::ContractID
 #elif defined(MOZ_WIDGET_COCOA)
     { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID },
 #elif defined(MOZ_ENABLE_LIBCONIC)
     { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID },
 #elif defined(MOZ_ENABLE_QTNETWORK)
     { NS_NETWORK_LINK_SERVICE_CONTRACTID, &kNS_NETWORK_LINK_SERVICE_CID },
 #endif
     { NS_SERIALIZATION_HELPER_CONTRACTID, &kNS_SERIALIZATION_HELPER_CID },
+#ifdef MOZ_IPC
+    { NS_REDIRECTCHANNELREGISTRAR_CONTRACTID, &kNS_REDIRECTCHANNELREGISTRAR_CID },
+#endif
     { NULL }
 };
 
 static const mozilla::Module kNeckoModule = {
     mozilla::Module::kVersion,
     kNeckoCIDs,
     kNeckoContracts,
     kNeckoCategories,
--- a/netwerk/protocol/ftp/FTPChannelChild.cpp
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -92,22 +92,23 @@ FTPChannelChild::ReleaseIPDLReference()
   mIPCOpen = false;
   Release();
 }
 
 //-----------------------------------------------------------------------------
 // FTPChannelChild::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS_INHERITED4(FTPChannelChild,
+NS_IMPL_ISUPPORTS_INHERITED5(FTPChannelChild,
                              nsBaseChannel,
                              nsIFTPChannel,
                              nsIUploadChannel,
                              nsIResumableChannel,
-                             nsIProxiedChannel)
+                             nsIProxiedChannel,
+                             nsIChildChannel)
 
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
 {
   *lastModifiedTime = mLastModifiedTime;
   return NS_OK;
@@ -434,16 +435,44 @@ FTPChannelChild::DoCancelEarly(const nsr
 
   mListener = nsnull;
   mListenerContext = nsnull;
 
   if (mIPCOpen)
     Send__delete__(this);
 }
 
+class FTPDeleteSelfEvent : public ChannelEvent
+{
+ public:
+  FTPDeleteSelfEvent(FTPChannelChild* aChild)
+  : mChild(aChild) {}
+  void Run() { mChild->DoDeleteSelf(); }
+ private:
+  FTPChannelChild* mChild;
+};
+
+bool
+FTPChannelChild::RecvDeleteSelf()
+{
+  if (ShouldEnqueue()) {
+    EnqueueEvent(new FTPDeleteSelfEvent(this));
+  } else {
+    DoDeleteSelf();
+  }
+  return true;
+}
+
+void
+FTPChannelChild::DoDeleteSelf()
+{
+  if (mIPCOpen)
+    Send__delete__(this);
+}
+
 NS_IMETHODIMP
 FTPChannelChild::Cancel(nsresult status)
 {
   if (mCanceled)
     return NS_OK;
 
   mCanceled = true;
   mStatus = status;
@@ -470,11 +499,55 @@ FTPChannelChild::Resume()
   if (!mSuspendCount) {
     if (mQueuePhase == PHASE_UNQUEUED)
       mQueuePhase = PHASE_FINISHED_QUEUEING;
     FlushEventQueue();
   }
   return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// FTPChannelChild::nsIChildChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelChild::ConnectParent(PRUint32 id)
+{
+  // The socket transport in the chrome process now holds a logical ref to us
+  // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
+  AddIPDLReference();
+
+  if (!gNeckoChild->SendPFTPChannelConstructor(this))
+    return NS_ERROR_FAILURE;
+
+  if (!SendConnectChannel(id))
+    return NS_ERROR_FAILURE;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::CompleteRedirectSetup(nsIStreamListener *listener,
+                                       nsISupports *aContext)
+{
+  LOG(("FTPChannelChild::CompleteRedirectSetup [this=%x]\n", this));
+
+  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
+  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
+
+  mIsPending = PR_TRUE;
+  mWasOpened = PR_TRUE;
+  mListener = listener;
+  mListenerContext = aContext;
+
+  // add ourselves to the load group.
+  if (mLoadGroup)
+    mLoadGroup->AddRequest(this, nsnull);
+
+  // We already have an open IPDL connection to the parent. If on-modify-request
+  // listeners or load group observers canceled us, let the parent handle it
+  // and send it back to us naturally.
+  return NS_OK;
+}
+
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/ftp/FTPChannelChild.h
+++ b/netwerk/protocol/ftp/FTPChannelChild.h
@@ -44,16 +44,17 @@
 
 #include "mozilla/net/PFTPChannelChild.h"
 #include "mozilla/net/ChannelEventQueue.h"
 #include "nsBaseChannel.h"
 #include "nsIFTPChannel.h"
 #include "nsIUploadChannel.h"
 #include "nsIProxiedChannel.h"
 #include "nsIResumableChannel.h"
+#include "nsIChildChannel.h"
 
 #include "nsIStreamListener.h"
 
 namespace mozilla {
 namespace net {
 
 // This class inherits logic from nsBaseChannel that is not needed for an
 // e10s child channel, but it works.  At some point we could slice up
@@ -61,36 +62,40 @@ namespace net {
 // nsFTPChannel/FTPChannelChild.
 
 class FTPChannelChild : public PFTPChannelChild
                       , public nsBaseChannel
                       , public nsIFTPChannel
                       , public nsIUploadChannel
                       , public nsIResumableChannel
                       , public nsIProxiedChannel
+                      , public nsIChildChannel
                       , public ChannelEventQueue<FTPChannelChild>
 {
 public:
+  typedef ::nsIStreamListener nsIStreamListener;
+
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSIFTPCHANNEL
   NS_DECL_NSIUPLOADCHANNEL
   NS_DECL_NSIRESUMABLECHANNEL
   NS_DECL_NSIPROXIEDCHANNEL
+  NS_DECL_NSICHILDCHANNEL
 
   NS_IMETHOD Cancel(nsresult status);
   NS_IMETHOD Suspend();
   NS_IMETHOD Resume();
 
   FTPChannelChild(nsIURI* uri);
   virtual ~FTPChannelChild();
 
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
-  NS_IMETHOD AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext);
+  NS_IMETHOD AsyncOpen(nsIStreamListener* listener, nsISupports* aContext);
 
   // Note that we handle this ourselves, overriding the nsBaseChannel
   // default behavior, in order to be e10s-friendly.
   NS_IMETHOD IsPending(PRBool* result);
 
   NS_OVERRIDE nsresult OpenContentStream(PRBool async,
                                          nsIInputStream** stream,
                                          nsIChannel** channel);
@@ -103,32 +108,35 @@ protected:
                                       const PRTime& aLastModified,
                                       const nsCString& aEntityID,
                                       const IPC::URI& aURI);
   NS_OVERRIDE bool RecvOnDataAvailable(const nsCString& data,
                                        const PRUint32& offset,
                                        const PRUint32& count);
   NS_OVERRIDE bool RecvOnStopRequest(const nsresult& statusCode);
   NS_OVERRIDE bool RecvCancelEarly(const nsresult& statusCode);
+  NS_OVERRIDE bool RecvDeleteSelf();
 
   void DoOnStartRequest(const PRInt32& aContentLength,
                         const nsCString& aContentType,
                         const PRTime& aLastModified,
                         const nsCString& aEntityID,
                         const IPC::URI& aURI);
   void DoOnDataAvailable(const nsCString& data,
                          const PRUint32& offset,
                          const PRUint32& count);
   void DoOnStopRequest(const nsresult& statusCode);
   void DoCancelEarly(const nsresult& statusCode);
+  void DoDeleteSelf();
 
   friend class FTPStartRequestEvent;
   friend class FTPDataAvailableEvent;
   friend class FTPStopRequestEvent;
   friend class FTPCancelEarlyEvent;
+  friend class FTPDeleteSelfEvent;
 
 private:
   nsCOMPtr<nsIInputStream> mUploadStream;
 
   bool mIPCOpen;
   bool mCanceled;
   PRUint32 mSuspendCount;
   PRPackedBool mIsPending;
--- a/netwerk/protocol/ftp/FTPChannelParent.cpp
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -38,16 +38,17 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/net/FTPChannelParent.h"
 #include "nsFTPChannel.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPriority.h"
+#include "nsIRedirectChannelRegistrar.h"
 #include "nsFtpProtocolHandler.h"
 
 #undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 namespace mozilla {
 namespace net {
 
@@ -71,18 +72,19 @@ FTPChannelParent::ActorDestroy(ActorDest
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // FTPChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS3(FTPChannelParent,
+NS_IMPL_ISUPPORTS4(FTPChannelParent,
                    nsIStreamListener,
+                   nsIParentChannel,
                    nsIInterfaceRequestor,
                    nsIRequestObserver);
 
 //-----------------------------------------------------------------------------
 // FTPChannelParent::PFTPChannelParent
 //-----------------------------------------------------------------------------
 
 bool
@@ -127,16 +129,33 @@ FTPChannelParent::RecvAsyncOpen(const IP
   rv = mChannel->AsyncOpen(this, nsnull);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
   
   return true;
 }
 
 bool
+FTPChannelParent::RecvConnectChannel(const PRUint32& channelId)
+{
+  nsresult rv;
+
+  LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId));
+
+  nsCOMPtr<nsIChannel> channel;
+  rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(channel));
+  if (NS_SUCCEEDED(rv))
+    mChannel = static_cast<nsFtpChannel*>(channel.get());
+
+  LOG(("  found channel %p, rv=%08x", mChannel.get(), rv));
+
+  return true;
+}
+
+bool
 FTPChannelParent::RecvCancel(const nsresult& status)
 {
   mChannel->Cancel(status);
   return true;
 }
 
 bool
 FTPChannelParent::RecvSuspend()
@@ -214,20 +233,33 @@ FTPChannelParent::OnDataAvailable(nsIReq
 
   if (mIPCClosed || !SendOnDataAvailable(data, aOffset, aCount))
     return NS_ERROR_UNEXPECTED;
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
+// FTPChannelParent::nsIParentChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelParent::Delete()
+{
+  if (mIPCClosed || !SendDeleteSelf())
+    return NS_ERROR_UNEXPECTED;
+
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
 // FTPChannelParent::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 FTPChannelParent::GetInterface(const nsIID& uuid, void** result)
 {
-  DROP_DEAD();
+  return QueryInterface(uuid, result);
 }
 
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/ftp/FTPChannelParent.h
+++ b/netwerk/protocol/ftp/FTPChannelParent.h
@@ -39,42 +39,44 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_net_FTPChannelParent_h
 #define mozilla_net_FTPChannelParent_h
 
 #include "mozilla/net/PFTPChannelParent.h"
 #include "mozilla/net/NeckoCommon.h"
-#include "nsIStreamListener.h"
+#include "nsIParentChannel.h"
 #include "nsIInterfaceRequestor.h"
 
 class nsFtpChannel;
 
 namespace mozilla {
 namespace net {
 
 class FTPChannelParent : public PFTPChannelParent
-                       , public nsIStreamListener
+                       , public nsIParentChannel
                        , public nsIInterfaceRequestor
 {
 public:
   NS_DECL_ISUPPORTS
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
+  NS_DECL_NSIPARENTCHANNEL
   NS_DECL_NSIINTERFACEREQUESTOR
 
   FTPChannelParent();
   virtual ~FTPChannelParent();
 
 protected:
   NS_OVERRIDE virtual bool RecvAsyncOpen(const IPC::URI& uri,
                                          const PRUint64& startPos,
                                          const nsCString& entityID,
                                          const IPC::InputStream& uploadStream);
+  NS_OVERRIDE virtual bool RecvConnectChannel(const PRUint32& channelId);
   NS_OVERRIDE virtual bool RecvCancel(const nsresult& status);
   NS_OVERRIDE virtual bool RecvSuspend();
   NS_OVERRIDE virtual bool RecvResume();
 
   NS_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why);
 
   nsRefPtr<nsFtpChannel> mChannel;
 
--- a/netwerk/protocol/ftp/PFTPChannel.ipdl
+++ b/netwerk/protocol/ftp/PFTPChannel.ipdl
@@ -54,23 +54,25 @@ async protocol PFTPChannel
 {
   manager PNecko;
 
 parent:
   __delete__();
 
   AsyncOpen(URI uri, PRUint64 startPos, nsCString entityID,
             InputStream uploadStream);
+  ConnectChannel(PRUint32 channelId);
   Cancel(nsresult status);
   Suspend();
   Resume();
 
 child:
   OnStartRequest(PRInt32 aContentLength, nsCString aContentType,
                  PRTime aLastModified, nsCString aEntityID, URI aURI);
   OnDataAvailable(nsCString data, PRUint32 offset, PRUint32 count);
   OnStopRequest(nsresult statusCode);
   CancelEarly(nsresult statusCode);
+  DeleteSelf();
 };
 
 } // namespace net
 } // namespace mozilla
 
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -114,16 +114,18 @@ NS_INTERFACE_MAP_BEGIN(HttpChannelChild)
   NS_INTERFACE_MAP_ENTRY(nsICacheInfoChannel)
   NS_INTERFACE_MAP_ENTRY(nsIResumableChannel)
   NS_INTERFACE_MAP_ENTRY(nsISupportsPriority)
   NS_INTERFACE_MAP_ENTRY(nsIProxiedChannel)
   NS_INTERFACE_MAP_ENTRY(nsITraceableChannel)
   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheContainer)
   NS_INTERFACE_MAP_ENTRY(nsIApplicationCacheChannel)
   NS_INTERFACE_MAP_ENTRY(nsIAsyncVerifyRedirectCallback)
+  NS_INTERFACE_MAP_ENTRY(nsIChildChannel)
+  NS_INTERFACE_MAP_ENTRY(nsIHttpChannelChild)
   NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAssociatedContentSecurity, GetAssociatedContentSecurity())
 NS_INTERFACE_MAP_END_INHERITING(HttpBaseChannel)
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::PHttpChannelChild
 //-----------------------------------------------------------------------------
 
 void
@@ -584,89 +586,101 @@ HttpChannelChild::DeleteSelf()
 {
   Send__delete__(this);
 }
 
 class Redirect1Event : public ChannelEvent
 {
  public:
   Redirect1Event(HttpChannelChild* child,
-                 PHttpChannelChild* newChannel,
+                 const PRUint32& newChannelId,
                  const IPC::URI& newURI,
                  const PRUint32& redirectFlags,
                  const nsHttpResponseHead& responseHead)
   : mChild(child)
-  , mNewChannel(newChannel)
+  , mNewChannelId(newChannelId)
   , mNewURI(newURI)
   , mRedirectFlags(redirectFlags)
   , mResponseHead(responseHead) {}
 
   void Run() 
   { 
-    mChild->Redirect1Begin(mNewChannel, mNewURI, mRedirectFlags, 
+    mChild->Redirect1Begin(mNewChannelId, mNewURI, mRedirectFlags,
                            mResponseHead); 
   }
  private:
   HttpChannelChild*   mChild;
-  PHttpChannelChild*  mNewChannel;
+  PRUint32            mNewChannelId;
   IPC::URI            mNewURI;
   PRUint32            mRedirectFlags;
   nsHttpResponseHead  mResponseHead;
 };
 
 bool
-HttpChannelChild::RecvRedirect1Begin(PHttpChannelChild* newChannel,
-                                     const IPC::URI& newURI,
+HttpChannelChild::RecvRedirect1Begin(const PRUint32& newChannelId,
+                                     const URI& newUri,
                                      const PRUint32& redirectFlags,
                                      const nsHttpResponseHead& responseHead)
 {
   if (ShouldEnqueue()) {
-    EnqueueEvent(new Redirect1Event(this, newChannel, newURI, redirectFlags, 
+    EnqueueEvent(new Redirect1Event(this, newChannelId, newUri, redirectFlags,
                                     responseHead)); 
   } else {
-    Redirect1Begin(newChannel, newURI, redirectFlags, responseHead);
+    Redirect1Begin(newChannelId, newUri, redirectFlags, responseHead);
   }
   return true;
 }
 
 void
-HttpChannelChild::Redirect1Begin(PHttpChannelChild* newChannel,
+HttpChannelChild::Redirect1Begin(const PRUint32& newChannelId,
                                  const IPC::URI& newURI,
                                  const PRUint32& redirectFlags,
                                  const nsHttpResponseHead& responseHead)
 {
-  HttpChannelChild* 
-    newHttpChannelChild = static_cast<HttpChannelChild*>(newChannel);
+  nsresult rv;
+
+  nsCOMPtr<nsIIOService> ioService;
+  rv = gHttpHandler->GetIOService(getter_AddRefs(ioService));
+  if (NS_FAILED(rv)) {
+    // Veto redirect.  nsHttpChannel decides to cancel or continue.
+    OnRedirectVerifyCallback(rv);
+    return;
+  }
+
   nsCOMPtr<nsIURI> uri(newURI);
 
-  nsresult rv = 
-    newHttpChannelChild->HttpBaseChannel::Init(uri, mCaps,
-                                               mConnectionInfo->ProxyInfo());
+  nsCOMPtr<nsIChannel> newChannel;
+  rv = ioService->NewChannelFromURI(uri, getter_AddRefs(newChannel));
   if (NS_FAILED(rv)) {
-    // Veto redirect.  nsHttpChannel decides to cancel or continue. 
-    SendRedirect2Verify(rv, newHttpChannelChild->mRequestHeaders);
+    // Veto redirect.  nsHttpChannel decides to cancel or continue.
+    OnRedirectVerifyCallback(rv);
     return;
   }
 
   // We won't get OnStartRequest, set cookies here.
   mResponseHead = new nsHttpResponseHead(responseHead);
   SetCookie(mResponseHead->PeekHeader(nsHttp::Set_Cookie));
 
   PRBool preserveMethod = (mResponseHead->Status() == 307);
-  rv = SetupReplacementChannel(uri, newHttpChannelChild, preserveMethod);
+  rv = SetupReplacementChannel(uri, newChannel, preserveMethod);
   if (NS_FAILED(rv)) {
     // Veto redirect.  nsHttpChannel decides to cancel or continue.
-    SendRedirect2Verify(rv, newHttpChannelChild->mRequestHeaders);
+    OnRedirectVerifyCallback(rv);
     return;
   }
 
-  mRedirectChannelChild = newHttpChannelChild;
+  mRedirectChannelChild = do_QueryInterface(newChannel);
+  if (mRedirectChannelChild) {
+    mRedirectChannelChild->ConnectParent(newChannelId);
+  } else {
+    NS_ERROR("Redirecting to a protocol that doesn't support universal protocol redirect");
+  }
 
   rv = gHttpHandler->AsyncOnChannelRedirect(this, 
-                                            newHttpChannelChild, 
+                                            newChannel,
                                             redirectFlags);
   if (NS_FAILED(rv))
     OnRedirectVerifyCallback(rv);
 }
 
 class Redirect3Event : public ChannelEvent
 {
  public:
@@ -685,33 +699,62 @@ HttpChannelChild::RecvRedirect3Complete(
     Redirect3Complete();
   }
   return true;
 }
 
 void
 HttpChannelChild::Redirect3Complete()
 {
-  nsresult rv;
+  nsresult rv = NS_OK;
+
+  // Chrome channel has been AsyncOpen'd.  Reflect this in child.
+  if (mRedirectChannelChild)
+    rv = mRedirectChannelChild->CompleteRedirectSetup(mListener,
+                                                      mListenerContext);
 
   // Redirecting to new channel: shut this down and init new channel
   if (mLoadGroup)
     mLoadGroup->RemoveRequest(this, nsnull, NS_BINDING_ABORTED);
 
-  // Chrome channel has been AsyncOpen'd.  Reflect this in child.
-  rv = mRedirectChannelChild->CompleteRedirectSetup(mListener, 
-                                                    mListenerContext);
   if (NS_FAILED(rv))
     NS_WARNING("CompleteRedirectSetup failed, HttpChannelChild already open?");
 
   // Release ref to new channel.
   mRedirectChannelChild = nsnull;
 }
 
-nsresult
+//-----------------------------------------------------------------------------
+// HttpChannelChild::nsIChildChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpChannelChild::ConnectParent(PRUint32 id)
+{
+  mozilla::dom::TabChild* tabChild = nsnull;
+  nsCOMPtr<nsITabChild> iTabChild;
+  GetCallback(iTabChild);
+  if (iTabChild) {
+    tabChild = static_cast<mozilla::dom::TabChild*>(iTabChild.get());
+  }
+
+  // The socket transport in the chrome process now holds a logical ref to us
+  // until OnStopRequest, or we do a redirect, or we hit an IPDL error.
+  AddIPDLReference();
+
+  if (!gNeckoChild->SendPHttpChannelConstructor(this, tabChild))
+    return NS_ERROR_FAILURE;
+
+  if (!SendConnectChannel(id))
+    return NS_ERROR_FAILURE;
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
 HttpChannelChild::CompleteRedirectSetup(nsIStreamListener *listener, 
                                         nsISupports *aContext)
 {
   LOG(("HttpChannelChild::FinishRedirectSetup [this=%x]\n", this));
 
   NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
   NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
 
@@ -739,27 +782,40 @@ HttpChannelChild::CompleteRedirectSetup(
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIAsyncVerifyRedirectCallback
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelChild::OnRedirectVerifyCallback(nsresult result)
 {
-  // Cookies may have been changed by redirect observers
-  mRedirectChannelChild->AddCookiesToRequest();
-  // Must not be called until after redirect observers called.
-  mRedirectChannelChild->SetOriginalURI(mRedirectOriginalURI);
+  nsCOMPtr<nsIHttpChannel> newHttpChannel =
+      do_QueryInterface(mRedirectChannelChild);
+
+  if (newHttpChannel) {
+    // Must not be called until after redirect observers called.
+    newHttpChannel->SetOriginalURI(mRedirectOriginalURI);
+  }
+
+  RequestHeaderTuples emptyHeaders;
+  RequestHeaderTuples* headerTuples = &emptyHeaders;
+
+  nsCOMPtr<nsIHttpChannelChild> newHttpChannelChild =
+      do_QueryInterface(mRedirectChannelChild);
+  if (newHttpChannelChild && NS_SUCCEEDED(result)) {
+    newHttpChannelChild->AddCookiesToRequest();
+    newHttpChannelChild->GetHeaderTuples(&headerTuples);
+  }
 
   // After we verify redirect, nsHttpChannel may hit the network: must give
   // "http-on-modify-request" observers the chance to cancel before that.
   if (NS_SUCCEEDED(result))
-    gHttpHandler->OnModifyRequest(mRedirectChannelChild);
+    gHttpHandler->OnModifyRequest(newHttpChannel);
 
-  return SendRedirect2Verify(result, mRedirectChannelChild->mRequestHeaders);
+  return SendRedirect2Verify(result, *headerTuples);
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIRequest
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelChild::Cancel(nsresult status)
@@ -1241,12 +1297,27 @@ HttpChannelChild::Flush()
   NS_ENSURE_SUCCESS(rv, rv);
 
   if (mIPCOpen)
     SendUpdateAssociatedContentSecurity(hi, low, broken, no);
 
   return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// HttpChannelChild::nsIHttpChannelChild
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP HttpChannelChild::AddCookiesToRequest()
+{
+  HttpBaseChannel::AddCookiesToRequest();
+  return NS_OK;
+}
+
+NS_IMETHODIMP HttpChannelChild::GetHeaderTuples(RequestHeaderTuples **aHeaderTuples)
+{
+  *aHeaderTuples = &mRequestHeaders;
+  return NS_OK;
+}
+
 //------------------------------------------------------------------------------
 
 }} // mozilla::net
-
--- a/netwerk/protocol/http/HttpChannelChild.h
+++ b/netwerk/protocol/http/HttpChannelChild.h
@@ -56,39 +56,45 @@
 #include "nsIApplicationCache.h"
 #include "nsIApplicationCacheChannel.h"
 #include "nsIUploadChannel2.h"
 #include "nsIResumableChannel.h"
 #include "nsIProxiedChannel.h"
 #include "nsITraceableChannel.h"
 #include "nsIAsyncVerifyRedirectCallback.h"
 #include "nsIAssociatedContentSecurity.h"
+#include "nsIChildChannel.h"
+#include "nsIHttpChannelChild.h"
 
 namespace mozilla {
 namespace net {
 
 class HttpChannelChild : public PHttpChannelChild
                        , public HttpBaseChannel
                        , public nsICacheInfoChannel
                        , public nsIProxiedChannel
                        , public nsITraceableChannel
                        , public nsIApplicationCacheChannel
                        , public nsIAsyncVerifyRedirectCallback
                        , public nsIAssociatedContentSecurity
+                       , public nsIChildChannel
+                       , public nsIHttpChannelChild
                        , public ChannelEventQueue<HttpChannelChild>
 {
 public:
   NS_DECL_ISUPPORTS_INHERITED
   NS_DECL_NSICACHEINFOCHANNEL
   NS_DECL_NSIPROXIEDCHANNEL
   NS_DECL_NSITRACEABLECHANNEL
   NS_DECL_NSIAPPLICATIONCACHECONTAINER
   NS_DECL_NSIAPPLICATIONCACHECHANNEL
   NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK
   NS_DECL_NSIASSOCIATEDCONTENTSECURITY
+  NS_DECL_NSICHILDCHANNEL
+  NS_DECL_NSIHTTPCHANNELCHILD
 
   HttpChannelChild();
   virtual ~HttpChannelChild();
 
   // Methods HttpBaseChannel didn't implement for us or that we override.
   //
   // nsIRequest
   NS_IMETHOD Cancel(nsresult status);
@@ -103,20 +109,16 @@ public:
                               PRBool aMerge);
   // nsIHttpChannelInternal
   NS_IMETHOD SetupFallbackChannel(const char *aFallbackKey);
   // nsISupportsPriority
   NS_IMETHOD SetPriority(PRInt32 value);
   // nsIResumableChannel
   NS_IMETHOD ResumeAt(PRUint64 startPos, const nsACString& entityID);
 
-  // Final setup when redirect has proceeded successfully in chrome
-  nsresult CompleteRedirectSetup(nsIStreamListener *listener, 
-                                 nsISupports *aContext);
-
   // IPDL holds a reference while the PHttpChannel protocol is live (starting at
   // AsyncOpen, and ending at either OnStopRequest or any IPDL error, either of
   // which call NeckoChild::DeallocPHttpChannel()).
   void AddIPDLReference();
   void ReleaseIPDLReference();
 
   bool IsSuspended();
 
@@ -131,30 +133,30 @@ protected:
                           const nsCString& securityInfoSerialization);
   bool RecvOnDataAvailable(const nsCString& data, 
                            const PRUint32& offset,
                            const PRUint32& count);
   bool RecvOnStopRequest(const nsresult& statusCode);
   bool RecvOnProgress(const PRUint64& progress, const PRUint64& progressMax);
   bool RecvOnStatus(const nsresult& status, const nsString& statusArg);
   bool RecvCancelEarly(const nsresult& status);
-  bool RecvRedirect1Begin(PHttpChannelChild* newChannel,
+  bool RecvRedirect1Begin(const PRUint32& newChannel,
                           const URI& newURI,
                           const PRUint32& redirectFlags,
                           const nsHttpResponseHead& responseHead);
   bool RecvRedirect3Complete();
   bool RecvAssociateApplicationCache(const nsCString& groupID,
                                      const nsCString& clientID);
   bool RecvDeleteSelf();
 
   bool GetAssociatedContentSecurity(nsIAssociatedContentSecurity** res = nsnull);
 
 private:
   RequestHeaderTuples mRequestHeaders;
-  nsRefPtr<HttpChannelChild> mRedirectChannelChild;
+  nsCOMPtr<nsIChildChannel> mRedirectChannelChild;
   nsCOMPtr<nsIURI> mRedirectOriginalURI;
   nsCOMPtr<nsISupports> mSecurityInfo;
 
   PRPackedBool mIsFromCache;
   PRPackedBool mCacheEntryAvailable;
   PRUint32     mCacheExpirationTime;
   nsCString    mCachedCharset;
 
@@ -176,17 +178,18 @@ private:
                           const nsCString& securityInfoSerialization);
   void OnDataAvailable(const nsCString& data, 
                        const PRUint32& offset,
                        const PRUint32& count);
   void OnStopRequest(const nsresult& statusCode);
   void OnProgress(const PRUint64& progress, const PRUint64& progressMax);
   void OnStatus(const nsresult& status, const nsString& statusArg);
   void OnCancel(const nsresult& status);
-  void Redirect1Begin(PHttpChannelChild* newChannel, const URI& newURI,
+  void Redirect1Begin(const PRUint32& newChannelId,
+                      const URI& newUri,
                       const PRUint32& redirectFlags,
                       const nsHttpResponseHead& responseHead);
   void Redirect3Complete();
   void DeleteSelf();
 
   friend class StartRequestEvent;
   friend class StopRequestEvent;
   friend class DataAvailableEvent;
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -37,30 +37,32 @@
  * the provisions above, a recipient may use your version of this file under
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "mozilla/net/HttpChannelParent.h"
 #include "mozilla/dom/TabParent.h"
 #include "mozilla/net/NeckoParent.h"
+#include "mozilla/unused.h"
 #include "HttpChannelParentListener.h"
 #include "nsHttpChannel.h"
 #include "nsHttpHandler.h"
 #include "nsNetUtil.h"
 #include "nsISupportsPriority.h"
 #include "nsIAuthPromptProvider.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIBadCertListener2.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsSerializationHelper.h"
 #include "nsISerializable.h"
 #include "nsIAssociatedContentSecurity.h"
 #include "nsIApplicationCacheService.h"
 #include "nsIOfflineCacheUpdate.h"
+#include "nsIRedirectChannelRegistrar.h"
 
 namespace mozilla {
 namespace net {
 
 HttpChannelParent::HttpChannelParent(PBrowserParent* iframeEmbedding)
 : mIPCClosed(false)
 {
   // Ensure gHttpHandler is initialized: we need the atom table up and running.
@@ -84,18 +86,41 @@ HttpChannelParent::ActorDestroy(ActorDes
   // yet, but we must not send any more msgs to child.
   mIPCClosed = true;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::nsISupports
 //-----------------------------------------------------------------------------
 
-NS_IMPL_ISUPPORTS1(HttpChannelParent,
-                   nsIProgressEventSink)
+NS_IMPL_ISUPPORTS6(HttpChannelParent,
+                   nsIInterfaceRequestor,
+                   nsIProgressEventSink,
+                   nsIRequestObserver,
+                   nsIStreamListener,
+                   nsIParentChannel,
+                   nsIParentRedirectingChannel)
+
+//-----------------------------------------------------------------------------
+// HttpChannelParent::nsIInterfaceRequestor
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpChannelParent::GetInterface(const nsIID& aIID, void **result)
+{
+  if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider)) ||
+      aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) {
+    if (!mTabParent)
+      return NS_NOINTERFACE;
+
+    return mTabParent->QueryInterface(aIID, result);
+  }
+
+  return QueryInterface(aIID, result);
+}
 
 //-----------------------------------------------------------------------------
 // HttpChannelParent::PHttpChannelParent
 //-----------------------------------------------------------------------------
 
 bool 
 HttpChannelParent::RecvAsyncOpen(const IPC::URI&            aURI,
                                  const IPC::URI&            aOriginalURI,
@@ -151,19 +176,20 @@ HttpChannelParent::RecvAsyncOpen(const I
     httpChan->SetLoadFlags(loadFlags);
 
   for (PRUint32 i = 0; i < requestHeaders.Length(); i++) {
     httpChan->SetRequestHeader(requestHeaders[i].mHeader,
                                requestHeaders[i].mValue,
                                requestHeaders[i].mMerge);
   }
 
-  mChannelListener = new HttpChannelParentListener(this);
+  nsRefPtr<HttpChannelParentListener> channelListener =
+      new HttpChannelParentListener(this);
 
-  httpChan->SetNotificationCallbacks(mChannelListener);
+  httpChan->SetNotificationCallbacks(channelListener);
 
   httpChan->SetRequestMethod(nsDependentCString(requestMethod.get()));
 
   nsCOMPtr<nsIInputStream> stream(uploadStream);
   if (stream) {
     httpChan->InternalSetUploadStream(stream);
     httpChan->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   }
@@ -204,33 +230,46 @@ HttpChannelParent::RecvAsyncOpen(const I
                                                            &setChooseApplicationCache);
 
         if (setChooseApplicationCache && NS_SUCCEEDED(rv))
           appCacheChan->SetChooseApplicationCache(PR_TRUE);
       }
     }
   }
 
-  rv = httpChan->AsyncOpen(mChannelListener, nsnull);
+  rv = httpChan->AsyncOpen(channelListener, nsnull);
   if (NS_FAILED(rv))
     return SendCancelEarly(rv);
 
   return true;
 }
 
+bool
+HttpChannelParent::RecvConnectChannel(const PRUint32& channelId)
+{
+  nsresult rv;
+
+  LOG(("Looking for a registered channel [this=%p, id=%d]", this, channelId));
+  rv = NS_LinkRedirectChannels(channelId, this, getter_AddRefs(mChannel));
+  LOG(("  found channel %p, rv=%08x", mChannel.get(), rv));
+
+  return true;
+}
+
 bool 
 HttpChannelParent::RecvSetPriority(const PRUint16& priority)
 {
   nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
   httpChan->SetPriority(priority);
 
-  if (mChannelListener && mChannelListener->mRedirectChannel &&
-      mChannelListener->mRedirectChannel != this)
-    return mChannelListener->mRedirectChannel->RecvSetPriority(priority);
-  
+  nsCOMPtr<nsISupportsPriority> priorityRedirectChannel =
+      do_QueryInterface(mRedirectChannel);
+  if (priorityRedirectChannel)
+    priorityRedirectChannel->SetPriority(priority);
+
   return true;
 }
 
 bool
 HttpChannelParent::RecvSuspend()
 {
   mChannel->Suspend();
   return true;
@@ -286,18 +325,31 @@ HttpChannelParent::RecvUpdateAssociatedC
 
   return true;
 }
 
 bool
 HttpChannelParent::RecvRedirect2Verify(const nsresult& result, 
                                        const RequestHeaderTuples& changedHeaders)
 {
-  if (mChannelListener)
-    mChannelListener->OnContentRedirectResultReceived(result, changedHeaders);
+  if (NS_SUCCEEDED(result)) {
+    nsCOMPtr<nsIHttpChannel> newHttpChannel =
+        do_QueryInterface(mRedirectChannel);
+
+    if (newHttpChannel) {
+      for (PRUint32 i = 0; i < changedHeaders.Length(); i++) {
+        newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
+                                         changedHeaders[i].mValue,
+                                         changedHeaders[i].mMerge);
+      }
+    }
+  }
+
+  mRedirectCallback->OnRedirectVerifyCallback(result);
+  mRedirectCallback = nsnull;
   return true;
 }
 
 bool
 HttpChannelParent::RecvDocumentChannelCleanup()
 {
   // We must clear the cache entry here, else we'll block other channels from
   // reading it if we've got it open for writing.  
@@ -310,28 +362,24 @@ bool
 HttpChannelParent::RecvMarkOfflineCacheEntryAsForeign()
 {
   nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
   httpChan->MarkOfflineCacheEntryAsForeign();
   return true;
 }
 
 //-----------------------------------------------------------------------------
-// nsIRequestObserver and nsIStreamListener methods equivalents
+// HttpChannelParent::nsIRequestObserver
 //-----------------------------------------------------------------------------
 
-nsresult
+NS_IMETHODIMP
 HttpChannelParent::OnStartRequest(nsIRequest *aRequest, nsISupports *aContext)
 {
   LOG(("HttpChannelParent::OnStartRequest [this=%x]\n", this));
 
-  // We need this member only to call OnContentRedirectResultReceived on it, 
-  // that will for sure not happen when we get here.  Throw it away ASAP.
-  mChannelListener = nsnull;
-
   nsHttpChannel *chan = static_cast<nsHttpChannel *>(aRequest);
   nsHttpResponseHead *responseHead = chan->GetResponseHead();
   nsHttpRequestHead  *requestHead = chan->GetRequestHead();
   PRBool isFromCache = false;
   chan->IsFromCache(&isFromCache);
   PRUint32 expirationTime = nsICache::NO_EXPIRATION_TIME;
   chan->GetCacheTokenExpirationTime(&expirationTime);
   nsCString cachedCharset;
@@ -388,30 +436,34 @@ HttpChannelParent::OnStartRequest(nsIReq
                           mCacheDescriptor ? PR_TRUE : PR_FALSE,
                           expirationTime, cachedCharset, secInfoSerialization)) 
   {
     return NS_ERROR_UNEXPECTED; 
   }
   return NS_OK;
 }
 
-nsresult
+NS_IMETHODIMP
 HttpChannelParent::OnStopRequest(nsIRequest *aRequest, 
                                  nsISupports *aContext, 
                                  nsresult aStatusCode)
 {
   LOG(("HttpChannelParent::OnStopRequest: [this=%x status=%ul]\n", 
        this, aStatusCode));
 
   if (mIPCClosed || !SendOnStopRequest(aStatusCode))
     return NS_ERROR_UNEXPECTED; 
   return NS_OK;
 }
 
-nsresult
+//-----------------------------------------------------------------------------
+// HttpChannelParent::nsIStreamListener
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
 HttpChannelParent::OnDataAvailable(nsIRequest *aRequest, 
                                    nsISupports *aContext, 
                                    nsIInputStream *aInputStream, 
                                    PRUint32 aOffset, 
                                    PRUint32 aCount)
 {
   LOG(("HttpChannelParent::OnDataAvailable [this=%x]\n", this));
  
@@ -447,10 +499,67 @@ HttpChannelParent::OnStatus(nsIRequest *
                             nsresult aStatus, 
                             const PRUnichar *aStatusArg)
 {
   if (mIPCClosed || !SendOnStatus(aStatus, nsString(aStatusArg)))
     return NS_ERROR_UNEXPECTED;
   return NS_OK;
 }
 
+//-----------------------------------------------------------------------------
+// HttpChannelParent::nsIParentChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpChannelParent::Delete()
+{
+  if (!mIPCClosed)
+    SendDeleteSelf();
+
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// HttpChannelParent::nsIParentRedirectingChannel
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+HttpChannelParent::StartRedirect(PRUint32 newChannelId,
+                                 nsIChannel* newChannel,
+                                 PRUint32 redirectFlags,
+                                 nsIAsyncVerifyRedirectCallback* callback)
+{
+  if (mIPCClosed)
+    return NS_BINDING_ABORTED;
+
+  nsCOMPtr<nsIURI> newURI;
+  newChannel->GetURI(getter_AddRefs(newURI));
+
+  nsHttpChannel *httpChan = static_cast<nsHttpChannel *>(mChannel.get());
+  nsHttpResponseHead *responseHead = httpChan->GetResponseHead();
+  bool result = SendRedirect1Begin(newChannelId,
+                                   IPC::URI(newURI),
+                                   redirectFlags,
+                                   responseHead ? *responseHead
+                                                : nsHttpResponseHead());
+  if (!result)
+    return NS_BINDING_ABORTED;
+
+  // Result is handled in RecvRedirect2Verify above
+
+  mRedirectChannel = newChannel;
+  mRedirectCallback = callback;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+HttpChannelParent::CompleteRedirect(PRBool succeeded)
+{
+  if (succeeded && !mIPCClosed) {
+    // TODO: check return value: assume child dead if failed
+    unused << SendRedirect3Complete();
+  }
+
+  mRedirectChannel = nsnull;
+  return NS_OK;
+}
+
 }} // mozilla::net
-
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -41,47 +41,43 @@
 
 #ifndef mozilla_net_HttpChannelParent_h
 #define mozilla_net_HttpChannelParent_h
 
 #include "nsHttp.h"
 #include "mozilla/dom/PBrowserParent.h"
 #include "mozilla/net/PHttpChannelParent.h"
 #include "mozilla/net/NeckoCommon.h"
+#include "nsIParentRedirectingChannel.h"
 #include "nsIProgressEventSink.h"
 #include "nsITabParent.h"
 
 using namespace mozilla::dom;
 
 class nsICacheEntryDescriptor;
 
 namespace mozilla {
 namespace net {
 
 class HttpChannelParentListener;
 
 class HttpChannelParent : public PHttpChannelParent
+                        , public nsIParentRedirectingChannel
                         , public nsIProgressEventSink
+                        , public nsIInterfaceRequestor
 {
 public:
   NS_DECL_ISUPPORTS
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSISTREAMLISTENER
+  NS_DECL_NSIPARENTCHANNEL
+  NS_DECL_NSIPARENTREDIRECTINGCHANNEL
   NS_DECL_NSIPROGRESSEVENTSINK
+  NS_DECL_NSIINTERFACEREQUESTOR
 
-  // Make these non-virtual for a little performance benefit
-  nsresult OnStartRequest(nsIRequest *aRequest, 
-                          nsISupports *aContext);
-  nsresult OnStopRequest(nsIRequest *aRequest, 
-                         nsISupports *aContext, 
-                         nsresult aStatusCode);
-  nsresult OnDataAvailable(nsIRequest *aRequest, 
-                           nsISupports *aContext, 
-                           nsIInputStream *aInputStream, 
-                           PRUint32 aOffset, 
-                           PRUint32 aCount);
-  
   HttpChannelParent(PBrowserParent* iframeEmbedding);
   virtual ~HttpChannelParent();
 
 protected:
   virtual bool RecvAsyncOpen(const IPC::URI&            uri,
                              const IPC::URI&            originalUri,
                              const IPC::URI&            docUri,
                              const IPC::URI&            referrerUri,
@@ -95,16 +91,17 @@ protected:
                              const PRBool&              allowPipelining,
                              const PRBool&              forceAllowThirdPartyCookie,
                              const bool&                doResumeAt,
                              const PRUint64&            startPos,
                              const nsCString&           entityID,
                              const bool&                chooseApplicationCache,
                              const nsCString&           appCacheClientID);
 
+  virtual bool RecvConnectChannel(const PRUint32& channelId);
   virtual bool RecvSetPriority(const PRUint16& priority);
   virtual bool RecvSetCacheTokenCachedCharset(const nsCString& charset);
   virtual bool RecvSuspend();
   virtual bool RecvResume();
   virtual bool RecvCancel(const nsresult& status);
   virtual bool RecvRedirect2Verify(const nsresult& result,
                                    const RequestHeaderTuples& changedHeaders);
   virtual bool RecvUpdateAssociatedContentSecurity(const PRInt32& high,
@@ -117,17 +114,19 @@ protected:
   virtual void ActorDestroy(ActorDestroyReason why);
 
 protected:
   friend class mozilla::net::HttpChannelParentListener;
   nsCOMPtr<nsITabParent> mTabParent;
 
 private:
   nsCOMPtr<nsIChannel> mChannel;
-  nsRefPtr<HttpChannelParentListener> mChannelListener;
   nsCOMPtr<nsICacheEntryDescriptor> mCacheDescriptor;
   bool mIPCClosed;                // PHttpChannel actor has been Closed()
+
+  nsCOMPtr<nsIChannel> mRedirectChannel;
+  nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/HttpChannelParentListener.cpp
+++ b/netwerk/protocol/http/HttpChannelParentListener.cpp
@@ -51,24 +51,28 @@
 #include "nsIAuthPromptProvider.h"
 #include "nsIDocShellTreeItem.h"
 #include "nsIBadCertListener2.h"
 #include "nsICacheEntryDescriptor.h"
 #include "nsSerializationHelper.h"
 #include "nsISerializable.h"
 #include "nsIAssociatedContentSecurity.h"
 #include "nsISecureBrowserUI.h"
+#include "nsIRedirectChannelRegistrar.h"
+
+#include "nsIFTPChannel.h"
 
 using mozilla::unused;
 
 namespace mozilla {
 namespace net {
 
 HttpChannelParentListener::HttpChannelParentListener(HttpChannelParent* aInitialChannel)
   : mActiveChannel(aInitialChannel)
+  , mRedirectChannelId(0)
 {
 }
 
 HttpChannelParentListener::~HttpChannelParentListener()
 {
 }
 
 //-----------------------------------------------------------------------------
@@ -132,171 +136,120 @@ HttpChannelParentListener::OnDataAvailab
 
 //-----------------------------------------------------------------------------
 // HttpChannelParentListener::nsIInterfaceRequestor
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP 
 HttpChannelParentListener::GetInterface(const nsIID& aIID, void **result)
 {
-  if (aIID.Equals(NS_GET_IID(nsIAuthPromptProvider))) {
-    if (!mActiveChannel || !mActiveChannel->mTabParent)
-      return NS_NOINTERFACE;
-    return mActiveChannel->mTabParent->QueryInterface(aIID, result);
-  }
-
-  if (aIID.Equals(NS_GET_IID(nsISecureBrowserUI))) {
-    if (!mActiveChannel || !mActiveChannel->mTabParent)
-      return NS_NOINTERFACE;
-    return mActiveChannel->mTabParent->QueryInterface(aIID, result);
-  }
-
-  if (aIID.Equals(NS_GET_IID(nsIProgressEventSink))) {
-    if (!mActiveChannel)
-      return NS_NOINTERFACE;
-    return mActiveChannel->QueryInterface(aIID, result);
+  if (aIID.Equals(NS_GET_IID(nsIChannelEventSink)) ||
+      aIID.Equals(NS_GET_IID(nsIHttpEventSink))  ||
+      aIID.Equals(NS_GET_IID(nsIRedirectResultListener)))
+  {
+    return QueryInterface(aIID, result);
   }
 
-  // TODO: 575494: once we're confident we're handling all needed interfaces,
-  // remove all code below and simply "return QueryInterface(aIID, result)"
-  if (// Known interface calls:
+  nsCOMPtr<nsIInterfaceRequestor> ir;
+  if (mActiveChannel &&
+      NS_SUCCEEDED(CallQueryInterface(mActiveChannel.get(),
+                                      getter_AddRefs(ir))))
+  {
+    return ir->GetInterface(aIID, result);
+  }
 
-      // FIXME: HTTP Authorization (bug 537782):
-      // nsHttpChannel first tries to get this as an nsIAuthPromptProvider; if that
-      // fails, it tries as an nsIAuthPrompt2, and if that fails, an nsIAuthPrompt.
-      // See nsHttpChannel::GetAuthPrompt().  So if we can return any one of these,
-      // HTTP auth should be all set.  The other two if checks can be eventually
-      // deleted.
-      aIID.Equals(NS_GET_IID(nsIAuthPrompt2)) ||
-      aIID.Equals(NS_GET_IID(nsIAuthPrompt))  ||
-      // FIXME: redirects (bug 536294):
-      // The likely solution here is for this class to implement nsIChannelEventSink
-      // and nsIHttpEventSink (and forward calls to any real sinks in the child), in
-      // which case QueryInterface() will do the work here and these if statements
-      // can be eventually discarded.
-      aIID.Equals(NS_GET_IID(nsIChannelEventSink)) || 
-      aIID.Equals(NS_GET_IID(nsIHttpEventSink))  ||
-      aIID.Equals(NS_GET_IID(nsIRedirectResultListener))  ||
-      // FIXME: application cache (bug 536295):
-      aIID.Equals(NS_GET_IID(nsIApplicationCacheContainer)) ||
-      // FIXME:  bug 561830: when fixed, we shouldn't be asked for this interface
-      aIID.Equals(NS_GET_IID(nsIDocShellTreeItem)) ||
-      // Let this return NS_ERROR_NO_INTERFACE: it's OK to not provide it.
-      aIID.Equals(NS_GET_IID(nsIBadCertListener2))) 
-  {
-    return QueryInterface(aIID, result);
-  } else {
-    nsPrintfCString msg(2000, 
-       "HttpChannelParentListener::GetInterface: interface UUID=%s not yet supported! "
-       "Use 'grep -ri UUID <mozilla_src>' to find the name of the interface, "
-       "check http://tinyurl.com/255ojvu to see if a bug has already been "
-       "filed, and if not, add one and make it block bug 516730. Thanks!",
-       aIID.ToString());
-    NECKO_MAYBE_ABORT(msg);
-    return NS_NOINTERFACE;
-  }
+  return NS_NOINTERFACE;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParentListener::nsIChannelEventSink
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelParentListener::AsyncOnChannelRedirect(
                                     nsIChannel *oldChannel,
                                     nsIChannel *newChannel,
                                     PRUint32 redirectFlags,
                                     nsIAsyncVerifyRedirectCallback* callback)
 {
-  if (mActiveChannel->mIPCClosed)
-    return NS_BINDING_ABORTED;
-
-  // Create new PHttpChannel
-  PBrowserParent* browser = mActiveChannel->mTabParent ?
-      static_cast<TabParent*>(mActiveChannel->mTabParent.get()) : nsnull;
-  mRedirectChannel = static_cast<HttpChannelParent *>
-      (mActiveChannel->Manager()->SendPHttpChannelConstructor(browser));
-
-  // Join it with the correct channel
-  mRedirectChannel->mChannel = newChannel;
+  nsresult rv;
 
-  // Let the new channel also keep the wrapper in case we get another redirect
-  // response, it wouldn't be able to send back the redirect result.
-  mRedirectChannel->mChannelListener = this;
-
-  // And finally, let the content process decide to redirect or not.
-  mRedirectCallback = callback;
-
-  nsCOMPtr<nsIURI> newURI;
-  newChannel->GetURI(getter_AddRefs(newURI));
-
-  nsHttpChannel *oldHttpChannel = static_cast<nsHttpChannel *>(oldChannel);
-  nsHttpResponseHead *responseHead = oldHttpChannel->GetResponseHead();
+  // Register the new channel and obtain id for it
+  nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
+      do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // TODO: check mActiveChannel->mIPCClosed and return val from Send function
-  
-  unused << mActiveChannel->SendRedirect1Begin(mRedirectChannel,
-                                               IPC::URI(newURI),
-                                               redirectFlags,
-                                               responseHead ? *responseHead 
-                                                            : nsHttpResponseHead());
+  rv = registrar->RegisterChannel(newChannel, &mRedirectChannelId);
+  NS_ENSURE_SUCCESS(rv, rv);
 
-  // mActiveChannel gets the response in RecvRedirect2Verify and forwards it
-  // to this wrapper through OnContentRedirectResultReceived
-
-  return NS_OK;
-}
+  LOG(("Registered %p channel under id=%d", newChannel, mRedirectChannelId));
 
-void
-HttpChannelParentListener::OnContentRedirectResultReceived(
-                                const nsresult result,
-                                const RequestHeaderTuples& changedHeaders)
-{
-  nsHttpChannel* newHttpChannel = 
-      static_cast<nsHttpChannel*>(mRedirectChannel->mChannel.get());
-
-  if (NS_SUCCEEDED(result)) {
-    for (PRUint32 i = 0; i < changedHeaders.Length(); i++) {
-      newHttpChannel->SetRequestHeader(changedHeaders[i].mHeader,
-                                       changedHeaders[i].mValue,
-                                       changedHeaders[i].mMerge);
-    }
+  nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
+      do_QueryInterface(mActiveChannel);
+  if (!activeRedirectingChannel) {
+    NS_RUNTIMEABORT("Channel got a redirect response, but doesn't implement "
+                    "nsIParentRedirectingChannel to handle it.");
   }
 
-  mRedirectCallback->OnRedirectVerifyCallback(result);
-  mRedirectCallback = nsnull;
+  return activeRedirectingChannel->StartRedirect(mRedirectChannelId,
+                                                 newChannel,
+                                                 redirectFlags,
+                                                 callback);
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelParentListener::nsIRedirectResultListener
 //-----------------------------------------------------------------------------
 
 NS_IMETHODIMP
 HttpChannelParentListener::OnRedirectResult(PRBool succeeded)
 {
-  if (!mRedirectChannel) {
-    // Redirect might get canceled before we got AsyncOnChannelRedirect
-    return NS_OK;
-  }
+  nsresult rv;
+
+  nsCOMPtr<nsIParentChannel> redirectChannel;
+  if (mRedirectChannelId) {
+    nsCOMPtr<nsIRedirectChannelRegistrar> registrar =
+        do_GetService("@mozilla.org/redirectchannelregistrar;1", &rv);
+    NS_ENSURE_SUCCESS(rv, rv);
+
+    rv = registrar->GetParentChannel(mRedirectChannelId,
+                                     getter_AddRefs(redirectChannel));
+    if (NS_FAILED(rv) || !redirectChannel) {
+      // Redirect might get canceled before we got AsyncOnChannelRedirect
+      LOG(("Registered parent channel not found under id=%d", mRedirectChannelId));
 
-  if (succeeded && !mActiveChannel->mIPCClosed) {
-    // TODO: check return value: assume child dead if failed
-    unused << mActiveChannel->SendRedirect3Complete();
+      nsCOMPtr<nsIChannel> newChannel;
+      rv = registrar->GetRegisteredChannel(mRedirectChannelId,
+                                           getter_AddRefs(newChannel));
+      NS_ASSERTION(newChannel, "Already registered channel not found");
+
+      if (NS_SUCCEEDED(rv))
+        newChannel->Cancel(NS_BINDING_ABORTED);
+    }
+
+    // Release all previously registered channels, they are no longer need to be
+    // kept in the registrar from this moment.
+    registrar->DeregisterChannels(mRedirectChannelId);
+
+    mRedirectChannelId = 0;
   }
 
-  HttpChannelParent* channelToDelete;
+  nsCOMPtr<nsIParentRedirectingChannel> activeRedirectingChannel =
+      do_QueryInterface(mActiveChannel);
+  NS_ABORT_IF_FALSE(activeRedirectingChannel,
+    "Channel finished a redirect response, but doesn't implement "
+    "nsIParentRedirectingChannel to complete it.");
+
+  activeRedirectingChannel->CompleteRedirect(succeeded);
+
   if (succeeded) {
     // Switch to redirect channel and delete the old one.
-    channelToDelete = mActiveChannel;
-    mActiveChannel = mRedirectChannel;
-  } else {
+    mActiveChannel->Delete();
+    mActiveChannel = redirectChannel;
+  } else if (redirectChannel) {
     // Delete the redirect target channel: continue using old channel
-    channelToDelete = mRedirectChannel;
+    redirectChannel->Delete();
   }
 
-  if (!channelToDelete->mIPCClosed)
-    unused << channelToDelete->SendDeleteSelf();
-  mRedirectChannel = nsnull;
-
   return NS_OK;
 }
 
 }} // mozilla::net
--- a/netwerk/protocol/http/HttpChannelParentListener.h
+++ b/netwerk/protocol/http/HttpChannelParentListener.h
@@ -40,17 +40,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #ifndef mozilla_net_HttpChannelCallbackWrapper_h
 #define mozilla_net_HttpChannelCallbackWrapper_h
 
 #include "nsHttp.h"
 #include "mozilla/net/NeckoCommon.h"
 #include "PHttpChannelParams.h"
-#include "nsIStreamListener.h"
+#include "nsIParentChannel.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIChannelEventSink.h"
 #include "nsIRedirectResultListener.h"
 #include "nsIProgressEventSink.h"
 
 using namespace mozilla::dom;
 
 class nsICacheEntryDescriptor;
@@ -71,24 +71,17 @@ public:
   NS_DECL_NSICHANNELEVENTSINK
   NS_DECL_NSIREDIRECTRESULTLISTENER
   NS_DECL_NSIREQUESTOBSERVER
   NS_DECL_NSISTREAMLISTENER
 
   HttpChannelParentListener(HttpChannelParent* aInitialChannel);
   virtual ~HttpChannelParentListener();
 
-protected:
-  friend class HttpChannelParent;
-  void OnContentRedirectResultReceived(
-                            const nsresult result, 
-                            const RequestHeaderTuples& changedHeaders);
-
 private:
-  nsRefPtr<HttpChannelParent> mActiveChannel;
-  nsRefPtr<HttpChannelParent> mRedirectChannel;
-  nsCOMPtr<nsIAsyncVerifyRedirectCallback> mRedirectCallback;
+  nsCOMPtr<nsIParentChannel> mActiveChannel;
+  PRUint32 mRedirectChannelId;
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_HttpChannelParent_h
--- a/netwerk/protocol/http/Makefile.in
+++ b/netwerk/protocol/http/Makefile.in
@@ -61,16 +61,17 @@ XPIDLSRCS = \
   nsIHttpActivityObserver.idl \
   nsIHttpAuthManager.idl \
   nsIHttpAuthenticator.idl \
   nsIHttpChannelInternal.idl \
   nsIHttpEventSink.idl \
   nsIHttpProtocolHandler.idl \
   nsIHttpChannelAuthProvider.idl \
   nsIHttpAuthenticableChannel.idl \
+  nsIHttpChannelChild.idl \
   $(NULL)
 
 EXPORTS_mozilla/net = \
   HttpBaseChannel.h \
   $(NULL)
 
 ifdef MOZ_IPC
 EXPORTS_mozilla/net += \
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -76,16 +76,18 @@ parent:
             PRBool              allowPipelining,
             PRBool              forceAllowThirdPartyCookie,
             bool                resumeAt,
             PRUint64            startPos,
             nsCString           entityID,
             bool                chooseApplicationCache,
             nsCString           appCacheClientID);
 
+  ConnectChannel(PRUint32 channelId);
+
   SetPriority(PRUint16 priority);
 
   SetCacheTokenCachedCharset(nsCString charset);
 
   UpdateAssociatedContentSecurity(PRInt32 high,
                                   PRInt32 low,
                                   PRInt32 broken,
                                   PRInt32 no);
@@ -140,17 +142,17 @@ child:
   OnStatus(nsresult status, nsString statusArg);
 
   // Used to cancel child channel if we hit errors during creating and
   // AsyncOpen of nsHttpChannel on the parent.
   CancelEarly(nsresult status);
 
   // Called to initiate content channel redirect, starts talking to sinks
   // on the content process and reports result via Redirect2Verify above
-  Redirect1Begin(PHttpChannel       newChannel,
+  Redirect1Begin(PRUint32           newChannelId,
                  URI                newUri,
                  PRUint32           redirectFlags,
                  nsHttpResponseHead responseHead);
 
   // Called if redirect successful so that child can complete setup.
   Redirect3Complete();
 
   // Associte the child with an application ids
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/http/nsIHttpChannelChild.idl
@@ -0,0 +1,48 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications.
+ * Portions created by the Initial Developer are Copyright (C) 2001
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Honza Bambas <honzab.moz@firemni.cz>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+#include "nsISupports.idl"
+
+[ptr] native RequestHeaderTuples(mozilla::net::RequestHeaderTuples);
+
+[uuid(40192377-f83c-4b31-92c6-dbc6c767c860)]
+interface nsIHttpChannelChild : nsISupports
+{
+  void addCookiesToRequest();
+  readonly attribute RequestHeaderTuples headerTuples;
+};