Bug 564553 - e10s HTTP: Serialize nsInputStreams to support large file uploads. r=dwitte, a=blocking-fennec2.0b2+
authorJae-Seong Lee-Russo <lusian@gmail.com>
Thu, 21 Oct 2010 11:36:13 -0700
changeset 56318 b448b7b2e6d541ce9dccf37c2bddfa3dbf8e6a72
parent 56317 422f6f9b048dfd93c20dada411194c9e8146e12d
child 56319 a5cbd666cb0afae0d6cd36caf38247cec3912f02
push id1
push userroot
push dateTue, 26 Apr 2011 22:38:44 +0000
treeherdermozilla-beta@bfdb6e623a36 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdwitte, blocking-fennec2
bugs564553
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 564553 - e10s HTTP: Serialize nsInputStreams to support large file uploads. r=dwitte, a=blocking-fennec2.0b2+
netwerk/base/src/nsBufferedStreams.cpp
netwerk/base/src/nsBufferedStreams.h
netwerk/base/src/nsFileStreams.cpp
netwerk/base/src/nsFileStreams.h
netwerk/base/src/nsMIMEInputStream.cpp
netwerk/protocol/http/HttpBaseChannel.h
netwerk/protocol/http/HttpChannelChild.cpp
netwerk/protocol/http/HttpChannelParent.cpp
netwerk/protocol/http/HttpChannelParent.h
netwerk/protocol/http/PHttpChannel.ipdl
netwerk/protocol/http/PHttpChannelParams.h
xpcom/io/Makefile.in
xpcom/io/nsMultiplexInputStream.cpp
xpcom/io/nsStringStream.cpp
--- a/netwerk/base/src/nsBufferedStreams.cpp
+++ b/netwerk/base/src/nsBufferedStreams.cpp
@@ -30,19 +30,26 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "IPC/IPCMessageUtils.h"
+#include "mozilla/net/PHttpChannelParams.h"
+#endif
+
 #include "nsBufferedStreams.h"
 #include "nsStreamUtils.h"
 #include "nsCRT.h"
+#include "nsNetCID.h"
+#include "nsIClassInfoImpl.h"
 
 #ifdef DEBUG_brendan
 # define METERING
 #endif
 
 #ifdef METERING
 # include <stdio.h>
 # define METER(x)       x
@@ -241,21 +248,36 @@ nsBufferedStream::SetEOF()
     if (NS_FAILED(rv)) return rv;
 
     return ras->SetEOF();
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsBufferedInputStream
 
-NS_IMPL_ISUPPORTS_INHERITED3(nsBufferedInputStream, 
-                             nsBufferedStream,
+NS_IMPL_ADDREF_INHERITED(nsBufferedInputStream, nsBufferedStream)
+NS_IMPL_RELEASE_INHERITED(nsBufferedInputStream, nsBufferedStream)
+
+NS_IMPL_CLASSINFO(nsBufferedInputStream, NULL, nsIClassInfo::THREADSAFE,
+                  NS_BUFFEREDINPUTSTREAM_CID)
+
+NS_INTERFACE_MAP_BEGIN(nsBufferedInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsIInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsIBufferedInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsIStreamBufferAccess)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
+    NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream)
+NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream)
+
+NS_IMPL_CI_INTERFACE_GETTER5(nsBufferedInputStream,
                              nsIInputStream,
                              nsIBufferedInputStream,
-                             nsIStreamBufferAccess)
+                             nsISeekableStream,
+                             nsIStreamBufferAccess,
+                             nsIIPCSerializable)
 
 nsresult
 nsBufferedInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
 {
     NS_ENSURE_NO_AGGREGATION(aOuter);
 
     nsBufferedInputStream* stream = new nsBufferedInputStream();
     if (stream == nsnull)
@@ -461,16 +483,52 @@ nsBufferedInputStream::GetUnbufferedStre
     mBufferStartOffset += mCursor;
     mFillPoint = mCursor = 0;
 
     *aStream = mStream;
     NS_IF_ADDREF(*aStream);
     return NS_OK;
 }
 
