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:
Jae-Seong Lee-Russo 2010-10-19 17:24:52 -07:00
Родитель 6c1ea3e5dc
Коммит b33b8c353d
16 изменённых файлов: 559 добавлений и 115 удалений

Просмотреть файл

@ -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,