Bug 536289 - Part 2: Make FTP work for fennec. r=jduell a=blocking-fennec
authorAlon Zakai <azakai>
Tue, 10 Aug 2010 14:47:00 -0400
changeset 56142 b2cb926d1ea145b44a08a4558aa147371334b597
parent 56141 290d90eb8ee89dda239ae4ca1c9b331d3d5c625b
child 56143 da156c724d1a0b93e3ff65ace3c4d8e9f6186565
push id16423
push userdwitte@mozilla.com
push dateWed, 20 Oct 2010 00:25:30 +0000
treeherdermozilla-central@44ab0d4958f6 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjduell, blocking-fennec
bugs536289
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 536289 - Part 2: Make FTP work for fennec. r=jduell a=blocking-fennec
ipc/ipdl/Makefile.in
netwerk/base/src/nsBaseChannel.h
netwerk/ipc/NeckoChild.cpp
netwerk/ipc/NeckoChild.h
netwerk/ipc/NeckoCommon.h
netwerk/ipc/NeckoParent.cpp
netwerk/ipc/NeckoParent.h
netwerk/ipc/PNecko.ipdl
netwerk/protocol/ftp/FTPChannelChild.cpp
netwerk/protocol/ftp/FTPChannelChild.h
netwerk/protocol/ftp/FTPChannelParent.cpp
netwerk/protocol/ftp/FTPChannelParent.h
netwerk/protocol/ftp/Makefile.in
netwerk/protocol/ftp/PFTPChannel.ipdl
netwerk/protocol/ftp/ipdl.mk
netwerk/protocol/ftp/nsFTPChannel.h
netwerk/protocol/ftp/nsFtpProtocolHandler.cpp
netwerk/protocol/ftp/nsFtpProtocolHandler.h
netwerk/protocol/http/HttpBaseChannel.h
--- a/ipc/ipdl/Makefile.in
+++ b/ipc/ipdl/Makefile.in
@@ -59,16 +59,17 @@ IPDLDIRS =  \
   dom/ipc  \
   gfx/layers/ipc \
   ipc/ipdl/test/cxx  \
   ipc/testshell  \
   js/ipc  \
   js/jetpack \
   layout/ipc \
   netwerk/ipc  \
+  netwerk/protocol/ftp \
   netwerk/protocol/http  \
   netwerk/protocol/wyciwyg \
   netwerk/cookie  \
   $(NULL)
 ##-----------------------------------------------------------------------------
 
 ifdef MOZ_IPDL_TESTS
 DIRS += test
--- a/netwerk/base/src/nsBaseChannel.h
+++ b/netwerk/base/src/nsBaseChannel.h
@@ -276,27 +276,29 @@ private:
   };
   friend class RedirectRunnable;
 
   nsRefPtr<nsInputStreamPump>         mPump;
   nsCOMPtr<nsIInterfaceRequestor>     mCallbacks;
   nsCOMPtr<nsIProgressEventSink>      mProgressSink;
   nsCOMPtr<nsIURI>                    mOriginalURI;
   nsCOMPtr<nsIURI>                    mURI;
-  nsCOMPtr<nsILoadGroup>              mLoadGroup;
   nsCOMPtr<nsISupports>               mOwner;
   nsCOMPtr<nsISupports>               mSecurityInfo;
-  nsCOMPtr<nsIStreamListener>         mListener;
-  nsCOMPtr<nsISupports>               mListenerContext;
   nsCOMPtr<nsIChannel>                mRedirectChannel;
   nsCString                           mContentType;
   nsCString                           mContentCharset;
   PRUint32                            mLoadFlags;
-  nsresult                            mStatus;
   PRPackedBool                        mQueriedProgressSink;
   PRPackedBool                        mSynthProgressEvents;
   PRPackedBool                        mWasOpened;
   PRPackedBool                        mWaitingOnAsyncRedirect;
   PRPackedBool                        mOpenRedirectChannel;
   PRUint32                            mRedirectFlags;
+
+protected:
+  nsCOMPtr<nsILoadGroup>              mLoadGroup;
+  nsCOMPtr<nsIStreamListener>         mListener;
+  nsCOMPtr<nsISupports>               mListenerContext;
+  nsresult                            mStatus;
 };
 
 #endif // !nsBaseChannel_h__
--- a/netwerk/ipc/NeckoChild.cpp
+++ b/netwerk/ipc/NeckoChild.cpp
@@ -40,16 +40,17 @@
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHttp.h"
 #include "mozilla/net/NeckoChild.h"
 #include "mozilla/dom/ContentChild.h"
 #include "mozilla/net/HttpChannelChild.h"
 #include "mozilla/net/CookieServiceChild.h"
 #include "mozilla/net/WyciwygChannelChild.h"