+PRBool
+nsBufferedInputStream::Read(const IPC::Message *aMsg, void **aIter)
+{
+#ifdef MOZ_IPC
+    using IPC::ReadParam;
+
+    PRUint32 bufferSize;
+    IPC::InputStream inputStream;
+    if (!ReadParam(aMsg, aIter, &bufferSize) ||
+        !ReadParam(aMsg, aIter, &inputStream))
+        return PR_FALSE;
+
+    nsCOMPtr<nsIInputStream> stream(inputStream);
+    nsresult rv = Init(stream, bufferSize);
+    if (NS_FAILED(rv))
+        return PR_FALSE;
+
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
+
+void
+nsBufferedInputStream::Write(IPC::Message *aMsg)
+{
+#ifdef MOZ_IPC
+    using IPC::WriteParam;
+
+    WriteParam(aMsg, mBufferSize);
+
+    IPC::InputStream inputStream(Source());
+    WriteParam(aMsg, inputStream);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsBufferedOutputStream
 
 NS_IMPL_ADDREF_INHERITED(nsBufferedOutputStream, nsBufferedStream)
 NS_IMPL_RELEASE_INHERITED(nsBufferedOutputStream, nsBufferedStream)
 // This QI uses NS_INTERFACE_MAP_ENTRY_CONDITIONAL to check for
 // non-nullness of mSafeStream.
 NS_INTERFACE_MAP_BEGIN(nsBufferedOutputStream)
--- a/netwerk/base/src/nsBufferedStreams.h
+++ b/netwerk/base/src/nsBufferedStreams.h
@@ -41,16 +41,18 @@
 #include "nsIBufferedStreams.h"
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsISeekableStream.h"
 #include "nsIStreamBufferAccess.h"
 #include "nsCOMPtr.h"
 #include "nsInt64.h"
+#include "nsIIPCSerializable.h"
+
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsBufferedStream : public nsISeekableStream
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSISEEKABLESTREAM
 
@@ -84,23 +86,25 @@ protected:
     PRPackedBool                mBufferDisabled;
     PRUint8                     mGetBufferCount;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsBufferedInputStream : public nsBufferedStream,
                               public nsIBufferedInputStream,
-                              public nsIStreamBufferAccess
+                              public nsIStreamBufferAccess,
+                              public nsIIPCSerializable
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIBUFFEREDINPUTSTREAM
     NS_DECL_NSISTREAMBUFFERACCESS
+    NS_DECL_NSIIPCSERIALIZABLE
 
     nsBufferedInputStream() : nsBufferedStream() {}
     virtual ~nsBufferedInputStream() {}
 
     static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
     nsIInputStream* Source() { 
--- a/netwerk/base/src/nsFileStreams.cpp
+++ b/netwerk/base/src/nsFileStreams.cpp
@@ -30,16 +30,20 @@
  * 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 ***** */
 
+#ifdef MOZ_IPC
+#include "IPC/IPCMessageUtils.h"
+#endif
+
 #if defined(XP_UNIX) || defined(XP_BEOS)
 #include <unistd.h>
 #elif defined(XP_WIN)
 #include <windows.h>
 #elif defined(XP_OS2)
 #define INCL_DOSERRORS
 #include <os2.h>
 #else
@@ -54,17 +58,17 @@
 #include "prerror.h"
 #include "nsCRT.h"
 #include "nsInt64.h"
 #include "nsIFile.h"
 #include "nsDirectoryIndexStream.h"
 #include "nsMimeTypes.h"
 #include "nsReadLine.h"
 #include "nsNetUtil.h"
-//#include "nsFileTransportService.h"
+#include "nsIClassInfoImpl.h"
 
 #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsFileStream
 
 nsFileStream::nsFileStream()
     : mFD(nsnull)
@@ -168,21 +172,37 @@ nsFileStream::SetEOF()
 #endif
 
     return NS_OK;
 }
 
 ////////////////////////////////////////////////////////////////////////////////
 // nsFileInputStream
 
-NS_IMPL_ISUPPORTS_INHERITED3(nsFileInputStream,
-                             nsFileStream,
+NS_IMPL_ADDREF_INHERITED(nsFileInputStream, nsFileStream)
+NS_IMPL_RELEASE_INHERITED(nsFileInputStream, nsFileStream)
+
+NS_IMPL_CLASSINFO(nsFileInputStream, NULL, nsIClassInfo::THREADSAFE,
+                  NS_LOCALFILEINPUTSTREAM_CID)
+
+NS_INTERFACE_MAP_BEGIN(nsFileInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsFileStream)
+    NS_INTERFACE_MAP_ENTRY(nsIInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsIFileInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsILineInputStream)
+    NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable)
+    NS_IMPL_QUERY_CLASSINFO(nsFileInputStream)
+NS_INTERFACE_MAP_END_INHERITING(nsFileStream)
+
+NS_IMPL_CI_INTERFACE_GETTER5(nsFileInputStream,
                              nsIInputStream,
                              nsIFileInputStream,
-                             nsILineInputStream)
+                             nsISeekableStream,
+                             nsILineInputStream,
+                             nsIIPCSerializable)
 
 nsresult
 nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult)
 {
     NS_ENSURE_NO_AGGREGATION(aOuter);
 
     nsFileInputStream* stream = new nsFileInputStream();
     if (stream == nsnull)
@@ -219,41 +239,34 @@ nsFileInputStream::Open(nsIFile* aFile, 
     mFD = fd;
 
     if (mBehaviorFlags & DELETE_ON_CLOSE) {
         // POSIX compatible filesystems allow a file to be unlinked while a
         // file descriptor is still referencing the file.  since we've already
         // opened the file descriptor, we'll try to remove the file.  if that
         // fails, then we'll just remember the nsIFile and remove it after we
         // close the file descriptor.
-        rv = aFile->Remove(PR_FALSE);
-        if (NS_FAILED(rv) && !(mBehaviorFlags & REOPEN_ON_REWIND)) {
-            // If REOPEN_ON_REWIND is not happenin', we haven't saved the file yet
-            mFile = aFile;
-        }
+        aFile->Remove(PR_FALSE);
     }
 
     return NS_OK;
 }
 
 NS_IMETHODIMP
 nsFileInputStream::Init(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm,
                         PRInt32 aBehaviorFlags)
 {
     NS_ENSURE_TRUE(!mFD, NS_ERROR_ALREADY_INITIALIZED);
     NS_ENSURE_TRUE(!mParent, NS_ERROR_ALREADY_INITIALIZED);
 
     mBehaviorFlags = aBehaviorFlags;
 
-    // If the file will be reopened on rewind, save the info to open the file
-    if (mBehaviorFlags & REOPEN_ON_REWIND) {
-        mFile = aFile;
-        mIOFlags = aIOFlags;
-        mPerm = aPerm;
-    }
+    mFile = aFile;
+    mIOFlags = aIOFlags;
+    mPerm = aPerm;
 
     return Open(aFile, aIOFlags, aPerm);
 }
 
 NS_IMETHODIMP
 nsFileInputStream::Close()
 {
     // null out mLineBuffer in case Close() is called again after failing
@@ -358,16 +371,64 @@ nsFileInputStream::Seek(PRInt32 aWhence,
         } else {
             return NS_BASE_STREAM_CLOSED;
         }
     }
 
     return nsFileStream::Seek(aWhence, aOffset);
 }
 
