зеркало из https://github.com/mozilla/gecko-dev.git
Bug 564553 - e10s HTTP: Serialize nsInputStreams to support large file uploads. Part 1: serialize them. r=dwitte, a=blocking-fennec2.0b2+
This commit is contained in:
Родитель
6c1ea3e5dc
Коммит
b33b8c353d
|
@ -35,9 +35,16 @@
|
|||
*
|
||||
* ***** 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
|
||||
|
@ -246,11 +253,26 @@ nsBufferedStream::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)
|
||||
|
@ -466,6 +488,42 @@ nsBufferedInputStream::GetUnbufferedStream(nsISupports* *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
|
||||
|
||||
|
|
|
@ -46,6 +46,8 @@
|
|||
#include "nsIStreamBufferAccess.h"
|
||||
#include "nsCOMPtr.h"
|
||||
#include "nsInt64.h"
|
||||
#include "nsIIPCSerializable.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
class nsBufferedStream : public nsISeekableStream
|
||||
|
@ -89,13 +91,15 @@ protected:
|
|||
|
||||
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() {}
|
||||
|
|
|
@ -35,6 +35,10 @@
|
|||
*
|
||||
* ***** 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)
|
||||
|
@ -59,7 +63,7 @@
|
|||
#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
|
||||
|
||||
|
@ -173,11 +177,27 @@ nsFileStream::SetEOF()
|
|||
////////////////////////////////////////////////////////////////////////////////
|
||||
// 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)
|
||||
|
@ -224,11 +244,7 @@ nsFileInputStream::Open(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm)
|
|||
// 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;
|
||||
|
@ -243,12 +259,9 @@ nsFileInputStream::Init(nsIFile* aFile, PRInt32 aIOFlags, PRInt32 aPerm,
|
|||
|
||||
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);
|
||||
}
|
||||
|
@ -363,6 +376,54 @@ nsFileInputStream::Seek(PRInt32 aWhence, PRInt64 aOffset)
|
|||
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
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
#include "nsCOMPtr.h"
|
||||
#include "prlog.h"
|
||||
#include "prio.h"
|
||||
#include "nsIIPCSerializable.h"
|
||||
|
||||
template<class CharType> class nsLineBuffer;
|
||||
|
||||
|
@ -76,13 +77,15 @@ protected:
|
|||
|
||||
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);
|
||||
|
@ -104,18 +107,15 @@ 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;
|
||||
/**
|
||||
|
|
|
@ -41,6 +41,11 @@
|
|||
* 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"
|
||||
|
@ -48,9 +53,13 @@
|
|||
#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();
|
||||
|
@ -60,6 +69,7 @@ public:
|
|||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIMIMEINPUTSTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSIIPCSERIALIZABLE
|
||||
|
||||
NS_METHOD Init();
|
||||
|
||||
|
@ -88,10 +98,22 @@ private:
|
|||
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)
|
||||
|
@ -305,3 +327,58 @@ nsMIMEInputStreamConstructor(nsISupports *outer, REFNSIID iid, void **result)
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -81,10 +81,6 @@
|
|||
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.
|
||||
|
|
|
@ -820,29 +820,6 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
|
|||
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;
|
||||
|
@ -899,9 +876,10 @@ HttpChannelChild::AsyncOpen(nsIStreamListener *listener, nsISupports *aContext)
|
|||
|
||||
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);
|
||||
|
||||
return NS_OK;
|
||||
|
|
|
@ -102,8 +102,8 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
|
|||
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,
|
||||
|
@ -158,16 +158,10 @@ HttpChannelParent::RecvAsyncOpen(const IPC::URI& aURI,
|
|||
|
||||
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)
|
||||
|
|
|
@ -88,8 +88,8 @@ protected:
|
|||
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,
|
||||
|
|
|
@ -48,6 +48,7 @@ using RequestHeaderTuples;
|
|||
using nsHttpResponseHead;
|
||||
using nsHttpAtom;
|
||||
using IPC::URI;
|
||||
using IPC::InputStream;
|
||||
|
||||
namespace mozilla {
|
||||
namespace net {
|
||||
|
@ -68,8 +69,8 @@ parent:
|
|||
PRUint32 loadFlags,
|
||||
RequestHeaderTuples requestHeaders,
|
||||
nsHttpAtom requestMethod,
|
||||
nsCString uploadStreamData,
|
||||
PRInt32 uploadStreamInfo,
|
||||
InputStream uploadStream,
|
||||
PRBool uploadStreamHasHeaders,
|
||||
PRUint16 priority,
|
||||
PRUint8 redirectionLimit,
|
||||
PRBool allowPipelining,
|
||||
|
|
|
@ -49,8 +49,10 @@
|
|||
#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 {
|
||||
|
@ -195,56 +197,109 @@ struct ParamTraits<nsHttpResponseHead>
|
|||
}
|
||||
};
|
||||
|
||||
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 (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 (isNull)
|
||||
return;
|
||||
|
||||
nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(aParam.mStream);
|
||||
bool isSerializable = !!serializable;
|
||||
WriteParam(aMsg, isSerializable);
|
||||
|
||||
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;
|
||||
|
||||
nsresult rv;
|
||||
if (isNull) {
|
||||
aResult->mStream = nsnull;
|
||||
return true;
|
||||
}
|
||||
|
||||
nsCOMPtr<nsIStringInputStream> stream
|
||||
(do_CreateInstance("@mozilla.org/io/string-input-stream;1", &rv));
|
||||
if (NS_FAILED(rv))
|
||||
bool isSerializable;
|
||||
if (!ReadParam(aMsg, aIter, &isSerializable))
|
||||
return false;
|
||||
|
||||
rv = stream->SetData(value.get(), value.Length());
|
||||
if (NS_FAILED(rv))
|
||||
return false;
|
||||
nsCOMPtr<nsIInputStream> stream;
|
||||
if (!isSerializable) {
|
||||
nsCString streamString;
|
||||
if (!ReadParam(aMsg, aIter, &streamString))
|
||||
return false;
|
||||
|
||||
stream.forget(aResult);
|
||||
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;
|
||||
|
||||
stream = do_CreateInstance(cid);
|
||||
if (!stream)
|
||||
return false;
|
||||
nsCOMPtr<nsIIPCSerializable> serializable = do_QueryInterface(stream);
|
||||
if (!serializable || !serializable->Read(aMsg, aIter))
|
||||
return false;
|
||||
}
|
||||
|
||||
stream.swap(aResult->mStream);
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace IPC
|
||||
|
||||
#endif // mozilla_net_PHttpChannelParams_h
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
//
|
||||
// POST test
|
||||
//
|
||||
|
||||
do_load_httpd_js();
|
||||
|
||||
var httpserver = new nsHttpServer();
|
||||
var testpath = "/simple";
|
||||
|
||||
var testfile = getFile("XpcomLib");
|
||||
|
||||
const BOUNDARY = "AaB03x";
|
||||
var teststring1 = "--" + BOUNDARY + "\r\n"
|
||||
+ "Content-Disposition: form-data; name=\"body\"\r\n\r\n"
|
||||
+ "0123456789\r\n"
|
||||
+ "--" + BOUNDARY + "\r\n"
|
||||
+ "Content-Disposition: form-data; name=\"files\"; filename=\"" + testfile.leafName + "\"\r\n"
|
||||
+ "Content-Type: application/octet-stream\r\n"
|
||||
+ "Content-Length: " + testfile.fileSize + "\r\n\r\n";
|
||||
var teststring2 = "--" + BOUNDARY + "--\r\n";
|
||||
|
||||
const BUFFERSIZE = 4096;
|
||||
|
||||
function run_test() {
|
||||
var sstream1 = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
sstream1.data = teststring1;
|
||||
|
||||
var fstream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
fstream.init(testfile, -1, -1, 0);
|
||||
|
||||
var buffered = Cc["@mozilla.org/network/buffered-input-stream;1"].
|
||||
createInstance(Ci.nsIBufferedInputStream);
|
||||
buffered.init(fstream, BUFFERSIZE);
|
||||
|
||||
var sstream2 = Cc["@mozilla.org/io/string-input-stream;1"].
|
||||
createInstance(Ci.nsIStringInputStream);
|
||||
sstream2.data = teststring2;
|
||||
|
||||
var multi = Cc["@mozilla.org/io/multiplex-input-stream;1"].
|
||||
createInstance(Ci.nsIMultiplexInputStream);
|
||||
multi.appendStream(sstream1);
|
||||
multi.appendStream(buffered);
|
||||
multi.appendStream(sstream2);
|
||||
|
||||
var mime = Cc["@mozilla.org/network/mime-input-stream;1"].
|
||||
createInstance(Ci.nsIMIMEInputStream);
|
||||
mime.addHeader("Content-Type", "multipart/form-data; boundary="+BOUNDARY);
|
||||
mime.setData(multi);
|
||||
mime.addContentLength = true;
|
||||
|
||||
httpserver.registerPathHandler(testpath, serverHandler);
|
||||
httpserver.start(4444);
|
||||
|
||||
var channel = setupChannel(testpath);
|
||||
|
||||
channel.QueryInterface(Ci.nsIUploadChannel)
|
||||
.setUploadStream(mime, "", mime.available());
|
||||
channel.requestMethod = "POST";
|
||||
|
||||
channel.asyncOpen(new ChannelListener(checkRequest, channel), null);
|
||||
|
||||
do_test_pending();
|
||||
}
|
||||
|
||||
function setupChannel(path) {
|
||||
var ios = Cc["@mozilla.org/network/io-service;1"].getService(Ci.nsIIOService);
|
||||
return chan = ios.newChannel("http://localhost:4444" + path, "", null)
|
||||
.QueryInterface(Ci.nsIHttpChannel);
|
||||
}
|
||||
|
||||
function serverHandler(metadata, response) {
|
||||
do_check_eq(metadata.method, "POST");
|
||||
|
||||
var data = read_stream(metadata.bodyInputStream,
|
||||
metadata.bodyInputStream.available());
|
||||
|
||||
var testfile_stream = Cc["@mozilla.org/network/file-input-stream;1"].
|
||||
createInstance(Ci.nsIFileInputStream);
|
||||
testfile_stream.init(testfile, -1, -1, 0);
|
||||
|
||||
do_check_eq(teststring1 +
|
||||
read_stream(testfile_stream, testfile_stream.available()) +
|
||||
teststring2,
|
||||
data);
|
||||
}
|
||||
|
||||
function checkRequest(request, data, context) {
|
||||
httpserver.stop(do_test_finished);
|
||||
}
|
||||
|
||||
function getFile(key) {
|
||||
var dirSvc = Components.classes["@mozilla.org/file/directory_service;1"]
|
||||
.getService(Components.interfaces.nsIProperties);
|
||||
return dirSvc.get(key, Components.interfaces.nsILocalFile);
|
||||
}
|
|
@ -0,0 +1,3 @@
|
|||
function run_test() {
|
||||
run_test_in_child("../unit/test_post.js");
|
||||
}
|
|
@ -187,6 +187,7 @@ FORCE_STATIC_LIB = 1
|
|||
FORCE_USE_PIC = 1
|
||||
|
||||
include $(topsrcdir)/config/rules.mk
|
||||
include $(topsrcdir)/ipc/chromium/chromium-config.mk
|
||||
|
||||
DEFINES += -D_IMPL_NS_COM
|
||||
|
||||
|
@ -196,7 +197,7 @@ DEFINES += -DHAVE_USR_LIB64_DIR
|
|||
endif
|
||||
endif
|
||||
|
||||
LOCAL_INCLUDES = -I..
|
||||
LOCAL_INCLUDES += -I..
|
||||
|
||||
ifeq ($(MOZ_PLATFORM_MAEMO),5)
|
||||
CFLAGS += $(MOZ_DBUS_CFLAGS)
|
||||
|
|
|
@ -41,15 +41,23 @@
|
|||
* 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();
|
||||
|
@ -58,6 +66,7 @@ public:
|
|||
NS_DECL_NSIINPUTSTREAM
|
||||
NS_DECL_NSIMULTIPLEXINPUTSTREAM
|
||||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSIIPCSERIALIZABLE
|
||||
|
||||
private:
|
||||
~nsMultiplexInputStream() {}
|
||||
|
@ -80,11 +89,22 @@ private:
|
|||
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),
|
||||
|
@ -408,3 +428,55 @@ nsMultiplexInputStreamConstructor(nsISupports *outer,
|
|||
|
||||
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
|
||||
}
|
||||
|
|
|
@ -52,6 +52,10 @@
|
|||
* Based on original code from nsIStringStream.cpp
|
||||
*/
|
||||
|
||||
#ifdef MOZ_IPC
|
||||
#include "IPC/IPCMessageUtils.h"
|
||||
#endif
|
||||
|
||||
#include "nsStringStream.h"
|
||||
#include "nsStreamUtils.h"
|
||||
#include "nsReadableUtils.h"
|
||||
|
@ -62,6 +66,7 @@
|
|||
#include "prerror.h"
|
||||
#include "plstr.h"
|
||||
#include "nsIClassInfoImpl.h"
|
||||
#include "nsIIPCSerializable.h"
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// nsIStringInputStream implementation
|
||||
|
@ -70,6 +75,7 @@
|
|||
class nsStringInputStream : public nsIStringInputStream
|
||||
, public nsISeekableStream
|
||||
, public nsISupportsCString
|
||||
, public nsIIPCSerializable
|
||||
{
|
||||
public:
|
||||
NS_DECL_ISUPPORTS
|
||||
|
@ -78,6 +84,7 @@ public:
|
|||
NS_DECL_NSISEEKABLESTREAM
|
||||
NS_DECL_NSISUPPORTSPRIMITIVE
|
||||
NS_DECL_NSISUPPORTSCSTRING
|
||||
NS_DECL_NSIIPCSERIALIZABLE
|
||||
|
||||
nsStringInputStream()
|
||||
: mData(nsnull)
|
||||
|
@ -121,16 +128,18 @@ 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
|
||||
|
@ -349,6 +358,44 @@ nsStringInputStream::SetEOF()
|
|||
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,
|
||||
|
|
Загрузка…
Ссылка в новой задаче