+#include "mozilla/net/FTPChannelChild.h"
 
 namespace mozilla {
 namespace net {
 
 PNeckoChild *gNeckoChild = nsnull;
 
 // C++ file contents
 NeckoChild::NeckoChild()
@@ -107,16 +108,34 @@ NeckoChild::DeallocPHttpChannel(PHttpCha
 {
   NS_ABORT_IF_FALSE(IsNeckoChild(), "DeallocPHttpChannel called by non-child!");
 
   HttpChannelChild* child = static_cast<HttpChannelChild*>(channel);
   child->ReleaseIPDLReference();
   return true;
 }
 
+PFTPChannelChild*
+NeckoChild::AllocPFTPChannel()
+{
+  // We don't allocate here: see FTPChannelChild::AsyncOpen()
+  NS_RUNTIMEABORT("AllocPFTPChannel should not be called");
+  return nsnull;
+}
+
+bool
+NeckoChild::DeallocPFTPChannel(PFTPChannelChild* channel)
+{
+  NS_ABORT_IF_FALSE(IsNeckoChild(), "DeallocPFTPChannel called by non-child!");
+
+  FTPChannelChild* child = static_cast<FTPChannelChild*>(channel);
+  child->ReleaseIPDLReference();
+  return true;
+}
+
 PCookieServiceChild* 
 NeckoChild::AllocPCookieService()
 {
   // We don't allocate here: see nsCookieService::GetSingleton()
   NS_NOTREACHED("AllocPCookieService should not be called");
   return nsnull;
 }
 
--- a/netwerk/ipc/NeckoChild.h
+++ b/netwerk/ipc/NeckoChild.h
@@ -60,16 +60,18 @@ public:
 
 protected:
   virtual PHttpChannelChild* AllocPHttpChannel(PBrowserChild* iframeEmbedding);
   virtual bool DeallocPHttpChannel(PHttpChannelChild*);
   virtual PCookieServiceChild* AllocPCookieService();
   virtual bool DeallocPCookieService(PCookieServiceChild*);
   virtual PWyciwygChannelChild* AllocPWyciwygChannel();
   virtual bool DeallocPWyciwygChannel(PWyciwygChannelChild*);
+  virtual PFTPChannelChild* AllocPFTPChannel();
+  virtual bool DeallocPFTPChannel(PFTPChannelChild*);
 };
 
 /**
  * Reference to the PNecko Child protocol.
  * Null if this is not a content process.
  */
 extern PNeckoChild *gNeckoChild;
 
--- a/netwerk/ipc/NeckoCommon.h
+++ b/netwerk/ipc/NeckoCommon.h
@@ -68,22 +68,30 @@
       msg.Append(" (set NECKO_ERRORS_ARE_FATAL=1 in your environment to "      \
                       "convert this warning into a fatal error.)");            \
       NS_WARNING(msg.get());                                                   \
     }                                                                          \
   } while (0)
 
 #define DROP_DEAD()                                                            \
   do {                                                                         \
-    nsPrintfCString msg(1000,"FATAL NECKO ERROR: '%s' UNIMPLEMENTED",          \
+    nsPrintfCString msg(1000,"NECKO ERROR: '%s' UNIMPLEMENTED",                \
                         __FUNCTION__);                                         \
     NECKO_MAYBE_ABORT(msg);                                                    \
     return NS_ERROR_NOT_IMPLEMENTED;                                           \
   } while (0)
 
+#define ENSURE_CALLED_BEFORE_ASYNC_OPEN()                                      \
+  if (mIsPending || mWasOpened) {                                              \
+    nsPrintfCString msg(1000, "'%s' called after AsyncOpen: %s +%d",           \
+                        __FUNCTION__, __FILE__, __LINE__);                     \
+    NECKO_MAYBE_ABORT(msg);                                                    \
+  }                                                                            \
+  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);                           \
+  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
 
 namespace mozilla {
 namespace net {
 
 inline bool 
 IsNeckoChild() 
 {
   static bool didCheck = false;
--- a/netwerk/ipc/NeckoParent.cpp
+++ b/netwerk/ipc/NeckoParent.cpp
@@ -38,16 +38,17 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 #include "nsHttp.h"
 #include "mozilla/net/NeckoParent.h"
 #include "mozilla/net/HttpChannelParent.h"
 #include "mozilla/net/CookieServiceParent.h"
 #include "mozilla/net/WyciwygChannelParent.h"
+#include "mozilla/net/FTPChannelParent.h"
 
 #include "nsHTMLDNSPrefetch.h"
 
 namespace mozilla {
 namespace net {
 
 // C++ file contents
 NeckoParent::NeckoParent()
@@ -69,16 +70,32 @@ NeckoParent::AllocPHttpChannel(PBrowserP
 bool 
 NeckoParent::DeallocPHttpChannel(PHttpChannelParent* channel)
 {
   HttpChannelParent *p = static_cast<HttpChannelParent *>(channel);
   p->Release();
   return true;
 }
 
+PFTPChannelParent*
+NeckoParent::AllocPFTPChannel()
+{
+  FTPChannelParent *p = new FTPChannelParent();
+  p->AddRef();
+  return p;
+}
+
+bool
+NeckoParent::DeallocPFTPChannel(PFTPChannelParent* channel)
+{
+  FTPChannelParent *p = static_cast<FTPChannelParent *>(channel);
+  p->Release();
+  return true;
+}
+
 PCookieServiceParent* 
 NeckoParent::AllocPCookieService()
 {
   return new CookieServiceParent();
 }
 
 bool 
 NeckoParent::DeallocPCookieService(PCookieServiceParent* cs)
--- a/netwerk/ipc/NeckoParent.h
+++ b/netwerk/ipc/NeckoParent.h
@@ -57,16 +57,18 @@ public:
 
 protected:
   virtual PHttpChannelParent* AllocPHttpChannel(PBrowserParent* browser);
   virtual bool DeallocPHttpChannel(PHttpChannelParent*);
   virtual PCookieServiceParent* AllocPCookieService();
   virtual bool DeallocPCookieService(PCookieServiceParent*);
   virtual PWyciwygChannelParent* AllocPWyciwygChannel();
   virtual bool DeallocPWyciwygChannel(PWyciwygChannelParent*);
+  virtual PFTPChannelParent* AllocPFTPChannel();
+  virtual bool DeallocPFTPChannel(PFTPChannelParent*);
   virtual bool RecvHTMLDNSPrefetch(const nsString& hostname,
                                    const PRUint16& flags);
 };
 
 } // namespace net
 } // namespace mozilla
 
 #endif // mozilla_net_NeckoParent_h
--- a/netwerk/ipc/PNecko.ipdl
+++ b/netwerk/ipc/PNecko.ipdl
@@ -38,34 +38,37 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 include protocol PContent;
 include protocol PHttpChannel;
 include protocol PCookieService;
 include protocol PBrowser;
 include protocol PWyciwygChannel;
+include protocol PFTPChannel;
 
 namespace mozilla {
 namespace net {
 
 
 //-------------------------------------------------------------------
 sync protocol PNecko
 {
   manager PContent;
   manages PHttpChannel;
   manages PCookieService;
   manages PWyciwygChannel;
+  manages PFTPChannel;
 
 parent:
   __delete__();
 
   PCookieService();
   PWyciwygChannel();
+  PFTPChannel();
 
   HTMLDNSPrefetch(nsString hostname, PRUint16 flags);
 
 both:
   PHttpChannel(nullable PBrowser browser);
 };
 
 
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/ftp/FTPChannelChild.cpp
@@ -0,0 +1,480 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alon Zakai <azakai@mozilla.com>
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * 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 "mozilla/net/NeckoChild.h"
+#include "mozilla/net/FTPChannelChild.h"
+#include "nsFtpProtocolHandler.h"
+
+#include "nsStringStream.h"
+#include "nsMimeTypes.h"
+#include "nsNetUtil.h"
+#include "nsIURIFixup.h"
+#include "nsCDefaultURIFixup.h"
+
+#undef LOG
+#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
+
+namespace mozilla {
+namespace net {
+
+FTPChannelChild::FTPChannelChild(nsIURI* uri)
+: ChannelEventQueue<FTPChannelChild>(this)
+, mIPCOpen(false)
+, mCanceled(false)
+, mSuspendCount(0)
+, mIsPending(PR_FALSE)
+, mWasOpened(PR_FALSE)
+, mLastModifiedTime(0)
+, mStartPos(0)
+{
+  LOG(("Creating FTPChannelChild @%x\n", this));
+  // grab a reference to the handler to ensure that it doesn't go away.
+  NS_ADDREF(gFtpHandler);
+  SetURI(uri);
+}
+
+FTPChannelChild::~FTPChannelChild()
+{
+  LOG(("Destroying FTPChannelChild @%x\n", this));
+  gFtpHandler->Release();
+}
+
+void
+FTPChannelChild::AddIPDLReference()
+{
+  NS_ABORT_IF_FALSE(!mIPCOpen, "Attempt to retain more than one IPDL reference");
+  mIPCOpen = true;
+  AddRef();
+}
+
+void
+FTPChannelChild::ReleaseIPDLReference()
+{
+  NS_ABORT_IF_FALSE(mIPCOpen, "Attempt to release nonexistent IPDL reference");
+  mIPCOpen = false;
+  Release();
+}
+
+//-----------------------------------------------------------------------------
+// FTPChannelChild::nsISupports
+//-----------------------------------------------------------------------------
+
+NS_IMPL_ISUPPORTS_INHERITED4(FTPChannelChild,
+                             nsBaseChannel,
+                             nsIFTPChannel,
+                             nsIUploadChannel,
+                             nsIResumableChannel,
+                             nsIProxiedChannel)
+
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelChild::GetLastModifiedTime(PRTime* lastModifiedTime)
+{
+  *lastModifiedTime = mLastModifiedTime;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::SetLastModifiedTime(PRTime lastModifiedTime)
+{
+  return NS_ERROR_NOT_AVAILABLE;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::ResumeAt(PRUint64 aStartPos, const nsACString& aEntityID)
+{
+  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
+  mStartPos = aStartPos;
+  mEntityID = aEntityID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::GetEntityID(nsACString& entityID)
+{
+  entityID = mEntityID;
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::GetProxyInfo(nsIProxyInfo** aProxyInfo)
+{
+  DROP_DEAD();
+}
+
+NS_IMETHODIMP
+FTPChannelChild::SetUploadStream(nsIInputStream* stream,
+                                 const nsACString& contentType,
+                                 PRInt32 contentLength)
+{
+  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
+  mUploadStream = stream;
+  // NOTE: contentLength is intentionally ignored here.
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::GetUploadStream(nsIInputStream** stream)
+{
+  NS_ENSURE_ARG_POINTER(stream);
+  *stream = mUploadStream;
+  NS_IF_ADDREF(*stream);
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelChild::AsyncOpen(::nsIStreamListener* listener, nsISupports* aContext)
+{
+  LOG(("FTPChannelChild::AsyncOpen [this=%x]\n", this));
+
+  NS_ENSURE_TRUE((gNeckoChild), NS_ERROR_FAILURE);
+  NS_ENSURE_ARG_POINTER(listener);
+  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);
+  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
+
+  // Port checked in parent, but duplicate here so we can return with error
+  // immediately, as we've done since before e10s.
+  nsresult rv;
+  rv = NS_CheckPortSafety(nsBaseChannel::URI()); // Need to disambiguate,
+                                                 // because in the child ipdl,
+                                                 // a typedef URI is defined...
+  if (NS_FAILED(rv))
+    return rv;
+
+  // FIXME: like bug 558623, merge constructor+SendAsyncOpen into 1 IPC msg
+  gNeckoChild->SendPFTPChannelConstructor(this);
+  mListener = listener;
+  mListenerContext = aContext;
+
+  // add ourselves to the load group. 
+  if (mLoadGroup)
+    mLoadGroup->AddRequest(this, nsnull);
+
+  SendAsyncOpen(nsBaseChannel::URI(), mStartPos, mEntityID,
+                IPC::InputStream(mUploadStream));
+
+  // The socket transport layer in the chrome process now has a logical ref to
+  // us until OnStopRequest is called.
+  AddIPDLReference();
+
+  mIsPending = PR_TRUE;
+  mWasOpened = PR_TRUE;
+
+  return rv;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::IsPending(PRBool* result)
+{
+  *result = mIsPending;
+  return NS_OK;
+}
+
+nsresult
+FTPChannelChild::OpenContentStream(PRBool async,
+                                   nsIInputStream** stream,
+                                   nsIChannel** channel)
+{
+  NS_RUNTIMEABORT("FTPChannel*Child* should never have OpenContentStream called!");
+  return NS_OK;
+}
+  
+//-----------------------------------------------------------------------------
+// FTPChannelChild::PFTPChannelChild
+//-----------------------------------------------------------------------------
+
+class FTPStartRequestEvent : public ChannelEvent
+{
+ public:
+  FTPStartRequestEvent(FTPChannelChild* aChild, const PRInt32& aContentLength,
+                       const nsCString& aContentType, const PRTime& aLastModified,
+                       const nsCString& aEntityID, const IPC::URI& aURI)
+  : mChild(aChild), mContentLength(aContentLength), mContentType(aContentType),
+    mLastModified(aLastModified), mEntityID(aEntityID), mURI(aURI) {}
+  void Run() { mChild->DoOnStartRequest(mContentLength, mContentType,
+                                       mLastModified, mEntityID, mURI); }
+ private:
+  FTPChannelChild* mChild;
+  PRInt32 mContentLength;
+  nsCString mContentType;
+  PRTime mLastModified;
+  nsCString mEntityID;
+  IPC::URI mURI;
+};
+
+bool
+FTPChannelChild::RecvOnStartRequest(const PRInt32& aContentLength,
+                                    const nsCString& aContentType,
+                                    const PRTime& aLastModified,
+                                    const nsCString& aEntityID,
+                                    const IPC::URI& aURI)
+{
+  if (ShouldEnqueue()) {
+    EnqueueEvent(new FTPStartRequestEvent(this, aContentLength, aContentType,
+                                          aLastModified, aEntityID, aURI));
+  } else {
+    DoOnStartRequest(aContentLength, aContentType, aLastModified,
+                     aEntityID, aURI);
+  }
+  return true;
+}
+
+void
+FTPChannelChild::DoOnStartRequest(const PRInt32& aContentLength,
+                                  const nsCString& aContentType,
+                                  const PRTime& aLastModified,
+                                  const nsCString& aEntityID,
+                                  const IPC::URI& aURI)
+{
+  LOG(("FTPChannelChild::RecvOnStartRequest [this=%x]\n", this));
+
+  SetContentLength(aContentLength);
+  SetContentType(aContentType);
+  mLastModifiedTime = aLastModified;
+  mEntityID = aEntityID;
+
+  nsCString spec;
+  nsCOMPtr<nsIURI> uri(aURI);
+  uri->GetSpec(spec);
+  nsBaseChannel::URI()->SetSpec(spec);
+
+  AutoEventEnqueuer ensureSerialDispatch(this);
+  nsresult rv = mListener->OnStartRequest(this, mListenerContext);
+  if (NS_FAILED(rv))
+    Cancel(rv);
+}
+
+class FTPDataAvailableEvent : public ChannelEvent
+{
+ public:
+  FTPDataAvailableEvent(FTPChannelChild* aChild, const nsCString& aData,
+                        const PRUint32& aOffset, const PRUint32& aCount)
+  : mChild(aChild), mData(aData), mOffset(aOffset), mCount(aCount) {}
+  void Run() { mChild->DoOnDataAvailable(mData, mOffset, mCount); }
+ private:
+  FTPChannelChild* mChild;
+  nsCString mData;
+  PRUint32 mOffset, mCount;
+};
+
+bool
+FTPChannelChild::RecvOnDataAvailable(const nsCString& data,
+                                     const PRUint32& offset,
+                                     const PRUint32& count)
+{
+  if (ShouldEnqueue()) {
+    EnqueueEvent(new FTPDataAvailableEvent(this, data, offset, count));
+  } else {
+    DoOnDataAvailable(data, offset, count);
+  }
+  return true;
+}
+
+void
+FTPChannelChild::DoOnDataAvailable(const nsCString& data,
+                                   const PRUint32& offset,
+                                   const PRUint32& count)
+{
+  LOG(("FTPChannelChild::RecvOnDataAvailable [this=%x]\n", this));
+
+  if (mCanceled)
+    return;
+
+  // NOTE: the OnDataAvailable contract requires the client to read all the data
+  // in the inputstream.  This code relies on that ('data' will go away after
+  // this function).  Apparently the previous, non-e10s behavior was to actually
+  // support only reading part of the data, allowing later calls to read the
+  // rest.
+  nsCOMPtr<nsIInputStream> stringStream;
+  nsresult rv = NS_NewByteInputStream(getter_AddRefs(stringStream),
+                                      data.get(),
+                                      count,
+                                      NS_ASSIGNMENT_DEPEND);
+  if (NS_FAILED(rv)) {
+    Cancel(rv);
+    return;
+  }
+
+  AutoEventEnqueuer ensureSerialDispatch(this);
+  rv = mListener->OnDataAvailable(this, mListenerContext,
+                                  stringStream, offset, count);
+  if (NS_FAILED(rv))
+    Cancel(rv);
+  stringStream->Close();
+}
+
+class FTPStopRequestEvent : public ChannelEvent
+{
+ public:
+  FTPStopRequestEvent(FTPChannelChild* aChild, const nsresult& aStatusCode)
+  : mChild(aChild), mStatusCode(aStatusCode) {}
+  void Run() { mChild->DoOnStopRequest(mStatusCode); }
+ private:
+  FTPChannelChild* mChild;
+  nsresult mStatusCode;
+};
+
+bool
+FTPChannelChild::RecvOnStopRequest(const nsresult& statusCode)
+{
+  if (ShouldEnqueue()) {
+    EnqueueEvent(new FTPStopRequestEvent(this, statusCode));
+  } else {
+    DoOnStopRequest(statusCode);
+  }
+  return true;
+}
+
+void
+FTPChannelChild::DoOnStopRequest(const nsresult& statusCode)
+{
+  LOG(("FTPChannelChild::RecvOnStopRequest [this=%x status=%u]\n",
+           this, statusCode));
+
+  if (!mCanceled)
+    mStatus = statusCode;
+
+  { // Ensure that all queued ipdl events are dispatched before
+    // we initiate protocol deletion below.
+    mIsPending = PR_FALSE;
+    AutoEventEnqueuer ensureSerialDispatch(this);
+    (void)mListener->OnStopRequest(this, mListenerContext, statusCode);
+    mListener = nsnull;
+    mListenerContext = nsnull;
+
+    if (mLoadGroup)
+      mLoadGroup->RemoveRequest(this, nsnull, statusCode);
+  }
+
+  // This calls NeckoChild::DeallocPFTPChannel(), which deletes |this| if IPDL
+  // holds the last reference.  Don't rely on |this| existing after here!
+  Send__delete__(this);
+}
+
+class FTPCancelEarlyEvent : public ChannelEvent
+{
+ public:
+  FTPCancelEarlyEvent(FTPChannelChild* aChild, nsresult aStatus)
+  : mChild(aChild), mStatus(aStatus) {}
+  void Run() { mChild->DoCancelEarly(mStatus); }
+ private:
+  FTPChannelChild* mChild;
+  nsresult mStatus;
+};
+
+bool
+FTPChannelChild::RecvCancelEarly(const nsresult& statusCode)
+{
+  if (ShouldEnqueue()) {
+    EnqueueEvent(new FTPCancelEarlyEvent(this, statusCode));
+  } else {
+    DoCancelEarly(statusCode);
+  }
+  return true;
+}
+
+void
+FTPChannelChild::DoCancelEarly(const nsresult& statusCode)
+{
+  if (mCanceled)
+    return;
+
+  mCanceled = true;
+  mStatus = statusCode;
+  mIsPending = PR_FALSE;
+  
+  if (mLoadGroup)
+    mLoadGroup->RemoveRequest(this, nsnull, statusCode);
+
+  if (mListener) {
+    mListener->OnStartRequest(this, mListenerContext);
+    mListener->OnStopRequest(this, mListenerContext, statusCode);
+  }
+
+  mListener = nsnull;
+  mListenerContext = nsnull;
+
+  if (mIPCOpen)
+    Send__delete__(this);
+}
+
+NS_IMETHODIMP
+FTPChannelChild::Cancel(nsresult status)
+{
+  if (mCanceled)
+    return NS_OK;
+
+  mCanceled = true;
+  mStatus = status;
+  if (mIPCOpen)
+    SendCancel(status);
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::Suspend()
+{
+  NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
+  mSuspendCount++;
+  SendSuspend();
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelChild::Resume()
+{
+  NS_ENSURE_TRUE(mIPCOpen, NS_ERROR_NOT_AVAILABLE);
+  SendResume();
+  --mSuspendCount;
+  if (!mSuspendCount) {
+    if (mQueuePhase == PHASE_UNQUEUED)
+      mQueuePhase = PHASE_FINISHED_QUEUEING;
+    FlushEventQueue();
+  }
+  return NS_OK;
+}
+
+} // namespace net
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/ftp/FTPChannelChild.h
@@ -0,0 +1,151 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alon Zakai <azakai@mozilla.com>
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * 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 mozilla_net_FTPChannelChild_h
+#define mozilla_net_FTPChannelChild_h
+
+#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 "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
+// nsBaseChannel and have a new class that has only the common logic for
+// nsFTPChannel/FTPChannelChild.
+
+class FTPChannelChild : public PFTPChannelChild
+                      , public nsBaseChannel
+                      , public nsIFTPChannel
+                      , public nsIUploadChannel
+                      , public nsIResumableChannel
+                      , public nsIProxiedChannel
+                      , public ChannelEventQueue<FTPChannelChild>
+{
+public:
+  NS_DECL_ISUPPORTS_INHERITED
+  NS_DECL_NSIFTPCHANNEL
+  NS_DECL_NSIUPLOADCHANNEL
+  NS_DECL_NSIRESUMABLECHANNEL
+  NS_DECL_NSIPROXIEDCHANNEL
+
+  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);
+
+  // 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);
+
+  bool IsSuspended();
+
+protected:
+  NS_OVERRIDE bool RecvOnStartRequest(const PRInt32& aContentLength,
+                                      const nsCString& aContentType,
+                                      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);
+
+  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);
+
+  friend class FTPStartRequestEvent;
+  friend class FTPDataAvailableEvent;
+  friend class FTPStopRequestEvent;
+  friend class FTPCancelEarlyEvent;
+
+private:
+  nsCOMPtr<nsIInputStream> mUploadStream;
+
+  bool mIPCOpen;
+  bool mCanceled;
+  PRUint32 mSuspendCount;
+  PRPackedBool mIsPending;
+  PRPackedBool mWasOpened;
+  
+  PRTime mLastModifiedTime;
+  PRUint64 mStartPos;
+  nsCString mEntityID;
+};
+
+inline bool
+FTPChannelChild::IsSuspended()
+{
+  return mSuspendCount != 0;
+}
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_FTPChannelChild_h
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/ftp/FTPChannelParent.cpp
@@ -0,0 +1,233 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alon Zakai <azakai@mozilla.com>
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * 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 "mozilla/net/FTPChannelParent.h"
+#include "nsFTPChannel.h"
+#include "nsNetUtil.h"
+#include "nsISupportsPriority.h"
+#include "nsFtpProtocolHandler.h"
+
+#undef LOG
+#define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
+
+namespace mozilla {
+namespace net {
+
+FTPChannelParent::FTPChannelParent()
+: mIPCClosed(false)
+{
+  nsIProtocolHandler* handler;
+  CallGetService(NS_NETWORK_PROTOCOL_CONTRACTID_PREFIX "ftp", &handler);
+  NS_ASSERTION(handler, "no ftp handler");
+}
+
+FTPChannelParent::~FTPChannelParent()
+{
+  gFtpHandler->Release();
+}
+
+void
+FTPChannelParent::ActorDestroy(ActorDestroyReason why)
+{
+  // We may still have refcount>0 if the channel hasn't called OnStopRequest
+  // yet, but we must not send any more msgs to child.
+  mIPCClosed = true;
+}
+
+//-----------------------------------------------------------------------------
+// FTPChannelParent::nsISupports
+//-----------------------------------------------------------------------------
+
+NS_IMPL_ISUPPORTS3(FTPChannelParent,
+                   nsIStreamListener,
+                   nsIInterfaceRequestor,
+                   nsIRequestObserver);
+
+//-----------------------------------------------------------------------------
+// FTPChannelParent::PFTPChannelParent
+//-----------------------------------------------------------------------------
+
+bool
+FTPChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
+                                const PRUint64& aStartPos,
+                                const nsCString& aEntityID,
+                                const IPC::InputStream& aUploadStream)
+{
+  nsCOMPtr<nsIURI> uri(aURI);
+
+#ifdef DEBUG
+  nsCString uriSpec;
+  uri->GetSpec(uriSpec);
+  LOG(("FTPChannelParent RecvAsyncOpen [this=%x uri=%s]\n",
+       this, uriSpec.get()));
+#endif
+
+  nsresult rv;
+  nsCOMPtr<nsIIOService> ios(do_GetIOService(&rv));
+  if (NS_FAILED(rv))
+    return SendCancelEarly(rv);
+
+  nsCOMPtr<nsIChannel> chan;
+  rv = NS_NewChannel(getter_AddRefs(chan), uri, ios);
+  if (NS_FAILED(rv))
+    return SendCancelEarly(rv);
+
+  mChannel = static_cast<nsFtpChannel*>(chan.get());
+  
+  nsCOMPtr<nsIInputStream> upload(aUploadStream);
+  if (upload) {
+    // contentType and contentLength are ignored
+    rv = mChannel->SetUploadStream(upload, EmptyCString(), 0);
+    if (NS_FAILED(rv))
+      return SendCancelEarly(rv);
+  }
+
+  rv = mChannel->ResumeAt(aStartPos, aEntityID);
+  if (NS_FAILED(rv))
+    return SendCancelEarly(rv);
+
+  rv = mChannel->AsyncOpen(this, nsnull);
+  if (NS_FAILED(rv))
+    return SendCancelEarly(rv);
+  
+  return true;
+}
+
+bool
+FTPChannelParent::RecvCancel(const nsresult& status)
+{
+  mChannel->Cancel(status);
+  return true;
+}
+
+bool
+FTPChannelParent::RecvSuspend()
+{
+  mChannel->Suspend();
+  return true;
+}
+
+bool
+FTPChannelParent::RecvResume()
+{
+  mChannel->Resume();
+  return true;
+}
+
+//-----------------------------------------------------------------------------
+// FTPChannelParent::nsIRequestObserver
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelParent::OnStartRequest(nsIRequest* aRequest, nsISupports* aContext)
+{
+  LOG(("FTPChannelParent::OnStartRequest [this=%x]\n", this));
+
+  nsFtpChannel* chan = static_cast<nsFtpChannel*>(aRequest);
+  PRInt32 aContentLength;
+  chan->GetContentLength(&aContentLength);
+  nsCString contentType;
+  chan->GetContentType(contentType);
+  nsCString entityID;
+  chan->GetEntityID(entityID);
+  PRTime lastModified;
+  chan->GetLastModifiedTime(&lastModified);
+
+  if (mIPCClosed || !SendOnStartRequest(aContentLength, contentType,
+                                       lastModified, entityID, chan->URI())) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+NS_IMETHODIMP
+FTPChannelParent::OnStopRequest(nsIRequest* aRequest,
+                                nsISupports* aContext,
+                                nsresult aStatusCode)
+{
+  LOG(("FTPChannelParent::OnStopRequest: [this=%x status=%ul]\n",
+       this, aStatusCode));
+
+  if (mIPCClosed || !SendOnStopRequest(aStatusCode)) {
+    return NS_ERROR_UNEXPECTED;
+  }
+
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// FTPChannelParent::nsIStreamListener
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelParent::OnDataAvailable(nsIRequest* aRequest,
+                                  nsISupports* aContext,
+                                  nsIInputStream* aInputStream,
+                                  PRUint32 aOffset,
+                                  PRUint32 aCount)
+{
+  LOG(("FTPChannelParent::OnDataAvailable [this=%x]\n", this));
+  
+  nsCString data;
+  nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
+  if (NS_FAILED(rv))
+    return rv;
+
+  if (mIPCClosed || !SendOnDataAvailable(data, aOffset, aCount))
+    return NS_ERROR_UNEXPECTED;
+
+  return NS_OK;
+}
+
+//-----------------------------------------------------------------------------
+// FTPChannelParent::nsIInterfaceRequestor
+//-----------------------------------------------------------------------------
+
+NS_IMETHODIMP
+FTPChannelParent::GetInterface(const nsIID& uuid, void** result)
+{
+  DROP_DEAD();
+}
+
+} // namespace net
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/ftp/FTPChannelParent.h
@@ -0,0 +1,87 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alon Zakai <azakai@mozilla.com>
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * 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 mozilla_net_FTPChannelParent_h
+#define mozilla_net_FTPChannelParent_h
+
+#include "mozilla/net/PFTPChannelParent.h"
+#include "mozilla/net/NeckoCommon.h"
+#include "nsIStreamListener.h"
+#include "nsIInterfaceRequestor.h"
+
+class nsFtpChannel;
+
+namespace mozilla {
+namespace net {
+
+class FTPChannelParent : public PFTPChannelParent
+                       , public nsIStreamListener
+                       , public nsIInterfaceRequestor
+{
+public:
+  NS_DECL_ISUPPORTS
+  NS_DECL_NSIREQUESTOBSERVER
+  NS_DECL_NSISTREAMLISTENER
+  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 RecvCancel(const nsresult& status);
+  NS_OVERRIDE virtual bool RecvSuspend();
+  NS_OVERRIDE virtual bool RecvResume();
+
+  NS_OVERRIDE virtual void ActorDestroy(ActorDestroyReason why);
+
+  nsRefPtr<nsFtpChannel> mChannel;
+
+  bool mIPCClosed;
+};
+
+} // namespace net
+} // namespace mozilla
+
+#endif // mozilla_net_FTPChannelParent_h
--- a/netwerk/protocol/ftp/Makefile.in
+++ b/netwerk/protocol/ftp/Makefile.in
@@ -51,35 +51,53 @@ GRE_MODULE     = 1
 FORCE_STATIC_LIB = 1
 
 EXPORTS = ftpCore.h
 
 XPIDLSRCS = \
   nsIFTPChannel.idl \
   $(NULL)
 
+ifdef MOZ_IPC
+EXPORTS_NAMESPACES = mozilla/net
+
+EXPORTS_mozilla/net += \
+  FTPChannelParent.h \
+  FTPChannelChild.h  \
+  $(NULL)
+endif
+
 CPPSRCS = \
   nsFtpProtocolHandler.cpp \
   nsFTPChannel.cpp \
   nsFtpConnectionThread.cpp \
   nsFtpControlConnection.cpp \
   $(NULL)
 
+ifdef MOZ_IPC
+CPPSRCS += \
+  FTPChannelParent.cpp \
+  FTPChannelChild.cpp \
+  $(NULL)
+endif
+
 # Use -g for Irix mipspro builds as workaround for bug 92099
 ifneq (,$(filter IRIX IRIX64,$(OS_ARCH)))
 ifndef GNU_CC
 MODULE_OPTIMIZE_FLAGS=-O -g
 endif
 endif
 
 LOCAL_INCLUDES = \
   -I$(srcdir)/../../base/src \
   -I$(topsrcdir)/xpcom/ds \
   $(NULL)
 
+include $(topsrcdir)/config/config.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 include $(topsrcdir)/config/rules.mk
 
 ifeq ($(OS_ARCH),WINNT)
 ifndef MOZ_DEBUG
 ifndef NO_LOGGING
 DEFINES += -DFORCE_PR_LOG
 endif
 endif
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/ftp/PFTPChannel.ipdl
@@ -0,0 +1,76 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set sw=2 ts=8 et tw=80 ft=cpp : */
+
+/* ***** 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
+ *  The Mozilla Foundation
+ * Portions created by the Initial Developer are Copyright (C) 2010
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Alon Zakai <azakai@mozilla.com>
+ *   Josh Matthews <josh@joshmatthews.net>
+ *
+ * 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 protocol PNecko;
+
+include "mozilla/net/NeckoMessageUtils.h";
+
+using IPC::URI;
+using IPC::InputStream;
+using PRTime;
+
+namespace mozilla {
+namespace net {
+
+async protocol PFTPChannel
+{
+  manager PNecko;
+
+parent:
+  __delete__();
+
+  AsyncOpen(URI uri, PRUint64 startPos, nsCString entityID,
+            InputStream uploadStream);
+  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);
+};
+
+} // namespace net
+} // namespace mozilla
+
new file mode 100644
--- /dev/null
+++ b/netwerk/protocol/ftp/ipdl.mk
@@ -0,0 +1,40 @@
+# ***** 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 Firefox.
+#
+# The Initial Developer of the Original Code is
+# The Mozilla Foundation <http://www.mozilla.org/>.
+# Portions created by the Initial Developer are Copyright (C) 2010
+# the Initial Developer. All Rights Reserved.
+#
+# Contributor(s):  Alon Zakai
+#
+# 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 *****
+
+IPDLSRCS =         \
+  PFTPChannel.ipdl \
+  $(NULL)
+
--- a/netwerk/protocol/ftp/nsFTPChannel.h
+++ b/netwerk/protocol/ftp/nsFTPChannel.h
@@ -57,16 +57,17 @@
 #include "nsIStreamListener.h"
 #include "nsAutoLock.h"
 #include "nsIFTPChannel.h"
 #include "nsIUploadChannel.h"
 #include "nsIProxyInfo.h"
 #include "nsIProxiedChannel.h"
 #include "nsIResumableChannel.h"
 #include "nsHashPropertyBag.h"
+#include "nsFtpProtocolHandler.h"
 
 class nsFtpChannel : public nsBaseChannel,
                      public nsIFTPChannel,
                      public nsIUploadChannel,
                      public nsIResumableChannel,
                      public nsIProxiedChannel
 {
 public:
--- a/netwerk/protocol/ftp/nsFtpProtocolHandler.cpp
+++ b/netwerk/protocol/ftp/nsFtpProtocolHandler.cpp
@@ -44,16 +44,22 @@
  * Modifications to Mozilla code or documentation
  * identified per MPL Section 3.3
  *
  * Date         Modified by     Description of modification
  * 03/27/2000   IBM Corp.       Added PR_CALLBACK for Optlink
  *                               use in OS2
  */
 
+#ifdef MOZ_IPC
+#include "mozilla/net/NeckoChild.h"
+#include "mozilla/net/FTPChannelChild.h"
+using namespace mozilla::net;
+#endif
+
 #include "nsFtpProtocolHandler.h"
 #include "nsFTPChannel.h"
 #include "nsIURL.h"
 #include "nsIStandardURL.h"
 #include "nsCRT.h"
 #include "nsIComponentManager.h"
 #include "nsIInterfaceRequestor.h"
 #include "nsIInterfaceRequestorUtils.h"
@@ -76,16 +82,17 @@
 //    set NSPR_LOG_MODULES=nsFtp:5
 //    set NSPR_LOG_FILE=nspr.log
 //
 // this enables PR_LOG_DEBUG level information and places all output in
 // the file nspr.log
 //
 PRLogModuleInfo* gFTPLog = nsnull;
 #endif
+#undef LOG
 #define LOG(args) PR_LOG(gFTPLog, PR_LOG_DEBUG, args)
 
 //-----------------------------------------------------------------------------
 
 #define IDLE_TIMEOUT_PREF     "network.ftp.idleConnectionTimeout"
 #define IDLE_CONNECTION_LIMIT 8 /* TODO pref me */
 
 #define QOS_DATA_PREF         "network.ftp.data.qos"
@@ -123,16 +130,21 @@ NS_IMPL_THREADSAFE_ISUPPORTS4(nsFtpProto
                               nsIProtocolHandler,
                               nsIProxiedProtocolHandler,
                               nsIObserver,
                               nsISupportsWeakReference)
 
 nsresult
 nsFtpProtocolHandler::Init()
 {
+#ifdef MOZ_IPC
+    if (IsNeckoChild())
+        NeckoChild::InitNeckoChild();
+#endif // MOZ_IPC
+
     if (mIdleTimeout == -1) {
         nsresult rv;
         nsCOMPtr<nsIPrefBranch2> branch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv);
         if (NS_FAILED(rv)) return rv;
 
         rv = branch->GetIntPref(IDLE_TIMEOUT_PREF, &mIdleTimeout);
         if (NS_FAILED(rv))
             mIdleTimeout = 5*60; // 5 minute default
@@ -236,28 +248,30 @@ nsFtpProtocolHandler::NewChannel(nsIURI*
     return NewProxiedChannel(url, nsnull, result);
 }
 
 NS_IMETHODIMP
 nsFtpProtocolHandler::NewProxiedChannel(nsIURI* uri, nsIProxyInfo* proxyInfo,
                                         nsIChannel* *result)
 {
     NS_ENSURE_ARG_POINTER(uri);
-    nsFtpChannel *channel = new nsFtpChannel(uri, proxyInfo);
-    if (!channel)
-        return NS_ERROR_OUT_OF_MEMORY;
-    NS_ADDREF(channel);
+    nsRefPtr<nsBaseChannel> channel;
+#ifdef MOZ_IPC
+    if (IsNeckoChild())
+        channel = new FTPChannelChild(uri);
+    else
+#endif
+        channel = new nsFtpChannel(uri, proxyInfo);
 
     nsresult rv = channel->Init();
     if (NS_FAILED(rv)) {
-        NS_RELEASE(channel);
         return rv;
     }
     
-    *result = channel;
+    channel.forget(result);
     return rv;
 }
 
 NS_IMETHODIMP 
 nsFtpProtocolHandler::AllowPort(PRInt32 port, const char *scheme, PRBool *_retval)
 {
     *_retval = (port == 21 || port == 22);
     return NS_OK;
--- a/netwerk/protocol/ftp/nsFtpProtocolHandler.h
+++ b/netwerk/protocol/ftp/nsFtpProtocolHandler.h
@@ -118,9 +118,13 @@ private:
     PRUint8 mControlQoSBits;
     PRUint8 mDataQoSBits;
 };
 
 //-----------------------------------------------------------------------------
 
 extern nsFtpProtocolHandler *gFtpHandler;
 
+#ifdef PR_LOGGING
+extern PRLogModuleInfo* gFTPLog;
+#endif
+
 #endif // !nsFtpProtocolHandler_h__
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -55,34 +55,16 @@
 #include "nsIUploadChannel2.h"
 #include "nsIProgressEventSink.h"
 #include "nsIURI.h"
 #include "nsIStringEnumerator.h"
 #include "nsISupportsPriority.h"
 #include "nsIApplicationCache.h"
 #include "nsIResumableChannel.h"
 
-#define DIE_WITH_ASYNC_OPEN_MSG()                                              \
-  do {                                                                         \
-    fprintf(stderr,                                                            \
-            "*&*&*&*&*&*&*&**&*&&*& FATAL ERROR: '%s' "                        \
-            "called after AsyncOpen: %s +%d",                                  \
-            __FUNCTION__, __FILE__, __LINE__);                                 \
-    NS_ABORT();                                                                \
-    return NS_ERROR_NOT_IMPLEMENTED;                                           \
-  } while (0)
-
-#define ENSURE_CALLED_BEFORE_ASYNC_OPEN()                                      \
-  if (mIsPending)                                                              \
-    DIE_WITH_ASYNC_OPEN_MSG();                                                 \
-  if (mWasOpened)                                                              \
-    DIE_WITH_ASYNC_OPEN_MSG();                                                 \
-  NS_ENSURE_TRUE(!mIsPending, NS_ERROR_IN_PROGRESS);                           \
-  NS_ENSURE_TRUE(!mWasOpened, NS_ERROR_ALREADY_OPENED);
-
 namespace mozilla {
 namespace net {
 
 /*
  * This class is a partial implementation of nsIHttpChannel.  It contains code
  * shared by nsHttpChannel and HttpChannelChild. 
  * - Note that this class has nothing to do with nsBaseChannel, which is an
  *   earlier effort at a base class for channels that somehow never made it all