+PRBool
+nsFileInputStream::Read(const IPC::Message *aMsg, void **aIter)
+{
+#ifdef MOZ_IPC
+    using IPC::ReadParam;
+
+    nsCString path;
+    PRBool followLinks;
+    PRInt32 flags;
+    if (!ReadParam(aMsg, aIter, &path) ||
+        !ReadParam(aMsg, aIter, &followLinks) ||
+        !ReadParam(aMsg, aIter, &flags))
+        return PR_FALSE;
+
+    nsCOMPtr<nsILocalFile> file;
+    nsresult rv = NS_NewNativeLocalFile(path, followLinks, getter_AddRefs(file));
+    if (NS_FAILED(rv))
+        return PR_FALSE;
+
+    // IO flags = -1 means readonly, and
+    // permissions are unimportant since we're reading
+    rv = Init(file, -1, -1, flags);
+    if (NS_FAILED(rv))
+        return PR_FALSE;
+
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
+
+void
+nsFileInputStream::Write(IPC::Message *aMsg)
+{
+#ifdef MOZ_IPC
+    using IPC::WriteParam;
+
+    nsCString path;
+    mFile->GetNativePath(path);
+    WriteParam(aMsg, path);
+    nsCOMPtr<nsILocalFile> localFile = do_QueryInterface(mFile);
+    PRBool followLinks;
+    localFile->GetFollowLinks(&followLinks);
+    WriteParam(aMsg, followLinks);
+    WriteParam(aMsg, mBehaviorFlags);
+#endif
+}
+
 ////////////////////////////////////////////////////////////////////////////////
 // nsPartialFileInputStream
 
 // Don't forward to nsFileInputStream as we don't want to QI to
 // nsIFileInputStream
 NS_IMPL_ISUPPORTS_INHERITED3(nsPartialFileInputStream,
                              nsFileStream,
                              nsIInputStream,
--- a/netwerk/base/src/nsFileStreams.h
+++ b/netwerk/base/src/nsFileStreams.h
@@ -43,16 +43,17 @@
 #include "nsIInputStream.h"
 #include "nsIOutputStream.h"
 #include "nsISafeOutputStream.h"
 #include "nsISeekableStream.h"
 #include "nsILineInputStream.h"
 #include "nsCOMPtr.h"
 #include "prlog.h"
 #include "prio.h"
+#include "nsIIPCSerializable.h"
 
 template<class CharType> class nsLineBuffer;
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsFileStream : public nsISeekableStream
 {
 public:
@@ -71,23 +72,25 @@ protected:
                                    // which ensures mFD remains valid.
     PRBool                mCloseFD;
 };
 
 ////////////////////////////////////////////////////////////////////////////////
 
 class nsFileInputStream : public nsFileStream,
                           public nsIFileInputStream,
-                          public nsILineInputStream
+                          public nsILineInputStream,
+                          public nsIIPCSerializable
 {
 public:
     NS_DECL_ISUPPORTS_INHERITED
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIFILEINPUTSTREAM
     NS_DECL_NSILINEINPUTSTREAM
+    NS_DECL_NSIIPCSERIALIZABLE
     
     // Overrided from nsFileStream
     NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset);
 
     nsFileInputStream() : nsFileStream() 
     {
         mLineBuffer = nsnull;
         mBehaviorFlags = 0;
@@ -99,28 +102,25 @@ public:
 
     static nsresult
     Create(nsISupports *aOuter, REFNSIID aIID, void **aResult);
 
 protected:
     nsLineBuffer<char> *mLineBuffer;
 
     /**
-     * The file being opened.  Only stored when DELETE_ON_CLOSE or
-     * REOPEN_ON_REWIND are true.
+     * The file being opened.
      */
     nsCOMPtr<nsIFile> mFile;
     /**
      * The IO flags passed to Init() for the file open.
-     * Only set for REOPEN_ON_REWIND.
      */
     PRInt32 mIOFlags;
     /**
      * The permissions passed to Init() for the file open.
-     * Only set for REOPEN_ON_REWIND.
      */
     PRInt32 mPerm;
     /**
      * Flags describing our behavior.  See the IDL file for possible values.
      */
     PRInt32 mBehaviorFlags;
 
 protected:
--- a/netwerk/base/src/nsMIMEInputStream.cpp
+++ b/netwerk/base/src/nsMIMEInputStream.cpp
@@ -36,35 +36,45 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * The MIME stream separates headers and a datastream. It also allows
  * automatic creation of the content-length header.
  */
 
+#ifdef MOZ_IPC
+#include "IPC/IPCMessageUtils.h"
+#include "mozilla/net/PHttpChannelParams.h"
+#endif
+
 #include "nsCOMPtr.h"
 #include "nsComponentManagerUtils.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsIMIMEInputStream.h"
 #include "nsISeekableStream.h"
 #include "nsIStringStream.h"
 #include "nsString.h"
+#include "nsMIMEInputStream.h"
+#include "nsIIPCSerializable.h"
+#include "nsIClassInfoImpl.h"
 
 class nsMIMEInputStream : public nsIMIMEInputStream,
-                          public nsISeekableStream
+                          public nsISeekableStream,
+                          public nsIIPCSerializable
 {
 public:
     nsMIMEInputStream();
     virtual ~nsMIMEInputStream();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIMIMEINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
+    NS_DECL_NSIIPCSERIALIZABLE
     
     NS_METHOD Init();
 
 private:
 
     void InitStreams();
 
     struct ReadSegmentsState {
@@ -83,20 +93,32 @@ private:
     nsCOMPtr<nsIStringInputStream> mCLStream;
     
     nsCOMPtr<nsIInputStream> mData;
     nsCOMPtr<nsIMultiplexInputStream> mStream;
     PRPackedBool mAddContentLength;
     PRPackedBool mStartedReading;
 };
 
-NS_IMPL_THREADSAFE_ISUPPORTS3(nsMIMEInputStream,
-                              nsIMIMEInputStream,
-                              nsIInputStream,
-                              nsISeekableStream)
+NS_IMPL_THREADSAFE_ADDREF(nsMIMEInputStream)
+NS_IMPL_THREADSAFE_RELEASE(nsMIMEInputStream)
+
+NS_IMPL_CLASSINFO(nsMIMEInputStream, NULL, nsIClassInfo::THREADSAFE,
+                  NS_MIMEINPUTSTREAM_CID)
+
+NS_IMPL_QUERY_INTERFACE4_CI(nsMIMEInputStream,
+                            nsIMIMEInputStream,
+                            nsIInputStream,
+                            nsISeekableStream,
+                            nsIIPCSerializable)
+NS_IMPL_CI_INTERFACE_GETTER4(nsMIMEInputStream,
+                             nsIMIMEInputStream,
+                             nsIInputStream,
+                             nsISeekableStream,
+                             nsIIPCSerializable)
 
 nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(PR_FALSE),
                                          mStartedReading(PR_FALSE)
 {
 }
 
 nsMIMEInputStream::~nsMIMEInputStream()
 {
@@ -300,8 +322,63 @@ nsMIMEInputStreamConstructor(nsISupports
         return rv;
     }
 
     rv = inst->QueryInterface(iid, result);
     NS_RELEASE(inst);
 
     return rv;
 }
+
+PRBool
+nsMIMEInputStream::Read(const IPC::Message *aMsg, void **aIter)
+{
+#ifdef MOZ_IPC
+    using IPC::ReadParam;
+
+    if (!ReadParam(aMsg, aIter, &mHeaders) ||
+        !ReadParam(aMsg, aIter, &mContentLength) ||
+        !ReadParam(aMsg, aIter, &mStartedReading))
+        return PR_FALSE;
+
+    // nsMIMEInputStream::Init() already appended mHeaderStream & mCLStream
+    mHeaderStream->ShareData(mHeaders.get(),
+                             mStartedReading? mHeaders.Length() : 0);
+    mCLStream->ShareData(mContentLength.get(),
+                         mStartedReading? mContentLength.Length() : 0);
+
+    IPC::InputStream inputStream;
+    if (!ReadParam(aMsg, aIter, &inputStream))
+        return PR_FALSE;
+
+    nsCOMPtr<nsIInputStream> stream(inputStream);
+    mData = stream;
+    if (stream) {
+        nsresult rv = mStream->AppendStream(mData);
+        if (NS_FAILED(rv))
+            return PR_FALSE;
+    }
+
+    if (!ReadParam(aMsg, aIter, &mAddContentLength))
+        return PR_FALSE;
+
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
+
+void
+nsMIMEInputStream::Write(IPC::Message *aMsg)
+{
+#ifdef MOZ_IPC
+    using IPC::WriteParam;
+
+    WriteParam(aMsg, mHeaders);
+    WriteParam(aMsg, mContentLength);
+    WriteParam(aMsg, mStartedReading);
+
+    IPC::InputStream inputStream(mData);
+    WriteParam(aMsg, inputStream);
+
+    WriteParam(aMsg, mAddContentLength);
+#endif
+}
--- a/netwerk/protocol/http/HttpBaseChannel.h
+++ b/netwerk/protocol/http/HttpBaseChannel.h
@@ -76,20 +76,16 @@
   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 {
 
-typedef enum { eUploadStream_null = -1,
-               eUploadStream_hasNoHeaders = 0,
-               eUploadStream_hasHeaders = 1 } UploadStreamInfoType;
-
 /*
  * 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
  *   the way to the HTTP channel.
  */
 class HttpBaseChannel : public nsHashPropertyBag
--- a/netwerk/protocol/http/HttpChannelChild.cpp
+++ b/netwerk/protocol/http/HttpChannelChild.cpp
@@ -830,39 +830,16 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
 
   // Port checked in parent, but duplicate here so we can return with error
   // immediately
   nsresult rv;
   rv = NS_CheckPortSafety(mURI);
   if (NS_FAILED(rv))
     return rv;
 
-  // Prepare uploadStream for POST data
-  nsCAutoString uploadStreamData;
-  PRInt32 uploadStreamInfo;
-
-  if (mUploadStream) {
-    // Read entire POST stream into string:
-    // This is a temporary measure until bug 564553 is implemented:  we're doing
-    // a blocking read of a potentially arbitrarily large stream, so this isn't
-    // performant/safe for large file uploads.
-    PRUint32 bytes;
-    mUploadStream->Available(&bytes);
-    if (bytes > 0) {
-      rv = NS_ReadInputStreamToString(mUploadStream, uploadStreamData, bytes);
-      if (NS_FAILED(rv))
-        return rv;
-    }
-
-    uploadStreamInfo = mUploadStreamHasHeaders ? 
-      eUploadStream_hasHeaders : eUploadStream_hasNoHeaders;
-  } else {
-    uploadStreamInfo = eUploadStream_null;
-  }
-
   const char *cookieHeader = mRequestHead.PeekHeader(nsHttp::Cookie);
   if (cookieHeader) {
     mUserSetCookieHeader = cookieHeader;
   }
 
   AddCookiesToRequest();
 
   //
@@ -925,19 +902,20 @@ HttpChannelChild::AsyncOpen(nsIStreamLis
   // 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();
 
   gNeckoChild->SendPHttpChannelConstructor(this, tabChild);
 
   SendAsyncOpen(IPC::URI(mURI), IPC::URI(mOriginalURI),
                 IPC::URI(mDocumentURI), IPC::URI(mReferrer), mLoadFlags,
-                mRequestHeaders, mRequestHead.Method(), uploadStreamData,
-                uploadStreamInfo, mPriority, mRedirectionLimit,
-                mAllowPipelining, mForceAllowThirdPartyCookie, mSendResumeAt,
+                mRequestHeaders, mRequestHead.Method(),
+                IPC::InputStream(mUploadStream), mUploadStreamHasHeaders,
+                mPriority, mRedirectionLimit, mAllowPipelining,
+                mForceAllowThirdPartyCookie, mSendResumeAt,
                 mStartPos, mEntityID, mChooseApplicationCache, 
                 appCacheClientId);
 
   return NS_OK;
 }
 
 //-----------------------------------------------------------------------------
 // HttpChannelChild::nsIHttpChannel
--- a/netwerk/protocol/http/HttpChannelParent.cpp
+++ b/netwerk/protocol/http/HttpChannelParent.cpp
@@ -99,18 +99,18 @@ NS_IMPL_ISUPPORTS1(HttpChannelParent,
 bool 
 HttpChannelParent::RecvAsyncOpen(const IPC::URI&            aURI,
                                  const IPC::URI&            aOriginalURI,
                                  const IPC::URI&            aDocURI,
                                  const IPC::URI&            aReferrerURI,
                                  const PRUint32&            loadFlags,
                                  const RequestHeaderTuples& requestHeaders,
                                  const nsHttpAtom&          requestMethod,
-                                 const nsCString&           uploadStreamData,
-                                 const PRInt32&             uploadStreamInfo,
+                                 const IPC::InputStream&    uploadStream,
+                                 const PRBool&              uploadStreamHasHeaders,
                                  const PRUint16&            priority,
                                  const PRUint8&             redirectionLimit,
                                  const PRBool&              allowPipelining,
                                  const PRBool&              forceAllowThirdPartyCookie,
                                  const bool&                doResumeAt,
                                  const PRUint64&            startPos,
                                  const nsCString&           entityID,
                                  const bool&                chooseApplicationCache,
@@ -157,26 +157,20 @@ HttpChannelParent::RecvAsyncOpen(const I
   }
 
   mChannelListener = new HttpChannelParentListener(this);
 
   httpChan->SetNotificationCallbacks(mChannelListener);
 
   httpChan->SetRequestMethod(nsDependentCString(requestMethod.get()));
 
-  if (uploadStreamInfo != eUploadStream_null) {
-    nsCOMPtr<nsIInputStream> stream;
-    rv = NS_NewPostDataStream(getter_AddRefs(stream), false, uploadStreamData, 0);
-    if (NS_FAILED(rv))
-      return SendCancelEarly(rv);
-
+  nsCOMPtr<nsIInputStream> stream(uploadStream);
+  if (stream) {
     httpChan->InternalSetUploadStream(stream);
-    // We're casting uploadStreamInfo into PRBool here on purpose because
-    // we know possible values are either 0 or 1. See uploadStreamInfoType.
-    httpChan->SetUploadStreamHasHeaders((PRBool) uploadStreamInfo);
+    httpChan->SetUploadStreamHasHeaders(uploadStreamHasHeaders);
   }
 
   if (priority != nsISupportsPriority::PRIORITY_NORMAL)
     httpChan->SetPriority(priority);
   httpChan->SetRedirectionLimit(redirectionLimit);
   httpChan->SetAllowPipelining(allowPipelining);
   httpChan->SetForceAllowThirdPartyCookie(forceAllowThirdPartyCookie);
 
--- a/netwerk/protocol/http/HttpChannelParent.h
+++ b/netwerk/protocol/http/HttpChannelParent.h
@@ -83,18 +83,18 @@ public:
 protected:
   virtual bool RecvAsyncOpen(const IPC::URI&            uri,
                              const IPC::URI&            originalUri,
                              const IPC::URI&            docUri,
                              const IPC::URI&            referrerUri,
                              const PRUint32&            loadFlags,
                              const RequestHeaderTuples& requestHeaders,
                              const nsHttpAtom&          requestMethod,
-                             const nsCString&           uploadStreamData,
-                             const PRInt32&             uploadStreamInfo,
+                             const IPC::InputStream&    uploadStream,
+                             const PRBool&              uploadStreamHasHeaders,
                              const PRUint16&            priority,
                              const PRUint8&             redirectionLimit,
                              const PRBool&              allowPipelining,
                              const PRBool&              forceAllowThirdPartyCookie,
                              const bool&                doResumeAt,
                              const PRUint64&            startPos,
                              const nsCString&           entityID,
                              const bool&                chooseApplicationCache,
--- a/netwerk/protocol/http/PHttpChannel.ipdl
+++ b/netwerk/protocol/http/PHttpChannel.ipdl
@@ -43,16 +43,17 @@ include protocol PNecko;
 
 include "mozilla/net/PHttpChannelParams.h";
 include "mozilla/net/NeckoMessageUtils.h";
 
 using RequestHeaderTuples;
 using nsHttpResponseHead;
 using nsHttpAtom;
 using IPC::URI;
+using IPC::InputStream;
 
 namespace mozilla {
 namespace net {
 
 //-------------------------------------------------------------------
 protocol PHttpChannel
 {
   manager PNecko;
@@ -63,18 +64,18 @@ parent:
             // set originalURI != uri (about:credits?); also not clear if
             // chrome channel would ever need to know.  Get rid of next arg?
             URI                 original,
             URI                 doc,
             URI                 referrer,
             PRUint32            loadFlags,
             RequestHeaderTuples requestHeaders,
             nsHttpAtom          requestMethod,
-            nsCString           uploadStreamData,
-            PRInt32             uploadStreamInfo,
+            InputStream         uploadStream,
+            PRBool              uploadStreamHasHeaders,
             PRUint16            priority,
             PRUint8             redirectionLimit,
             PRBool              allowPipelining,
             PRBool              forceAllowThirdPartyCookie,
             bool                resumeAt,
             PRUint64            startPos,
             nsCString           entityID,
             bool                chooseApplicationCache,
--- a/netwerk/protocol/http/PHttpChannelParams.h
+++ b/netwerk/protocol/http/PHttpChannelParams.h
@@ -44,18 +44,20 @@
 #define ALLOW_LATE_NSHTTP_H_INCLUDE 1
 #include "base/basictypes.h"
 
 #include "IPC/IPCMessageUtils.h"
 #include "nsHttp.h"
 #include "nsHttpHeaderArray.h"
 #include "nsHttpResponseHead.h"
 
-#include "nsIStringStream.h"
-#include "nsISupportsPrimitives.h"
+#include "nsStringStream.h"
+#include "nsIIPCSerializable.h"
+#include "nsIClassInfo.h"
+#include "nsNetUtil.h"
 
 namespace mozilla {
 namespace net {
 
 struct RequestHeaderTuple {
   nsCString mHeader;
   nsCString mValue;
   PRBool    mMerge;
@@ -190,61 +192,114 @@ struct ParamTraits<nsHttpResponseHead>
         !ReadParam(aMsg, aIter, &(aResult->mCacheControlNoCache)) ||
         !ReadParam(aMsg, aIter, &(aResult->mPragmaNoCache)))
       return false;
 
     return true;
   }
 };
 
+class InputStream {
+public:
+  InputStream() : mStream(nsnull) {}
+  InputStream(nsIInputStream* aStream) : mStream(aStream) {}
+  operator nsIInputStream*() const { return mStream.get(); }
+
+  friend struct ParamTraits<InputStream>;
+
+private:
+  // Unimplemented
+  InputStream& operator=(InputStream&);
+
+  nsCOMPtr<nsIInputStream> mStream;
+};
+
 template<>
-struct ParamTraits<nsIStringInputStream*>
+struct ParamTraits<InputStream>
 {
-  typedef nsIStringInputStream* paramType;
+  typedef InputStream paramType;
 
   static void Write(Message* aMsg, const paramType& aParam)
   {
-    nsCAutoString value;
-    nsCOMPtr<nsISupportsCString> cstr(do_QueryInterface(aParam));
+    bool isNull = !aParam.mStream;
+    aMsg->WriteBool(isNull);
+
+    if (isNull)
+      return;
+
+    nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mStream);
+    bool isSerializable = !!serializable;
+    WriteParam(aMsg, isSerializable);
 
-    if (cstr) {
-      cstr->GetData(value);
-    } else {
-      PRUint32 length;
-      aParam->Available(&length);
-      value.SetLength(length);
-      NS_ASSERTION(value.Length() == length, "SetLength failed");
-      char *c = value.BeginWriting();
-      PRUint32 bytesRead;
-#ifdef DEBUG
-      nsresult rv = 
-#endif
-      aParam->Read(c, length, &bytesRead);
-      NS_ASSERTION(NS_SUCCEEDED(rv) && bytesRead == length, "Read failed");
+    if (!serializable) {
+      NS_WARNING("nsIInputStream implementation doesn't support nsIIPCSerializable; falling back to copying data");
+
+      nsCString streamString;
+      PRUint32 bytes;
+
+      aParam.mStream->Available(&bytes);
+      if (bytes > 0) {
+        nsresult rv = NS_ReadInputStreamToString(aParam.mStream, streamString, bytes);
+        NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "Can't read input stream into a string!");
+      }
+
+      WriteParam(aMsg, streamString);
+      return;
     }
 
-    WriteParam(aMsg, value);
+    nsCOMPtr<nsIClassInfo> classInfo = do_QueryInterface(aParam.mStream);
+    char cidStr[NSID_LENGTH];
+    nsCID cid;
+    nsresult rv = classInfo->GetClassIDNoAlloc(&cid);
+    NS_ABORT_IF_FALSE(NS_SUCCEEDED(rv), "All IPDL streams must report a valid class ID");
+
+    cid.ToProvidedString(cidStr);
+    WriteParam(aMsg, nsCAutoString(cidStr));
+    serializable->Write(aMsg);
   }
 
   static bool Read(const Message* aMsg, void** aIter, paramType* aResult)
   {
-    nsCAutoString value;
-    if (!ReadParam(aMsg, aIter, &value))
+    bool isNull;
+    if (!ReadParam(aMsg, aIter, &isNull))
+      return false;
+
+    if (isNull) {
+      aResult->mStream = nsnull;
+      return true;
+    }
+
+    bool isSerializable;
+    if (!ReadParam(aMsg, aIter, &isSerializable))
       return false;
 
-    nsresult rv;
+    nsCOMPtr<nsIInputStream> stream;
+    if (!isSerializable) {
+      nsCString streamString;
+      if (!ReadParam(aMsg, aIter, &streamString))
+        return false;
 
-    nsCOMPtr<nsIStringInputStream> stream
-      (do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
-    if (NS_FAILED(rv))
-      return false;
+      nsresult rv = NS_NewCStringInputStream(getter_AddRefs(stream), streamString);
+      if (NS_FAILED(rv))
+        return false;
+    } else {
+      nsCAutoString cidStr;
+      nsCID cid;
+      if (!ReadParam(aMsg, aIter, &cidStr) ||
+          !cid.Parse(cidStr.get()))
+        return false;
 
-    rv = stream->SetData(value.get(), value.Length());
-    if (NS_FAILED(rv))
-      return false;
+      stream = do_CreateInstance(cid);
+      if (!stream)
+        return false;
+      nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(stream);
+      if (!serializable || !serializable->Read(aMsg, aIter))
+        return false;
+    }
 
-    stream.forget(aResult);
+    stream.swap(aResult->mStream);
     return true;
   }
 };
+
 } // namespace IPC
 
 #endif // mozilla_net_PHttpChannelParams_h
--- a/xpcom/io/Makefile.in
+++ b/xpcom/io/Makefile.in
@@ -182,26 +182,27 @@ EXPORTS		:= $(addprefix $(srcdir)/, $(EX
 
 # we don't want the shared lib, but we want to force the creation of a static lib.
 FORCE_STATIC_LIB = 1
 
 # Force use of PIC
 FORCE_USE_PIC	= 1
 
 include $(topsrcdir)/config/rules.mk
+include $(topsrcdir)/ipc/chromium/chromium-config.mk
 
 DEFINES		+= -D_IMPL_NS_COM
 
 ifeq ($(OS_ARCH),Linux)
 ifneq (,$(findstring lib64,$(libdir)))
 DEFINES     += -DHAVE_USR_LIB64_DIR
 endif
 endif
 
-LOCAL_INCLUDES	= -I..
+LOCAL_INCLUDES	+= -I..
 
 ifeq ($(MOZ_PLATFORM_MAEMO),5)
 CFLAGS          += $(MOZ_DBUS_CFLAGS)
 CXXFLAGS        += $(MOZ_DBUS_CFLAGS)
 endif
 
 ifdef MOZ_PLATFORM_MAEMO
 CFLAGS          += $(MOZ_PLATFORM_MAEMO_CFLAGS)
--- a/xpcom/io/nsMultiplexInputStream.cpp
+++ b/xpcom/io/nsMultiplexInputStream.cpp
@@ -36,33 +36,42 @@
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * The multiplex stream concatenates a list of input streams into a single
  * stream.
  */
 
+#ifdef MOZ_IPC
+#include "IPC/IPCMessageUtils.h"
+#include "mozilla/net/PHttpChannelParams.h"
+#endif
+
 #include "nsMultiplexInputStream.h"
 #include "nsIMultiplexInputStream.h"
 #include "nsISeekableStream.h"
 #include "nsCOMPtr.h"
 #include "nsCOMArray.h"
 #include "nsInt64.h"
+#include "nsIIPCSerializable.h"
+#include "nsIClassInfoImpl.h"
 
 class nsMultiplexInputStream : public nsIMultiplexInputStream,
-                               public nsISeekableStream
+                               public nsISeekableStream,
+                               public nsIIPCSerializable
 {
 public:
     nsMultiplexInputStream();
 
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSIMULTIPLEXINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
+    NS_DECL_NSIIPCSERIALIZABLE
 
 private:
     ~nsMultiplexInputStream() {}
 
     struct ReadSegmentsState {
         nsIInputStream* mThisStream;
         PRUint32 mOffset;
         nsWriteSegmentFun mWriter;
@@ -75,21 +84,32 @@ private:
                                PRUint32 aCount, PRUint32 *aWriteCount);
     
     nsCOMArray<nsIInputStream> mStreams;
     PRUint32 mCurrentStream;
     PRBool mStartedReadingCurrent;
     nsresult mStatus;
 };
 
+NS_IMPL_THREADSAFE_ADDREF(nsMultiplexInputStream)
+NS_IMPL_THREADSAFE_RELEASE(nsMultiplexInputStream)
 
-NS_IMPL_THREADSAFE_ISUPPORTS3(nsMultiplexInputStream,
-                              nsIMultiplexInputStream,
-                              nsIInputStream,
-                              nsISeekableStream)
+NS_IMPL_CLASSINFO(nsMultiplexInputStream, NULL, nsIClassInfo::THREADSAFE,
+                  NS_MULTIPLEXINPUTSTREAM_CID)
+
+NS_IMPL_QUERY_INTERFACE4_CI(nsMultiplexInputStream,
+                            nsIMultiplexInputStream,
+                            nsIInputStream,
+                            nsISeekableStream,
+                            nsIIPCSerializable)
+NS_IMPL_CI_INTERFACE_GETTER4(nsMultiplexInputStream,
+                             nsIMultiplexInputStream,
+                             nsIInputStream,
+                             nsISeekableStream,
+                             nsIIPCSerializable)
 
 nsMultiplexInputStream::nsMultiplexInputStream()
     : mCurrentStream(0),
       mStartedReadingCurrent(PR_FALSE),
       mStatus(NS_OK)
 {
 }
 
@@ -403,8 +423,60 @@ nsMultiplexInputStreamConstructor(nsISup
         return NS_ERROR_OUT_OF_MEMORY;
 
     NS_ADDREF(inst);
     nsresult rv = inst->QueryInterface(iid, result);
     NS_RELEASE(inst);
 
     return rv;
 }
+
+PRBool
+nsMultiplexInputStream::Read(const IPC::Message *aMsg, void **aIter)
+{
+#ifdef MOZ_IPC
+    using IPC::ReadParam;
+
+    PRUint32 count;
+    if (!ReadParam(aMsg, aIter, &count))
+        return PR_FALSE;
+
+    for (PRUint32 i = 0; i < count; i++) {
+        IPC::InputStream inputStream;
+        if (!ReadParam(aMsg, aIter, &inputStream))
+            return PR_FALSE;
+
+        nsCOMPtr<nsIInputStream> stream(inputStream);
+        nsresult rv = AppendStream(stream);
+        if (NS_FAILED(rv))
+            return PR_FALSE;
+    }
+
+    if (!ReadParam(aMsg, aIter, &mCurrentStream) ||
+        !ReadParam(aMsg, aIter, &mStartedReadingCurrent) ||
+        !ReadParam(aMsg, aIter, &mStatus))
+        return PR_FALSE;
+
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
+
+void
+nsMultiplexInputStream::Write(IPC::Message *aMsg)
+{
+#ifdef MOZ_IPC
+    using IPC::WriteParam;
+
+    PRUint32 count = mStreams.Count();
+    WriteParam(aMsg, count);
+
+    for (PRUint32 i = 0; i < count; i++) {
+        IPC::InputStream inputStream(mStreams.ObjectAt(i));
+        WriteParam(aMsg, inputStream);
+    }
+
+    WriteParam(aMsg, mCurrentStream);
+    WriteParam(aMsg, mStartedReadingCurrent);
+    WriteParam(aMsg, mStatus);
+#endif
+}
--- a/xpcom/io/nsStringStream.cpp
+++ b/xpcom/io/nsStringStream.cpp
@@ -47,42 +47,49 @@
  * the terms of any one of the MPL, the GPL or the LGPL.
  *
  * ***** END LICENSE BLOCK ***** */
 
 /**
  * Based on original code from nsIStringStream.cpp
  */
 
+#ifdef MOZ_IPC
+#include "IPC/IPCMessageUtils.h"
+#endif
+
 #include "nsStringStream.h"
 #include "nsStreamUtils.h"
 #include "nsReadableUtils.h"
 #include "nsISeekableStream.h"
 #include "nsISupportsPrimitives.h"
 #include "nsInt64.h"
 #include "nsCRT.h"
 #include "prerror.h"
 #include "plstr.h"
 #include "nsIClassInfoImpl.h"
+#include "nsIIPCSerializable.h"
 
 //-----------------------------------------------------------------------------
 // nsIStringInputStream implementation
 //-----------------------------------------------------------------------------
 
 class nsStringInputStream : public nsIStringInputStream
                           , public nsISeekableStream
                           , public nsISupportsCString
+                          , public nsIIPCSerializable
 {
 public:
     NS_DECL_ISUPPORTS
     NS_DECL_NSIINPUTSTREAM
     NS_DECL_NSISTRINGINPUTSTREAM
     NS_DECL_NSISEEKABLESTREAM
     NS_DECL_NSISUPPORTSPRIMITIVE
     NS_DECL_NSISUPPORTSCSTRING
+    NS_DECL_NSIIPCSERIALIZABLE
 
     nsStringInputStream()
         : mData(nsnull)
         , mOffset(0)
         , mLength(0)
         , mOwned(PR_FALSE)
     {}
 
@@ -116,26 +123,28 @@ private:
 
 // This class needs to support threadsafe refcounting since people often
 // allocate a string stream, and then read it from a background thread.
 NS_IMPL_THREADSAFE_ADDREF(nsStringInputStream)
 NS_IMPL_THREADSAFE_RELEASE(nsStringInputStream)
 
 NS_IMPL_CLASSINFO(nsStringInputStream, NULL, nsIClassInfo::THREADSAFE,
                   NS_STRINGINPUTSTREAM_CID)
-NS_IMPL_QUERY_INTERFACE4_CI(nsStringInputStream,
+NS_IMPL_QUERY_INTERFACE5_CI(nsStringInputStream,
                             nsIStringInputStream,
                             nsIInputStream,
                             nsISupportsCString,
-                            nsISeekableStream)
-NS_IMPL_CI_INTERFACE_GETTER4(nsStringInputStream,
+                            nsISeekableStream,
+                            nsIIPCSerializable)
+NS_IMPL_CI_INTERFACE_GETTER5(nsStringInputStream,
                              nsIStringInputStream,
                              nsIInputStream,
                              nsISupportsCString,
-                             nsISeekableStream)
+                             nsISeekableStream,
+                             nsIIPCSerializable)
 
 /////////
 // nsISupportsCString implementation
 /////////
 
 NS_IMETHODIMP
 nsStringInputStream::GetType(PRUint16 *type)
 {
@@ -344,16 +353,54 @@ nsStringInputStream::SetEOF()
 {
     if (!mData)
         return NS_BASE_STREAM_CLOSED;
 
     mLength = mOffset;
     return NS_OK;
 }
 
+/////////
+// nsIIPCSerializable implementation
+/////////
+
+PRBool
+nsStringInputStream::Read(const IPC::Message *aMsg, void **aIter)
+{
+#ifdef MOZ_IPC
+    using IPC::ReadParam;
+
+    nsCAutoString value;
+
+    if (!ReadParam(aMsg, aIter, &value))
+        return PR_FALSE;
+
+    nsresult rv = SetData(value.get(), value.Length());
+    if (NS_FAILED(rv))
+        return PR_FALSE;
+
+    return PR_TRUE;
+#else
+    return PR_FALSE;
+#endif
+}
+
+void
+nsStringInputStream::Write(IPC::Message *aMsg)
+{
+#ifdef MOZ_IPC
+    using IPC::WriteParam;
+
+    nsCAutoString value;
+    GetData(value);
+
+    WriteParam(aMsg, value);
+#endif
+}
+
 NS_COM nsresult
 NS_NewByteInputStream(nsIInputStream** aStreamResult,
                       const char* aStringToRead, PRInt32 aLength,
                       nsAssignmentType aAssignment)
 {
     NS_PRECONDITION(aStreamResult, "null out ptr");
 
     nsStringInputStream* stream = new nsStringInputStream();