diff --git a/content/base/src/nsDOMFile.cpp b/content/base/src/nsDOMFile.cpp index 686255190c62..0de4253a84b9 100644 --- a/content/base/src/nsDOMFile.cpp +++ b/content/base/src/nsDOMFile.cpp @@ -17,7 +17,8 @@ #include "nsIDocument.h" #include "nsIFileStreams.h" #include "nsIInputStream.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableInputStream.h" +#include "nsIIPCSerializableObsolete.h" #include "nsIMIMEService.h" #include "nsIPlatformCharset.h" #include "nsISeekableStream.h" @@ -47,8 +48,9 @@ using namespace mozilla::dom; // stream is. We do that by passing back this class instead. class DataOwnerAdapter MOZ_FINAL : public nsIInputStream, public nsISeekableStream, - public nsIIPCSerializable, - public nsIClassInfo + public nsIIPCSerializableObsolete, + public nsIClassInfo, + public nsIIPCSerializableInputStream { typedef nsDOMMemoryFile::DataOwner DataOwner; public: @@ -65,16 +67,18 @@ public: // These are optional. We use a conditional QI to keep them from being called // if the underlying stream doesn't QI to either interface. - NS_FORWARD_NSIIPCSERIALIZABLE(mSerializable->) + NS_FORWARD_NSIIPCSERIALIZABLEOBSOLETE(mSerializableObsolete->) NS_FORWARD_NSICLASSINFO(mClassInfo->) + NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(mSerializableInputStream->) private: DataOwnerAdapter(DataOwner* aDataOwner, nsIInputStream* aStream) : mDataOwner(aDataOwner), mStream(aStream), mSeekableStream(do_QueryInterface(aStream)), - mSerializable(do_QueryInterface(aStream)), - mClassInfo(do_QueryInterface(aStream)) + mSerializableObsolete(do_QueryInterface(aStream)), + mClassInfo(do_QueryInterface(aStream)), + mSerializableInputStream(do_QueryInterface(aStream)) { NS_ASSERTION(mSeekableStream, "Somebody gave us the wrong stream!"); } @@ -82,8 +86,9 @@ private: nsRefPtr mDataOwner; nsCOMPtr mStream; nsCOMPtr mSeekableStream; - nsCOMPtr mSerializable; + nsCOMPtr mSerializableObsolete; nsCOMPtr mClassInfo; + nsCOMPtr mSerializableInputStream; }; NS_IMPL_THREADSAFE_ADDREF(DataOwnerAdapter) @@ -92,8 +97,11 @@ NS_IMPL_THREADSAFE_RELEASE(DataOwnerAdapter) NS_INTERFACE_MAP_BEGIN(DataOwnerAdapter) NS_INTERFACE_MAP_ENTRY(nsIInputStream) NS_INTERFACE_MAP_ENTRY(nsISeekableStream) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializable, mSerializable) + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableObsolete, + mSerializableObsolete) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIClassInfo, mClassInfo) + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream, + mSerializableInputStream) NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) NS_INTERFACE_MAP_END diff --git a/docshell/base/SerializedLoadContext.h b/docshell/base/SerializedLoadContext.h index c2ae9e8923ac..8fdd8c391bb3 100644 --- a/docshell/base/SerializedLoadContext.h +++ b/docshell/base/SerializedLoadContext.h @@ -9,7 +9,6 @@ #include "base/basictypes.h" #include "IPC/IPCMessageUtils.h" -#include "nsIIPCSerializable.h" #include "nsILoadContext.h" /* diff --git a/dom/ipc/Blob.cpp b/dom/ipc/Blob.cpp index a50044ecac4a..c1ac012574f4 100644 --- a/dom/ipc/Blob.cpp +++ b/dom/ipc/Blob.cpp @@ -10,13 +10,14 @@ #include "nsIDOMFile.h" #include "nsIInputStream.h" +#include "nsIIPCSerializableInputStream.h" #include "nsIRemoteBlob.h" #include "nsISeekableStream.h" #include "mozilla/Assertions.h" #include "mozilla/Monitor.h" #include "mozilla/unused.h" -#include "mozilla/net/NeckoMessageUtils.h" +#include "mozilla/ipc/InputStreamUtils.h" #include "nsDOMFile.h" #include "nsThreadUtils.h" @@ -25,6 +26,7 @@ using namespace mozilla::dom; using namespace mozilla::dom::ipc; +using namespace mozilla::ipc; namespace { @@ -227,10 +229,18 @@ private: } }; +NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream) +NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream) + +NS_INTERFACE_MAP_BEGIN(RemoteInputStream) + NS_INTERFACE_MAP_ENTRY(nsIInputStream) + NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream()) + NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) +NS_INTERFACE_MAP_END + template class InputStreamActor : public BlobTraits::StreamType { - typedef typename BlobTraits::StreamType::InputStream InputStream; nsRefPtr mRemoteStream; public: @@ -249,12 +259,17 @@ public: private: // This method is only called by the IPDL message machinery. virtual bool - Recv__delete__(const InputStream& aStream) MOZ_OVERRIDE + Recv__delete__(const InputStreamParams& aParams) MOZ_OVERRIDE { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mRemoteStream); - mRemoteStream->SetStream(aStream); + nsCOMPtr stream = DeserializeInputStream(aParams); + if (!stream) { + return false; + } + + mRemoteStream->SetStream(stream); return true; } }; @@ -605,14 +620,10 @@ public: virtual void* GetPBlob() MOZ_OVERRIDE { - return static_cast(mActor); + return static_cast(mActor); } }; -} // namespace ipc -} // namespace dom -} // namespace mozilla - template Blob::Blob(nsIDOMBlob* aBlob) : mBlob(aBlob), mRemoteBlob(nullptr), mOwnsBlob(true), mBlobIsFile(false) @@ -740,7 +751,7 @@ Blob::SetMysteryBlobInfo(const nsString& aName, ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength); FileBlobConstructorParams params(aName, aContentType, aLength); - return BaseType::SendResolveMystery(params); + return ProtocolType::SendResolveMystery(params); } template @@ -759,7 +770,7 @@ Blob::SetMysteryBlobInfo(const nsString& aContentType, ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength); NormalBlobConstructorParams params(aContentType, aLength); - return BaseType::SendResolveMystery(params); + return ProtocolType::SendResolveMystery(params); } template @@ -809,7 +820,7 @@ Blob::NoteDyingRemoteBlob() // access a dangling pointer. mRemoteBlob = nullptr; - mozilla::unused << BaseType::Send__delete__(this); + mozilla::unused << ProtocolType::Send__delete__(this); } template @@ -868,9 +879,9 @@ Blob::RecvResolveMystery(const ResolveMysteryParams& aParams) return true; } -template +template <> bool -Blob::RecvPBlobStreamConstructor(StreamType* aActor) +Blob::RecvPBlobStreamConstructor(StreamType* aActor) { MOZ_ASSERT(NS_IsMainThread()); MOZ_ASSERT(mBlob); @@ -880,7 +891,55 @@ Blob::RecvPBlobStreamConstructor(StreamType* aActor) nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream)); NS_ENSURE_SUCCESS(rv, false); - return aActor->Send__delete__(aActor, stream.get()); + nsCOMPtr serializable = + do_QueryInterface(stream); + if (!serializable) { + MOZ_ASSERT(false, "Must be serializable!"); + return false; + } + + nsCOMPtr target = + do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); + NS_ENSURE_TRUE(target, false); + + nsRefPtr runnable = + new BaseType::OpenStreamRunnable(this, aActor, stream, serializable, + target); + + rv = target->Dispatch(runnable, NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, false); + + nsRevocableEventPtr* arrayMember = + mOpenStreamRunnables.AppendElement(); + *arrayMember = runnable; + return true; +} + +template <> +bool +Blob::RecvPBlobStreamConstructor(StreamType* aActor) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(mBlob); + MOZ_ASSERT(!mRemoteBlob); + + nsCOMPtr stream; + nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream)); + NS_ENSURE_SUCCESS(rv, false); + + nsCOMPtr serializable = + do_QueryInterface(stream); + if (!serializable) { + MOZ_ASSERT(false, "Must be serializable!"); + return false; + } + + InputStreamParams params; + serializable->Serialize(params); + + MOZ_ASSERT(params.type() != InputStreamParams::T__None); + + return aActor->Send__delete__(aActor, params); } template @@ -910,18 +969,127 @@ template NS_IMPL_QUERY_INTERFACE_INHERITED1(RemoteBlob, nsDOMFile, nsIRemoteBlob) -NS_IMPL_THREADSAFE_ADDREF(RemoteInputStream) -NS_IMPL_THREADSAFE_RELEASE(RemoteInputStream) +void +BlobTraits::BaseType::NoteRunnableCompleted( + BlobTraits::BaseType::OpenStreamRunnable* aRunnable) +{ + MOZ_ASSERT(NS_IsMainThread()); -NS_INTERFACE_MAP_BEGIN(RemoteInputStream) - NS_INTERFACE_MAP_ENTRY(nsIInputStream) - NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream()) - NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) -NS_INTERFACE_MAP_END + for (PRUint32 index = 0; index < mOpenStreamRunnables.Length(); index++) { + nsRevocableEventPtr& runnable = + mOpenStreamRunnables[index]; -namespace mozilla { -namespace dom { -namespace ipc { + if (runnable.get() == aRunnable) { + runnable.Forget(); + mOpenStreamRunnables.RemoveElementAt(index); + return; + } + } + + MOZ_NOT_REACHED("Runnable not in our array!"); +} + +BlobTraits::BaseType:: +OpenStreamRunnable::OpenStreamRunnable( + BlobTraits::BaseType* aOwner, + BlobTraits::StreamType* aActor, + nsIInputStream* aStream, + nsIIPCSerializableInputStream* aSerializable, + nsIEventTarget* aTarget) +: mOwner(aOwner), mActor(aActor), mStream(aStream), + mSerializable(aSerializable), mTarget(aTarget), mRevoked(false), + mClosing(false) +{ + MOZ_ASSERT(NS_IsMainThread()); + MOZ_ASSERT(aOwner); + MOZ_ASSERT(aActor); + MOZ_ASSERT(aStream); + MOZ_ASSERT(aSerializable); + MOZ_ASSERT(aTarget); +} + +NS_IMETHODIMP +BlobTraits::BaseType::OpenStreamRunnable::Run() +{ + MOZ_ASSERT(mStream); + + nsresult rv; + + if (NS_IsMainThread()) { + MOZ_ASSERT(mTarget); + MOZ_ASSERT(!mClosing); + + if (mRevoked) { + MOZ_ASSERT(!mOwner); + MOZ_ASSERT(!mActor); + } + else { + MOZ_ASSERT(mOwner); + MOZ_ASSERT(mActor); + + nsCOMPtr serializable; + mSerializable.swap(serializable); + + InputStreamParams params; + serializable->Serialize(params); + + MOZ_ASSERT(params.type() != InputStreamParams::T__None); + + unused << mActor->Send__delete__(mActor, params); + + mOwner->NoteRunnableCompleted(this); + +#ifdef DEBUG + mOwner = nullptr; + mActor = nullptr; +#endif + } + + mClosing = true; + + nsCOMPtr target; + mTarget.swap(target); + + rv = target->Dispatch(this, NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + if (!mClosing) { + // To force the stream open we call Available(). We don't actually care how + // much data is available. + PRUint64 available; + if (NS_FAILED(mStream->Available(&available))) { + NS_WARNING("Available failed on this stream!"); + } + + rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; + } + + // Going to always release here. + nsCOMPtr stream; + mStream.swap(stream); + + rv = stream->Close(); + NS_ENSURE_SUCCESS(rv, rv); + + return NS_OK; +} + +#ifdef DEBUG +void +BlobTraits::BaseType::OpenStreamRunnable::Revoke() +{ + MOZ_ASSERT(NS_IsMainThread()); + mOwner = nullptr; + mActor = nullptr; + mRevoked = true; +} +#endif // Explicit instantiation of both classes. template class Blob; diff --git a/dom/ipc/Blob.h b/dom/ipc/Blob.h index 08e9f7419c8d..65f66e26b009 100644 --- a/dom/ipc/Blob.h +++ b/dom/ipc/Blob.h @@ -12,12 +12,16 @@ #include "mozilla/dom/PBlobParent.h" #include "mozilla/dom/PBlobStreamChild.h" #include "mozilla/dom/PBlobStreamParent.h" -#include "mozilla/dom/PContentChild.h" -#include "mozilla/dom/PContentParent.h" +#include "mozilla/dom/PContent.h" + #include "nsAutoPtr.h" #include "nsCOMPtr.h" +#include "nsTArray.h" +#include "nsThreadUtils.h" class nsIDOMBlob; +class nsIIPCSerializableInputStream; +class nsIInputStream; namespace mozilla { namespace dom { @@ -36,17 +40,92 @@ struct BlobTraits template <> struct BlobTraits { - typedef mozilla::dom::PBlobParent BaseType; + typedef mozilla::dom::PBlobParent ProtocolType; typedef mozilla::dom::PBlobStreamParent StreamType; - typedef mozilla::dom::PContentParent ManagerType; + + // BaseType on the parent side is a bit more complicated than for the child + // side. In the case of nsIInputStreams backed by files we need to ensure that + // the files are actually opened and closed on a background thread before we + // can send their file handles across to the child. The child process could + // crash during this process so we need to make sure we cancel the intended + // response in such a case. We do that by holding an array of + // nsRevocableEventPtr. If the child crashes then this actor will be destroyed + // and the nsRevocableEventPtr destructor will cancel any stream events that + // are currently in flight. + class BaseType : public ProtocolType + { + protected: + BaseType() + { } + + virtual ~BaseType() + { } + + // Each instance of this class will be dispatched to the network stream + // thread pool to run the first time where it will open the file input + // stream. It will then dispatch itself back to the main thread to send the + // child process its response (assuming that the child has not crashed). The + // runnable will then dispatch itself to the thread pool again in order to + // close the file input stream. + class OpenStreamRunnable : public nsRunnable + { + friend class nsRevocableEventPtr; + public: + NS_DECL_NSIRUNNABLE + + OpenStreamRunnable(BaseType* aOwner, StreamType* aActor, + nsIInputStream* aStream, + nsIIPCSerializableInputStream* aSerializable, + nsIEventTarget* aTarget); + + private: +#ifdef DEBUG + void + Revoke(); +#else + void + Revoke() + { + mRevoked = true; + } +#endif + + // Only safe to access these two pointers if mRevoked is false! + BaseType* mOwner; + StreamType* mActor; + + nsCOMPtr mStream; + nsCOMPtr mSerializable; + nsCOMPtr mTarget; + + bool mRevoked; + bool mClosing; + }; + + friend class OpenStreamRunnable; + + void + NoteRunnableCompleted(OpenStreamRunnable* aRunnable); + + nsTArray > mOpenStreamRunnables; + }; }; template <> struct BlobTraits { - typedef mozilla::dom::PBlobChild BaseType; + typedef mozilla::dom::PBlobChild ProtocolType; typedef mozilla::dom::PBlobStreamChild StreamType; - typedef mozilla::dom::PContentChild ManagerType; + + class BaseType : public ProtocolType + { + protected: + BaseType() + { } + + virtual ~BaseType() + { } + }; }; template @@ -58,9 +137,9 @@ class Blob : public BlobTraits::BaseType friend class RemoteBlob; public: - typedef typename BlobTraits::BaseType BaseType; + typedef typename BlobTraits::ProtocolType ProtocolType; typedef typename BlobTraits::StreamType StreamType; - typedef typename BlobTraits::ManagerType ManagerType; + typedef typename BlobTraits::BaseType BaseType; typedef RemoteBlob RemoteBlobType; typedef mozilla::ipc::IProtocolManager< mozilla::ipc::RPCChannel::RPCListener>::ActorDestroyReason diff --git a/dom/ipc/PBlobStream.ipdl b/dom/ipc/PBlobStream.ipdl index 45be1cc0102f..aac11a1eabf2 100644 --- a/dom/ipc/PBlobStream.ipdl +++ b/dom/ipc/PBlobStream.ipdl @@ -3,10 +3,7 @@ * You can obtain one at http://mozilla.org/MPL/2.0/. */ include protocol PBlob; - -include "mozilla/net/NeckoMessageUtils.h"; - -using IPC::InputStream; +include IPCSerializableParams; namespace mozilla { namespace dom { @@ -16,7 +13,7 @@ protocol PBlobStream manager PBlob; both: - __delete__(InputStream stream); + __delete__(InputStreamParams params); }; } // namespace dom diff --git a/dom/plugins/ipc/PPluginModule.ipdl b/dom/plugins/ipc/PPluginModule.ipdl index f6c388ca08ef..5f2b837458ee 100644 --- a/dom/plugins/ipc/PPluginModule.ipdl +++ b/dom/plugins/ipc/PPluginModule.ipdl @@ -14,7 +14,6 @@ include "mozilla/dom/TabMessageUtils.h"; using NPError; using NPNVariable; -using base::FileDescriptor; using mozilla::dom::NativeThreadId; using mac_plugin_interposing::NSCursorInfo; using nsID; diff --git a/dom/plugins/ipc/PluginModuleChild.cpp b/dom/plugins/ipc/PluginModuleChild.cpp index 8ea5a3c106fd..52b027a77ce0 100644 --- a/dom/plugins/ipc/PluginModuleChild.cpp +++ b/dom/plugins/ipc/PluginModuleChild.cpp @@ -1850,10 +1850,10 @@ PluginModuleChild::AnswerNP_Initialize(const uint32_t& aFlags, NPError* _retval) #endif #ifdef MOZ_X11 - // Send the parent a dup of our X socket, to act as a proxy - // reference for our X resources + // Send the parent our X socket to act as a proxy reference for our X + // resources. int xSocketFd = ConnectionNumber(DefaultXDisplay()); - SendBackUpXResources(FileDescriptor(xSocketFd, false/*don't close*/)); + SendBackUpXResources(FileDescriptor(xSocketFd)); #endif #if defined(OS_LINUX) diff --git a/dom/plugins/ipc/PluginModuleParent.cpp b/dom/plugins/ipc/PluginModuleParent.cpp index 994602bd9cc2..0233b7857294 100644 --- a/dom/plugins/ipc/PluginModuleParent.cpp +++ b/dom/plugins/ipc/PluginModuleParent.cpp @@ -689,9 +689,8 @@ PluginModuleParent::RecvBackUpXResources(const FileDescriptor& aXSocketFd) #else NS_ABORT_IF_FALSE(0 > mPluginXSocketFdDup.get(), "Already backed up X resources??"); - int fd = aXSocketFd.fd; // Copy to discard |const| qualifier mPluginXSocketFdDup.forget(); - mPluginXSocketFdDup.reset(fd); + mPluginXSocketFdDup.reset(aXSocketFd.PlatformHandle()); #endif return true; } diff --git a/ipc/glue/FileDescriptor.cpp b/ipc/glue/FileDescriptor.cpp new file mode 100644 index 000000000000..78c3c545836c --- /dev/null +++ b/ipc/glue/FileDescriptor.cpp @@ -0,0 +1,65 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "FileDescriptor.h" + +#include "mozilla/Assertions.h" +#include "nsDebug.h" + +#ifdef XP_WIN +#include +#define INVALID_HANDLE INVALID_HANDLE_VALUE +#else +#include +#define INVALID_HANDLE -1 +#endif + +using mozilla::ipc::FileDescriptor; + +FileDescriptor::FileDescriptor() +: mHandle(INVALID_HANDLE) +{ } + +FileDescriptor::PickleType +FileDescriptor::ShareTo(const FileDescriptor::IPDLPrivate&, + FileDescriptor::ProcessHandle aOtherProcess) const +{ +#ifdef XP_WIN + if (mHandle == INVALID_HANDLE) { + return INVALID_HANDLE; + } + + PlatformHandleType newHandle; + if (!DuplicateHandle(GetCurrentProcess(), mHandle, aOtherProcess, &newHandle, + 0, FALSE, DUPLICATE_SAME_ACCESS)) { + NS_WARNING("Failed to duplicate file handle!"); + return INVALID_HANDLE; + } + + return newHandle; +#else // XP_WIN + if (mHandle == INVALID_HANDLE) { + return base::FileDescriptor(); + } + + PlatformHandleType newHandle = dup(mHandle); + if (newHandle < 0) { + NS_WARNING("Failed to duplicate file descriptor!"); + return base::FileDescriptor(); + } + + // This file descriptor must be closed once the caller is done using it, so + // pass true here for the 'auto_close' argument. + return base::FileDescriptor(newHandle, true); +#endif + + MOZ_NOT_REACHED("Must not get here!"); + return PickleType(); +} + +bool +FileDescriptor::IsValid() const +{ + return mHandle != INVALID_HANDLE; +} diff --git a/ipc/glue/FileDescriptor.h b/ipc/glue/FileDescriptor.h new file mode 100644 index 000000000000..26f8ad1df537 --- /dev/null +++ b/ipc/glue/FileDescriptor.h @@ -0,0 +1,95 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_FileDescriptor_h +#define mozilla_ipc_FileDescriptor_h + +#include "base/basictypes.h" +#include "base/process.h" +#include "nscore.h" + +#ifdef XP_WIN +// Need the HANDLE typedef. +#include +#else +#include "base/file_descriptor_posix.h" +#endif + +namespace mozilla { +namespace ipc { + +// This class is used by IPDL to share file descriptors across processes. When +// sending a FileDescriptor IPDL will first duplicate a platform-specific file +// handle type ('PlatformHandleType') into a handle that is valid in the other +// process. Then IPDL will convert the duplicated handle into a type suitable +// for pickling ('PickleType') and then send that through the IPC pipe. In the +// receiving process the pickled data is converted into a platform-specific file +// handle and then returned to the receiver. +// +// To use this class add 'FileDescriptor' as an argument in the IPDL protocol +// and then pass a file descriptor from C++ to the Call/Send method. The +// Answer/Recv method will receive a FileDescriptor& on which PlatformHandle() +// can be called to return the platform file handle. +class FileDescriptor +{ +public: + typedef base::ProcessHandle ProcessHandle; + +#ifdef XP_WIN + typedef HANDLE PlatformHandleType; + typedef HANDLE PickleType; +#else + typedef int PlatformHandleType; + typedef base::FileDescriptor PickleType; +#endif + + // This should only ever be created by IPDL. + struct IPDLPrivate + {}; + + FileDescriptor(); + + FileDescriptor(PlatformHandleType aHandle) + : mHandle(aHandle) + { } + + FileDescriptor(const IPDLPrivate&, const PickleType& aPickle) +#ifdef XP_WIN + : mHandle(aPickle) +#else + : mHandle(aPickle.fd) +#endif + { } + + // Performs platform-specific actions to duplicate mHandle in the other + // process (e.g. dup() on POSIX, DuplicateHandle() on Windows). Returns a + // pickled value that can be passed to the other process via IPC. + PickleType + ShareTo(const IPDLPrivate&, ProcessHandle aOtherProcess) const; + + // Tests mHandle against a well-known invalid platform-specific file handle + // (e.g. -1 on POSIX, INVALID_HANDLE_VALUE on Windows). + bool + IsValid() const; + + PlatformHandleType + PlatformHandle() const + { + return mHandle; + } + + bool + operator==(const FileDescriptor& aOther) const + { + return mHandle == aOther.mHandle; + } + +private: + PlatformHandleType mHandle; +}; + +} // namespace ipc +} // namespace mozilla + +#endif // mozilla_ipc_FileDescriptor_h diff --git a/ipc/glue/IPCSerializableParams.ipdlh b/ipc/glue/IPCSerializableParams.ipdlh new file mode 100644 index 000000000000..21acd68508de --- /dev/null +++ b/ipc/glue/IPCSerializableParams.ipdlh @@ -0,0 +1,44 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +namespace mozilla { +namespace ipc { + +struct StringInputStreamParams +{ + nsCString data; +}; + +struct FileInputStreamParams +{ + FileDescriptor file; + int32_t behaviorFlags; + int32_t ioFlags; +}; + +struct PartialFileInputStreamParams +{ + FileInputStreamParams fileStreamParams; + uint64_t begin; + uint64_t length; +}; + +struct MultiplexInputStreamParams +{ + InputStreamParams[] streams; + uint32_t currentStream; + nsresult status; + bool startedReadingCurrent; +}; + +union InputStreamParams +{ + StringInputStreamParams; + FileInputStreamParams; + PartialFileInputStreamParams; + MultiplexInputStreamParams; +}; + +} // namespace ipc +} // namespace mozilla diff --git a/ipc/glue/InputStreamUtils.cpp b/ipc/glue/InputStreamUtils.cpp new file mode 100644 index 000000000000..533326210bb8 --- /dev/null +++ b/ipc/glue/InputStreamUtils.cpp @@ -0,0 +1,79 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#include "InputStreamUtils.h" + +#include "nsIIPCSerializableInputStream.h" + +#include "mozilla/Assertions.h" +#include "nsComponentManagerUtils.h" +#include "nsDebug.h" +#include "nsID.h" +#include "nsMultiplexInputStream.h" +#include "nsNetCID.h" +#include "nsStringStream.h" +#include "nsThreadUtils.h" + +using namespace mozilla::ipc; + +namespace { + +NS_DEFINE_CID(kStringInputStreamCID, NS_STRINGINPUTSTREAM_CID); +NS_DEFINE_CID(kFileInputStreamCID, NS_LOCALFILEINPUTSTREAM_CID); +NS_DEFINE_CID(kPartialFileInputStreamCID, NS_PARTIALLOCALFILEINPUTSTREAM_CID); +NS_DEFINE_CID(kMultiplexInputStreamCID, NS_MULTIPLEXINPUTSTREAM_CID); + +} // anonymous namespace + +namespace mozilla { +namespace ipc { + +already_AddRefed +DeserializeInputStream(const InputStreamParams& aParams) +{ + MOZ_ASSERT(NS_IsMainThread()); + + nsCOMPtr serializable; + + switch (aParams.type()) { + case InputStreamParams::T__None: + NS_WARNING("This union has no type!"); + return nullptr; + + case InputStreamParams::TStringInputStreamParams: + serializable = do_CreateInstance(kStringInputStreamCID); + break; + + case InputStreamParams::TFileInputStreamParams: + serializable = do_CreateInstance(kFileInputStreamCID); + break; + + case InputStreamParams::TPartialFileInputStreamParams: + serializable = do_CreateInstance(kPartialFileInputStreamCID); + break; + + case InputStreamParams::TMultiplexInputStreamParams: + serializable = do_CreateInstance(kMultiplexInputStreamCID); + break; + + default: + NS_WARNING("Unknown params!"); + return nullptr; + } + + MOZ_ASSERT(serializable); + + if (!serializable->Deserialize(aParams)) { + NS_WARNING("Deserialize failed!"); + return nullptr; + } + + nsCOMPtr stream = do_QueryInterface(serializable); + MOZ_ASSERT(stream); + + return stream.forget(); +} + +} // namespace ipc +} // namespace mozilla diff --git a/ipc/glue/InputStreamUtils.h b/ipc/glue/InputStreamUtils.h new file mode 100644 index 000000000000..362488cf5894 --- /dev/null +++ b/ipc/glue/InputStreamUtils.h @@ -0,0 +1,21 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_InputStreamUtils_h +#define mozilla_ipc_InputStreamUtils_h + +#include "mozilla/ipc/IPCSerializableParams.h" +#include "nsCOMPtr.h" +#include "nsIInputStream.h" + +namespace mozilla { +namespace ipc { + +already_AddRefed +DeserializeInputStream(const InputStreamParams& aParams); + +} // namespace ipc +} // namespace mozilla + +#endif // mozilla_ipc_InputStreamUtils_h diff --git a/ipc/glue/Makefile.in b/ipc/glue/Makefile.in index 77bec25bcc67..467bf4f85e62 100644 --- a/ipc/glue/Makefile.in +++ b/ipc/glue/Makefile.in @@ -25,7 +25,9 @@ EXPORTS_mozilla/ipc = \ AsyncChannel.h \ BrowserProcessSubThread.h \ CrossProcessMutex.h \ + FileDescriptor.h \ GeckoChildProcessHost.h \ + InputStreamUtils.h \ IOThreadChild.h \ ProcessChild.h \ ProtocolUtils.h \ @@ -40,6 +42,8 @@ EXPORTS_mozilla/ipc = \ Transport.h \ $(NULL) +EXPORTS = nsIIPCSerializableInputStream.h + ifeq ($(OS_ARCH),WINNT) #{ EXPORTS_mozilla/ipc += \ Transport_win.h \ @@ -63,7 +67,9 @@ endif #} CPPSRCS += \ AsyncChannel.cpp \ BrowserProcessSubThread.cpp \ + FileDescriptor.cpp \ GeckoChildProcessHost.cpp \ + InputStreamUtils.cpp \ MessagePump.cpp \ ProcessChild.cpp \ ProtocolUtils.cpp \ diff --git a/ipc/glue/ProtocolUtils.h b/ipc/glue/ProtocolUtils.h index db4349789738..b5d2890d16e3 100644 --- a/ipc/glue/ProtocolUtils.h +++ b/ipc/glue/ProtocolUtils.h @@ -15,6 +15,7 @@ #include "prenv.h" #include "IPCMessageStart.h" +#include "mozilla/ipc/FileDescriptor.h" #include "mozilla/ipc/Shmem.h" #include "mozilla/ipc/Transport.h" diff --git a/ipc/glue/ipdl.mk b/ipc/glue/ipdl.mk new file mode 100644 index 000000000000..b2a320c7e60f --- /dev/null +++ b/ipc/glue/ipdl.mk @@ -0,0 +1,5 @@ +# This Source Code Form is subject to the terms of the Mozilla Public +# License, v. 2.0. If a copy of the MPL was not distributed with this +# file, You can obtain one at http://mozilla.org/MPL/2.0/. + +IPDLSRCS = IPCSerializableParams.ipdlh diff --git a/ipc/glue/nsIIPCSerializableInputStream.h b/ipc/glue/nsIIPCSerializableInputStream.h new file mode 100644 index 000000000000..2a770180a529 --- /dev/null +++ b/ipc/glue/nsIIPCSerializableInputStream.h @@ -0,0 +1,57 @@ +/* This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this file, + * You can obtain one at http://mozilla.org/MPL/2.0/. */ + +#ifndef mozilla_ipc_nsIIPCSerializableInputStream_h +#define mozilla_ipc_nsIIPCSerializableInputStream_h + +#include "nsISupports.h" +#include "mozilla/Attributes.h" + +namespace mozilla { +namespace ipc { +class InputStreamParams; +} +} + +#define NS_IIPCSERIALIZABLEINPUTSTREAM_IID \ + {0x1f56a3f8, 0xc413, 0x4274, {0x88, 0xe6, 0x68, 0x50, 0x9d, 0xf8, 0x85, 0x2d}} + +class NS_NO_VTABLE nsIIPCSerializableInputStream : public nsISupports +{ +public: + NS_DECLARE_STATIC_IID_ACCESSOR(NS_IIPCSERIALIZABLEINPUTSTREAM_IID) + + virtual void + Serialize(mozilla::ipc::InputStreamParams& aParams) = 0; + + virtual bool + Deserialize(const mozilla::ipc::InputStreamParams& aParams) = 0; +}; + +NS_DEFINE_STATIC_IID_ACCESSOR(nsIIPCSerializableInputStream, + NS_IIPCSERIALIZABLEINPUTSTREAM_IID) + +#define NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM \ + virtual void \ + Serialize(mozilla::ipc::InputStreamParams&) MOZ_OVERRIDE; \ + virtual bool \ + Deserialize(const mozilla::ipc::InputStreamParams&) MOZ_OVERRIDE; + +#define NS_FORWARD_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \ + virtual void \ + Serialize(mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \ + { _to Serialize(aParams); } \ + virtual bool \ + Deserialize(const mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \ + { return _to Deserialize(aParams); } + +#define NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(_to) \ + virtual void \ + Serialize(mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \ + { if (_to) { _to->Serialize(aParams); } } \ + virtual bool \ + Deserialize(const mozilla::ipc::InputStreamParams& aParams) MOZ_OVERRIDE \ + { if (_to) { return _to->Deserialize(aParams); } return false; } + +#endif // mozilla_ipc_nsIIPCSerializableInputStream_h diff --git a/ipc/ipdl/Makefile.in b/ipc/ipdl/Makefile.in index dc9032afa938..ff20ce584b02 100644 --- a/ipc/ipdl/Makefile.in +++ b/ipc/ipdl/Makefile.in @@ -32,6 +32,7 @@ IPDLDIRS = \ dom/src/storage \ gfx/layers/ipc \ hal/sandbox \ + ipc/glue \ ipc/testshell \ js/ipc \ layout/ipc \ diff --git a/ipc/ipdl/ipdl/builtin.py b/ipc/ipdl/ipdl/builtin.py index 4a600ce9486d..40ed00a7bd6f 100644 --- a/ipc/ipdl/ipdl/builtin.py +++ b/ipc/ipdl/ipdl/builtin.py @@ -48,6 +48,7 @@ Types = ( 'nsString', 'nsCString', 'mozilla::ipc::Shmem', + 'mozilla::ipc::FileDescriptor', # quasi-stdint types used by "public" Gecko headers 'int8', diff --git a/ipc/ipdl/ipdl/lower.py b/ipc/ipdl/ipdl/lower.py index 1fa87ec0fa17..f8f9e2b1d679 100644 --- a/ipc/ipdl/ipdl/lower.py +++ b/ipc/ipdl/ipdl/lower.py @@ -233,7 +233,6 @@ def _shmemRevokeRights(shmemexpr): def _lookupShmem(idexpr): return ExprCall(ExprVar('LookupSharedMemory'), args=[ idexpr ]) - def _makeForwardDeclForQClass(clsname, quals): fd = ForwardDecl(clsname, cls=1) if 0 == len(quals): @@ -492,6 +491,9 @@ class _ConvertToCxxType(TypeVisitor): def visitShmemType(self, s): return Type(self.typename(s)) + def visitFDType(self, s): + return Type(self.typename(s)) + def visitProtocolType(self, p): assert 0 def visitMessageType(self, m): assert 0 def visitVoidType(self, v): assert 0 @@ -668,6 +670,8 @@ class _StructField(_CompoundTypeComponent): refexpr = self.refExpr(thisexpr) if 'Shmem' == self.ipdltype.name(): refexpr = ExprCast(refexpr, Type('Shmem', ref=1), const=1) + if 'FileDescriptor' == self.ipdltype.name(): + refexpr = ExprCast(refexpr, Type('FileDescriptor', ref=1), const=1) return refexpr def argVar(self): @@ -826,6 +830,8 @@ IPDL union type.""" # sigh if 'Shmem' == self.ipdltype.name(): v = ExprCast(v, Type('Shmem', ref=1), const=1) + if 'FileDescriptor' == self.ipdltype.name(): + v = ExprCast(v, Type('FileDescriptor', ref=1), const=1) return v ##-------------------------------------------------- @@ -990,7 +996,6 @@ def _subtreeUsesShmem(p): return True return False - class Protocol(ipdl.ast.Protocol): def cxxTypedefs(self): return self.decl.cxxtypedefs @@ -1867,6 +1872,11 @@ stmt. Some types generate both kinds.''' self.visited.add(s) self.maybeTypedef('mozilla::ipc::Shmem', 'Shmem') + def visitFDType(self, s): + if s in self.visited: return + self.visited.add(s) + self.maybeTypedef('mozilla::ipc::FileDescriptor', 'FileDescriptor') + def visitVoidType(self, v): assert 0 def visitMessageType(self, v): assert 0 def visitProtocolType(self, v): assert 0 @@ -3379,11 +3389,11 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): p = self.protocol routedvar = ExprVar('aRouted') idvar = ExprVar('aId') - shmemvar = ExprVar('aShmem') + shmemvar = ExprVar('shmem') rawvar = ExprVar('segment') sizevar = ExprVar('aSize') - typevar = ExprVar('type') - unsafevar = ExprVar('unsafe') + typevar = ExprVar('aType') + unsafevar = ExprVar('aUnsafe') listenertype = Type('ChannelListener', ptr=1) register = MethodDefn(MethodDecl( @@ -3978,8 +3988,9 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): # pickling for IPDL types specialtypes = set() class findSpecialTypes(TypeVisitor): - def visitActorType(self, a): specialtypes.add(a) - def visitShmemType(self, s): specialtypes.add(s) + def visitActorType(self, a): specialtypes.add(a) + def visitShmemType(self, s): specialtypes.add(s) + def visitFDType(self, s): specialtypes.add(s) def visitStructType(self, s): specialtypes.add(s) return TypeVisitor.visitStructType(self, s) @@ -4006,6 +4017,7 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): if t.isActor(): self.implementActorPickling(t) elif t.isArray(): self.implementSpecialArrayPickling(t) elif t.isShmem(): self.implementShmemPickling(t) + elif t.isFD(): self.implementFDPickling(t) elif t.isStruct(): self.implementStructPickling(t) elif t.isUnion(): self.implementUnionPickling(t) else: @@ -4225,6 +4237,57 @@ class _GenerateProtocolActorCode(ipdl.ast.Visitor): self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ]) + def implementFDPickling(self, fdtype): + msgvar = self.msgvar + itervar = self.itervar + var = self.var + tmpvar = ExprVar('fd') + picklevar = ExprVar('pfd') + intype = _cxxConstRefType(fdtype, self.side) + outtype = _cxxPtrToType(fdtype, self.side) + + def _fdType(): + return Type('FileDescriptor') + + def _fdPickleType(): + return Type('FileDescriptor::PickleType') + + def _fdBackstagePass(): + return ExprCall(ExprVar('FileDescriptor::IPDLPrivate')) + + write = MethodDefn(self.writeMethodDecl(intype, var)) + write.addstmts([ + StmtDecl(Decl(_fdPickleType(), picklevar.name), + init=ExprCall(ExprSelect(var, '.', 'ShareTo'), + args=[ _fdBackstagePass(), + self.protocol.callOtherProcess() ])), + StmtExpr(ExprCall(ExprVar('IPC::WriteParam'), + args=[ msgvar, picklevar ])), + ]) + + read = MethodDefn(self.readMethodDecl(outtype, var)) + ifread = StmtIf(ExprNot(ExprCall(ExprVar('IPC::ReadParam'), + args=[ msgvar, itervar, + ExprAddrOf(picklevar) ]))) + ifread.addifstmt(StmtReturn.FALSE) + + ifnvalid = StmtIf(ExprNot(ExprCall(ExprSelect(tmpvar, '.', 'IsValid')))) + ifnvalid.addifstmt(StmtReturn.FALSE) + + read.addstmts([ + StmtDecl(Decl(_fdPickleType(), picklevar.name)), + ifread, + Whitespace.NL, + StmtDecl(Decl(_fdType(), tmpvar.name), + init=ExprCall(ExprVar('FileDescriptor'), + args=[ _fdBackstagePass(), picklevar ])), + ifnvalid, + Whitespace.NL, + StmtExpr(ExprAssn(ExprDeref(var), tmpvar)), + StmtReturn.TRUE + ]) + + self.cls.addstmts([ write, Whitespace.NL, read, Whitespace.NL ]) def implementStructPickling(self, structtype): msgvar = self.msgvar diff --git a/ipc/ipdl/ipdl/type.py b/ipc/ipdl/ipdl/type.py index 8ed6c214843f..b30534f22f35 100644 --- a/ipc/ipdl/ipdl/type.py +++ b/ipc/ipdl/ipdl/type.py @@ -89,6 +89,9 @@ class TypeVisitor: def visitShmemChmodType(self, c, *args): c.shmem.accept(self) + def visitFDType(self, s, *args): + pass + class Type: def __cmp__(self, o): @@ -196,6 +199,7 @@ class IPDLType(Type): def isCompound(self): return False def isShmem(self): return False def isChmod(self): return False + def isFD(self): return False def isAsync(self): return self.sendSemantics is ASYNC def isSync(self): return self.sendSemantics is SYNC @@ -417,6 +421,16 @@ class ShmemType(IPDLType): def fullname(self): return str(self.qname) +class FDType(IPDLType): + def __init__(self, qname): + self.qname = qname + def isFD(self): return True + + def name(self): + return self.qname.baseid + def fullname(self): + return str(self.qname) + def iteractortypes(t, visited=None): """Iterate over any actor(s) buried in |type|.""" if visited is None: @@ -452,6 +466,17 @@ def hasshmem(type): return True return False +def hasfd(type): + """Return true iff |type| is fd or has it buried within.""" + class found: pass + class findFD(TypeVisitor): + def visitFDType(self, s): raise found() + try: + type.accept(findFD()) + except found: + return True + return False + ##-------------------- _builtinloc = Loc('', 0) def makeBuiltinUsing(tname): @@ -775,6 +800,8 @@ class GatherDecls(TcheckVisitor): fullname = None if fullname == 'mozilla::ipc::Shmem': ipdltype = ShmemType(using.type.spec) + elif fullname == 'mozilla::ipc::FileDescriptor': + ipdltype = FDType(using.type.spec) else: ipdltype = ImportedCxxType(using.type.spec) using.decl = self.declare( diff --git a/netwerk/base/public/Makefile.in b/netwerk/base/public/Makefile.in index d13ef0b9b8ed..57a136c6ed03 100644 --- a/netwerk/base/public/Makefile.in +++ b/netwerk/base/public/Makefile.in @@ -52,7 +52,7 @@ XPIDLSRCS = \ nsIInputStreamPump.idl \ nsIInputStreamChannel.idl \ nsIIOService2.idl \ - nsIIPCSerializable.idl \ + nsIIPCSerializableObsolete.idl \ nsIMIMEInputStream.idl \ nsINetAddr.idl \ nsINetworkLinkService.idl \ diff --git a/netwerk/base/public/nsIIPCSerializable.idl b/netwerk/base/public/nsIIPCSerializableObsolete.idl similarity index 93% rename from netwerk/base/public/nsIIPCSerializable.idl rename to netwerk/base/public/nsIIPCSerializableObsolete.idl index 595b454209cf..0a04b5647535 100644 --- a/netwerk/base/public/nsIIPCSerializable.idl +++ b/netwerk/base/public/nsIIPCSerializableObsolete.idl @@ -17,7 +17,7 @@ class Message; [ptr] native Iterator(void*); [noscript, uuid(1f605ac7-666b-471f-9864-1a21a95f11c4)] -interface nsIIPCSerializable : nsISupports +interface nsIIPCSerializableObsolete : nsISupports { [notxpcom] boolean read(in ConstMessage msg, in Iterator iter); [notxpcom] void write(in Message msg); diff --git a/netwerk/base/src/nsBufferedStreams.cpp b/netwerk/base/src/nsBufferedStreams.cpp index 10ea3a101da2..1eb22aa6a7ae 100644 --- a/netwerk/base/src/nsBufferedStreams.cpp +++ b/netwerk/base/src/nsBufferedStreams.cpp @@ -252,7 +252,7 @@ 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_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete) NS_IMPL_QUERY_CLASSINFO(nsBufferedInputStream) NS_INTERFACE_MAP_END_INHERITING(nsBufferedStream) @@ -261,7 +261,7 @@ NS_IMPL_CI_INTERFACE_GETTER5(nsBufferedInputStream, nsIBufferedInputStream, nsISeekableStream, nsIStreamBufferAccess, - nsIIPCSerializable) + nsIIPCSerializableObsolete) nsresult nsBufferedInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) diff --git a/netwerk/base/src/nsBufferedStreams.h b/netwerk/base/src/nsBufferedStreams.h index cda118403b70..03a552a7328f 100644 --- a/netwerk/base/src/nsBufferedStreams.h +++ b/netwerk/base/src/nsBufferedStreams.h @@ -13,7 +13,7 @@ #include "nsISeekableStream.h" #include "nsIStreamBufferAccess.h" #include "nsCOMPtr.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" //////////////////////////////////////////////////////////////////////////////// @@ -60,14 +60,14 @@ protected: class nsBufferedInputStream : public nsBufferedStream, public nsIBufferedInputStream, public nsIStreamBufferAccess, - public nsIIPCSerializable + public nsIIPCSerializableObsolete { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIINPUTSTREAM NS_DECL_NSIBUFFEREDINPUTSTREAM NS_DECL_NSISTREAMBUFFERACCESS - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE nsBufferedInputStream() : nsBufferedStream() {} virtual ~nsBufferedInputStream() {} diff --git a/netwerk/base/src/nsFileStreams.cpp b/netwerk/base/src/nsFileStreams.cpp index 4b705c30558f..9f0b7876b60d 100644 --- a/netwerk/base/src/nsFileStreams.cpp +++ b/netwerk/base/src/nsFileStreams.cpp @@ -28,9 +28,14 @@ #include "nsReadLine.h" #include "nsNetUtil.h" #include "nsIClassInfoImpl.h" +#include "mozilla/ipc/IPCSerializableParams.h" #define NS_NO_INPUT_BUFFERING 1 // see http://bugzilla.mozilla.org/show_bug.cgi?id=41067 +typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType; + +using namespace mozilla::ipc; + //////////////////////////////////////////////////////////////////////////////// // nsFileStreamBase @@ -286,12 +291,16 @@ nsFileStreamBase::CleanUpOpen() nsresult nsFileStreamBase::DoOpen() { - NS_PRECONDITION(mOpenParams.localFile, "Must have a file to open"); + NS_ASSERTION(!mFD, "Already have a file descriptor!"); + NS_ASSERTION(mOpenParams.localFile, "Must have a file to open"); PRFileDesc* fd; - nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags, mOpenParams.perm, &fd); + nsresult rv = mOpenParams.localFile->OpenNSPRFileDesc(mOpenParams.ioFlags, + mOpenParams.perm, + &fd); CleanUpOpen(); - if (NS_FAILED(rv)) return rv; + if (NS_FAILED(rv)) + return rv; mFD = fd; return NS_OK; @@ -320,16 +329,16 @@ NS_INTERFACE_MAP_BEGIN(nsFileInputStream) NS_INTERFACE_MAP_ENTRY(nsIInputStream) NS_INTERFACE_MAP_ENTRY(nsIFileInputStream) NS_INTERFACE_MAP_ENTRY(nsILineInputStream) - NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable) + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete) + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream) NS_IMPL_QUERY_CLASSINFO(nsFileInputStream) NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase) -NS_IMPL_CI_INTERFACE_GETTER5(nsFileInputStream, +NS_IMPL_CI_INTERFACE_GETTER4(nsFileInputStream, nsIInputStream, nsIFileInputStream, nsISeekableStream, - nsILineInputStream, - nsIIPCSerializable) + nsILineInputStream) nsresult nsFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, void **aResult) @@ -505,6 +514,76 @@ nsFileInputStream::Write(IPC::Message *aMsg) WriteParam(aMsg, mBehaviorFlags); } +void +nsFileInputStream::Serialize(InputStreamParams& aParams) +{ + FileInputStreamParams params; + + if (mFD) { + FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFD)); + NS_ASSERTION(fd, "This should never be null!"); + + params.file() = FileDescriptor(fd); + NS_ASSERTION(params.file().IsValid(), + "Sending an invalid file descriptor!"); + } else { + NS_WARNING("This file has not been opened (or could not be opened). " + "Sending an invalid file descriptor to the other process!"); + } + + PRInt32 behaviorFlags = mBehaviorFlags; + + // The other process shouldn't close when it reads the end because it will + // not be able to reopen the file later. + behaviorFlags &= ~nsIFileInputStream::CLOSE_ON_EOF; + + // The other process will not be able to reopen the file so transferring + // this flag is meaningless. + behaviorFlags &= ~nsIFileInputStream::REOPEN_ON_REWIND; + + // The other process is going to have an open file descriptor automatically + // so transferring this flag is meaningless. + behaviorFlags &= ~nsIFileInputStream::DEFER_OPEN; + + params.behaviorFlags() = behaviorFlags; + params.ioFlags() = mIOFlags; + + aParams = params; +} + +bool +nsFileInputStream::Deserialize(const InputStreamParams& aParams) +{ + NS_ASSERTION(!mFD, "Already have a file descriptor?!"); + NS_ASSERTION(!mDeferredOpen, "Deferring open?!"); + NS_ASSERTION(!mFile, "Should never have a file here!"); + NS_ASSERTION(!mPerm, "This should always be 0!"); + + if (aParams.type() != InputStreamParams::TFileInputStreamParams) { + NS_WARNING("Received unknown parameters from the other process!"); + return false; + } + + const FileInputStreamParams& params = aParams.get_FileInputStreamParams(); + + const FileDescriptor& fd = params.file(); + NS_WARN_IF_FALSE(fd.IsValid(), "Received an invalid file descriptor!"); + + if (fd.IsValid()) { + PRFileDesc* fileDesc = PR_ImportFile(PROsfd(fd.PlatformHandle())); + if (!fileDesc) { + NS_WARNING("Failed to import file handle!"); + return false; + } + mFD = fileDesc; + } + + mBehaviorFlags = params.behaviorFlags(); + mIOFlags = params.ioFlags(); + + return true; +} + //////////////////////////////////////////////////////////////////////////////// // nsPartialFileInputStream @@ -520,16 +599,16 @@ NS_INTERFACE_MAP_BEGIN(nsPartialFileInputStream) NS_INTERFACE_MAP_ENTRY(nsIInputStream) NS_INTERFACE_MAP_ENTRY(nsIPartialFileInputStream) NS_INTERFACE_MAP_ENTRY(nsILineInputStream) - NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable) + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete) + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream) NS_IMPL_QUERY_CLASSINFO(nsPartialFileInputStream) NS_INTERFACE_MAP_END_INHERITING(nsFileStreamBase) -NS_IMPL_CI_INTERFACE_GETTER5(nsPartialFileInputStream, +NS_IMPL_CI_INTERFACE_GETTER4(nsPartialFileInputStream, nsIInputStream, nsIPartialFileInputStream, nsISeekableStream, - nsILineInputStream, - nsIIPCSerializable) + nsILineInputStream) nsresult nsPartialFileInputStream::Create(nsISupports *aOuter, REFNSIID aIID, @@ -680,6 +759,64 @@ nsPartialFileInputStream::Write(IPC::Message *aMsg) nsFileInputStream::Write(aMsg); } +void +nsPartialFileInputStream::Serialize(InputStreamParams& aParams) +{ + // Serialize the base class first. + InputStreamParams fileParams; + nsFileInputStream::Serialize(fileParams); + + if (fileParams.type() != InputStreamParams::TFileInputStreamParams) { + NS_ERROR("Base class serialize failed!"); + return; + } + + PartialFileInputStreamParams params; + + params.fileStreamParams() = fileParams.get_FileInputStreamParams(); + params.begin() = mStart; + params.length() = mLength; + + aParams = params; +} + +bool +nsPartialFileInputStream::Deserialize(const InputStreamParams& aParams) +{ + NS_ASSERTION(!mFD, "Already have a file descriptor?!"); + NS_ASSERTION(!mStart, "Already have a start?!"); + NS_ASSERTION(!mLength, "Already have a length?!"); + NS_ASSERTION(!mPosition, "Already have a position?!"); + + if (aParams.type() != InputStreamParams::TPartialFileInputStreamParams) { + NS_ERROR("Received unknown parameters from the other process!"); + return false; + } + + const PartialFileInputStreamParams& params = + aParams.get_PartialFileInputStreamParams(); + + // Deserialize the base class first. + InputStreamParams fileParams(params.fileStreamParams()); + if (!nsFileInputStream::Deserialize(fileParams)) { + NS_ERROR("Base class deserialize failed!"); + return false; + } + + NS_ASSERTION(mFD, "Must have a file descriptor now!"); + + mStart = params.begin(); + mLength = params.length(); + mPosition = 0; + + if (!mStart) { + return true; + } + + // XXX This is so broken. Main thread IO alert. + return NS_SUCCEEDED(nsFileInputStream::Seek(NS_SEEK_SET, mStart)); +} + //////////////////////////////////////////////////////////////////////////////// // nsFileOutputStream diff --git a/netwerk/base/src/nsFileStreams.h b/netwerk/base/src/nsFileStreams.h index c3b4d2438abb..e2835b9e9037 100644 --- a/netwerk/base/src/nsFileStreams.h +++ b/netwerk/base/src/nsFileStreams.h @@ -17,7 +17,8 @@ #include "nsCOMPtr.h" #include "prlog.h" #include "prio.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableInputStream.h" +#include "nsIIPCSerializableObsolete.h" template class nsLineBuffer; @@ -102,13 +103,15 @@ protected: class nsFileInputStream : public nsFileStreamBase, public nsIFileInputStream, public nsILineInputStream, - public nsIIPCSerializable + public nsIIPCSerializableObsolete, + public nsIIPCSerializableInputStream { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIFILEINPUTSTREAM NS_DECL_NSILINEINPUTSTREAM - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE + NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM NS_IMETHOD Close(); NS_IMETHOD Available(PRUint64* _retval) @@ -131,9 +134,11 @@ public: NS_IMETHOD Seek(PRInt32 aWhence, PRInt64 aOffset); nsFileInputStream() + : mIOFlags(0), mPerm(0) { mLineBuffer = nullptr; } + virtual ~nsFileInputStream() { Close(); @@ -179,7 +184,12 @@ public: using nsFileInputStream::Init; NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIPARTIALFILEINPUTSTREAM - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE + NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM + + nsPartialFileInputStream() + : mStart(0), mLength(0), mPosition(0) + { } NS_IMETHOD Tell(PRInt64 *aResult); NS_IMETHOD Available(PRUint64 *aResult); diff --git a/netwerk/base/src/nsMIMEInputStream.cpp b/netwerk/base/src/nsMIMEInputStream.cpp index 0878df32fa3a..f77073f208b1 100644 --- a/netwerk/base/src/nsMIMEInputStream.cpp +++ b/netwerk/base/src/nsMIMEInputStream.cpp @@ -19,12 +19,12 @@ #include "nsIStringStream.h" #include "nsString.h" #include "nsMIMEInputStream.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" #include "nsIClassInfoImpl.h" class nsMIMEInputStream : public nsIMIMEInputStream, public nsISeekableStream, - public nsIIPCSerializable + public nsIIPCSerializableObsolete { public: nsMIMEInputStream(); @@ -34,7 +34,7 @@ public: NS_DECL_NSIINPUTSTREAM NS_DECL_NSIMIMEINPUTSTREAM NS_DECL_NSISEEKABLESTREAM - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE NS_METHOD Init(); @@ -73,12 +73,12 @@ NS_IMPL_QUERY_INTERFACE4_CI(nsMIMEInputStream, nsIMIMEInputStream, nsIInputStream, nsISeekableStream, - nsIIPCSerializable) + nsIIPCSerializableObsolete) NS_IMPL_CI_INTERFACE_GETTER4(nsMIMEInputStream, nsIMIMEInputStream, nsIInputStream, nsISeekableStream, - nsIIPCSerializable) + nsIIPCSerializableObsolete) nsMIMEInputStream::nsMIMEInputStream() : mAddContentLength(false), mStartedReading(false) diff --git a/netwerk/base/src/nsSimpleNestedURI.cpp b/netwerk/base/src/nsSimpleNestedURI.cpp index df1f8d99304f..9a5822a8dacd 100644 --- a/netwerk/base/src/nsSimpleNestedURI.cpp +++ b/netwerk/base/src/nsSimpleNestedURI.cpp @@ -55,7 +55,7 @@ nsSimpleNestedURI::Write(nsIObjectOutputStream* aStream) return rv; } -// nsIIPCSerializable +// nsIIPCSerializableObsolete bool nsSimpleNestedURI::Read(const IPC::Message *aMsg, void **aIter) diff --git a/netwerk/base/src/nsSimpleNestedURI.h b/netwerk/base/src/nsSimpleNestedURI.h index f60071b8f155..e0122f807a4e 100644 --- a/netwerk/base/src/nsSimpleNestedURI.h +++ b/netwerk/base/src/nsSimpleNestedURI.h @@ -36,7 +36,7 @@ public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSINESTEDURI - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE // Overrides for various methods nsSimpleURI implements follow. diff --git a/netwerk/base/src/nsSimpleURI.cpp b/netwerk/base/src/nsSimpleURI.cpp index 78734f4b50a0..211ffde7de7f 100644 --- a/netwerk/base/src/nsSimpleURI.cpp +++ b/netwerk/base/src/nsSimpleURI.cpp @@ -41,7 +41,8 @@ nsSimpleURI::~nsSimpleURI() NS_IMPL_ADDREF(nsSimpleURI) NS_IMPL_RELEASE(nsSimpleURI) NS_INTERFACE_TABLE_HEAD(nsSimpleURI) -NS_INTERFACE_TABLE5(nsSimpleURI, nsIURI, nsISerializable, nsIIPCSerializable, nsIClassInfo, nsIMutable) +NS_INTERFACE_TABLE5(nsSimpleURI, nsIURI, nsISerializable, + nsIIPCSerializableObsolete, nsIClassInfo, nsIMutable) NS_INTERFACE_TABLE_TO_MAP_SEGUE if (aIID.Equals(kThisSimpleURIImplementationCID)) foundInterface = static_cast(this); @@ -117,7 +118,7 @@ nsSimpleURI::Write(nsIObjectOutputStream* aStream) } //////////////////////////////////////////////////////////////////////////////// -// nsIIPCSerializable methods: +// nsIIPCSerializableObsolete methods: bool nsSimpleURI::Read(const IPC::Message *aMsg, void **aIter) diff --git a/netwerk/base/src/nsSimpleURI.h b/netwerk/base/src/nsSimpleURI.h index 32a64b11e960..efe82ecc248b 100644 --- a/netwerk/base/src/nsSimpleURI.h +++ b/netwerk/base/src/nsSimpleURI.h @@ -9,7 +9,7 @@ #include "nsIURL.h" #include "nsAgg.h" #include "nsISerializable.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" #include "nsString.h" #include "nsIClassInfo.h" #include "nsIMutable.h" @@ -25,7 +25,7 @@ class nsSimpleURI : public nsIURI, public nsISerializable, - public nsIIPCSerializable, + public nsIIPCSerializableObsolete, public nsIClassInfo, public nsIMutable, public nsISizeOf @@ -34,7 +34,7 @@ public: NS_DECL_ISUPPORTS NS_DECL_NSIURI NS_DECL_NSISERIALIZABLE - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE NS_DECL_NSICLASSINFO NS_DECL_NSIMUTABLE diff --git a/netwerk/base/src/nsStandardURL.cpp b/netwerk/base/src/nsStandardURL.cpp index 7e53a84e6e00..9397df2141b6 100644 --- a/netwerk/base/src/nsStandardURL.cpp +++ b/netwerk/base/src/nsStandardURL.cpp @@ -937,7 +937,7 @@ NS_INTERFACE_MAP_BEGIN(nsStandardURL) NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIFileURL, mSupportsFileURL) NS_INTERFACE_MAP_ENTRY(nsIStandardURL) NS_INTERFACE_MAP_ENTRY(nsISerializable) - NS_INTERFACE_MAP_ENTRY(nsIIPCSerializable) + NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableObsolete) NS_INTERFACE_MAP_ENTRY(nsIClassInfo) NS_INTERFACE_MAP_ENTRY(nsIMutable) // see nsStandardURL::Equals @@ -2876,7 +2876,7 @@ nsStandardURL::Write(nsIObjectOutputStream *stream) } //--------------------------------------------------------------------------- -// nsStandardURL::nsIIPCSerializable +// nsStandardURL::nsIIPCSerializableObsolete //--------------------------------------------------------------------------- bool diff --git a/netwerk/base/src/nsStandardURL.h b/netwerk/base/src/nsStandardURL.h index 0fe881d9c9d9..0bbba2592a82 100644 --- a/netwerk/base/src/nsStandardURL.h +++ b/netwerk/base/src/nsStandardURL.h @@ -10,7 +10,7 @@ #include "nsDependentString.h" #include "nsDependentSubstring.h" #include "nsISerializable.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" #include "nsIFileURL.h" #include "nsIStandardURL.h" #include "nsIFile.h" @@ -42,7 +42,7 @@ class nsIPrefBranch; class nsStandardURL : public nsIFileURL , public nsIStandardURL , public nsISerializable - , public nsIIPCSerializable + , public nsIIPCSerializableObsolete , public nsIClassInfo , public nsISizeOf { @@ -53,7 +53,7 @@ public: NS_DECL_NSIFILEURL NS_DECL_NSISTANDARDURL NS_DECL_NSISERIALIZABLE - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE NS_DECL_NSICLASSINFO NS_DECL_NSIMUTABLE diff --git a/netwerk/ipc/NeckoMessageUtils.h b/netwerk/ipc/NeckoMessageUtils.h index 1473bbb0dd92..93b4aa989f9a 100644 --- a/netwerk/ipc/NeckoMessageUtils.h +++ b/netwerk/ipc/NeckoMessageUtils.h @@ -9,7 +9,7 @@ #include "IPC/IPCMessageUtils.h" #include "nsStringGlue.h" #include "nsIURI.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" #include "nsIClassInfo.h" #include "nsComponentManagerUtils.h" #include "nsNetUtil.h" @@ -51,7 +51,8 @@ struct ParamTraits if (isNull) return; - nsCOMPtr serializable = do_QueryInterface(aParam.mURI); + nsCOMPtr serializable = + do_QueryInterface(aParam.mURI); if (!serializable) { nsCString scheme; aParam.mURI->GetScheme(scheme); @@ -120,7 +121,7 @@ struct ParamTraits nsCOMPtr uri = do_CreateInstance(cid); if (!uri) return false; - nsCOMPtr serializable = do_QueryInterface(uri); + nsCOMPtr serializable = do_QueryInterface(uri); if (!serializable || !serializable->Read(aMsg, aIter)) return false; @@ -170,12 +171,14 @@ struct ParamTraits if (isNull) return; - nsCOMPtr serializable = do_QueryInterface(aParam.mStream); + nsCOMPtr 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"); + NS_WARNING("nsIInputStream implementation doesn't support " + "nsIIPCSerializableObsolete; falling back to copying data"); nsCString streamString; PRUint64 bytes; @@ -241,7 +244,8 @@ struct ParamTraits stream = do_CreateInstance(cid); if (!stream) return false; - nsCOMPtr serializable = do_QueryInterface(stream); + nsCOMPtr serializable = + do_QueryInterface(stream); if (!serializable || !serializable->Read(aMsg, aIter)) return false; } diff --git a/netwerk/protocol/about/nsAboutProtocolHandler.cpp b/netwerk/protocol/about/nsAboutProtocolHandler.cpp index 8e339aecb601..20d43cf349c0 100644 --- a/netwerk/protocol/about/nsAboutProtocolHandler.cpp +++ b/netwerk/protocol/about/nsAboutProtocolHandler.cpp @@ -292,7 +292,7 @@ nsNestedAboutURI::Write(nsIObjectOutputStream* aStream) return NS_OK; } -// nsIIPCSerializable +// nsIIPCSerializableObsolete bool nsNestedAboutURI::Read(const IPC::Message *aMsg, void **aIter) { diff --git a/netwerk/protocol/about/nsAboutProtocolHandler.h b/netwerk/protocol/about/nsAboutProtocolHandler.h index 4c0b83061b1e..0fa9d85013f6 100644 --- a/netwerk/protocol/about/nsAboutProtocolHandler.h +++ b/netwerk/protocol/about/nsAboutProtocolHandler.h @@ -45,7 +45,7 @@ private: // Class to allow us to propagate the base URI to about:blank correctly class nsNestedAboutURI : public nsSimpleNestedURI { public: - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE nsNestedAboutURI(nsIURI* aInnerURI, nsIURI* aBaseURI) : nsSimpleNestedURI(aInnerURI) diff --git a/netwerk/protocol/http/PHttpChannelParams.h b/netwerk/protocol/http/PHttpChannelParams.h index 3590592e1240..ff2c60901383 100644 --- a/netwerk/protocol/http/PHttpChannelParams.h +++ b/netwerk/protocol/http/PHttpChannelParams.h @@ -15,7 +15,6 @@ #include "nsHttpHeaderArray.h" #include "nsHttpResponseHead.h" -#include "nsIIPCSerializable.h" #include "nsIClassInfo.h" #include "nsNetUtil.h" diff --git a/xpcom/io/nsMultiplexInputStream.cpp b/xpcom/io/nsMultiplexInputStream.cpp index 735ede5a08fc..c3bc95226847 100644 --- a/xpcom/io/nsMultiplexInputStream.cpp +++ b/xpcom/io/nsMultiplexInputStream.cpp @@ -17,12 +17,18 @@ #include "nsISeekableStream.h" #include "nsCOMPtr.h" #include "nsCOMArray.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" #include "nsIClassInfoImpl.h" +#include "nsIIPCSerializableInputStream.h" +#include "mozilla/ipc/InputStreamUtils.h" +#include "mozilla/ipc/IPCSerializableParams.h" + +using namespace mozilla::ipc; class nsMultiplexInputStream MOZ_FINAL : public nsIMultiplexInputStream, public nsISeekableStream, - public nsIIPCSerializable + public nsIIPCSerializableObsolete, + public nsIIPCSerializableInputStream { public: nsMultiplexInputStream(); @@ -31,7 +37,8 @@ public: NS_DECL_NSIINPUTSTREAM NS_DECL_NSIMULTIPLEXINPUTSTREAM NS_DECL_NSISEEKABLESTREAM - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE + NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM private: ~nsMultiplexInputStream() {} @@ -60,16 +67,16 @@ NS_IMPL_THREADSAFE_RELEASE(nsMultiplexInputStream) NS_IMPL_CLASSINFO(nsMultiplexInputStream, NULL, nsIClassInfo::THREADSAFE, NS_MULTIPLEXINPUTSTREAM_CID) -NS_IMPL_QUERY_INTERFACE4_CI(nsMultiplexInputStream, +NS_IMPL_QUERY_INTERFACE5_CI(nsMultiplexInputStream, nsIMultiplexInputStream, nsIInputStream, nsISeekableStream, - nsIIPCSerializable) -NS_IMPL_CI_INTERFACE_GETTER4(nsMultiplexInputStream, + nsIIPCSerializableObsolete, + nsIIPCSerializableInputStream) +NS_IMPL_CI_INTERFACE_GETTER3(nsMultiplexInputStream, nsIMultiplexInputStream, nsIInputStream, - nsISeekableStream, - nsIIPCSerializable) + nsISeekableStream) nsMultiplexInputStream::nsMultiplexInputStream() : mCurrentStream(0), @@ -447,3 +454,75 @@ nsMultiplexInputStream::Write(IPC::Message *aMsg) WriteParam(aMsg, mStartedReadingCurrent); WriteParam(aMsg, mStatus); } + +void +nsMultiplexInputStream::Serialize(InputStreamParams& aParams) +{ + MultiplexInputStreamParams params; + + PRUint32 streamCount = mStreams.Count(); + + if (streamCount) { + InfallibleTArray& streams = params.streams(); + + streams.SetCapacity(streamCount); + for (PRUint32 index = 0; index < streamCount; index++) { + nsCOMPtr serializable = + do_QueryInterface(mStreams.ObjectAt(index)); + NS_ASSERTION(serializable, "Child stream isn't serializable!"); + + if (serializable) { + InputStreamParams childStreamParams; + serializable->Serialize(childStreamParams); + + NS_ASSERTION(childStreamParams.type() != + InputStreamParams::T__None, + "Serialize failed!"); + + streams.AppendElement(childStreamParams); + } + } + } + + params.currentStream() = mCurrentStream; + params.status() = mStatus; + params.startedReadingCurrent() = mStartedReadingCurrent; + + aParams = params; +} + +bool +nsMultiplexInputStream::Deserialize(const InputStreamParams& aParams) +{ + if (aParams.type() != + InputStreamParams::TMultiplexInputStreamParams) { + NS_ERROR("Received unknown parameters from the other process!"); + return false; + } + + const MultiplexInputStreamParams& params = + aParams.get_MultiplexInputStreamParams(); + + const InfallibleTArray& streams = params.streams(); + + PRUint32 streamCount = streams.Length(); + for (PRUint32 index = 0; index < streamCount; index++) { + nsCOMPtr stream = + DeserializeInputStream(streams[index]); + if (!stream) { + NS_WARNING("Deserialize failed!"); + return false; + } + + if (NS_FAILED(AppendStream(stream))) { + NS_WARNING("AppendStream failed!"); + return false; + } + } + + mCurrentStream = params.currentStream(); + mStatus = params.status(); + mStartedReadingCurrent = params.startedReadingCurrent(); + + return true; +} diff --git a/xpcom/io/nsStringStream.cpp b/xpcom/io/nsStringStream.cpp index 716dccdc7273..42f32f3ba45b 100644 --- a/xpcom/io/nsStringStream.cpp +++ b/xpcom/io/nsStringStream.cpp @@ -19,8 +19,12 @@ #include "prerror.h" #include "plstr.h" #include "nsIClassInfoImpl.h" -#include "nsIIPCSerializable.h" +#include "nsIIPCSerializableObsolete.h" #include "mozilla/Attributes.h" +#include "mozilla/ipc/IPCSerializableParams.h" +#include "nsIIPCSerializableInputStream.h" + +using namespace mozilla::ipc; //----------------------------------------------------------------------------- // nsIStringInputStream implementation @@ -29,7 +33,8 @@ class nsStringInputStream MOZ_FINAL : public nsIStringInputStream , public nsISeekableStream , public nsISupportsCString - , public nsIIPCSerializable + , public nsIIPCSerializableObsolete + , public nsIIPCSerializableInputStream { public: NS_DECL_ISUPPORTS @@ -38,7 +43,8 @@ public: NS_DECL_NSISEEKABLESTREAM NS_DECL_NSISUPPORTSPRIMITIVE NS_DECL_NSISUPPORTSCSTRING - NS_DECL_NSIIPCSERIALIZABLE + NS_DECL_NSIIPCSERIALIZABLEOBSOLETE + NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM nsStringInputStream() { @@ -80,18 +86,18 @@ NS_IMPL_THREADSAFE_RELEASE(nsStringInputStream) NS_IMPL_CLASSINFO(nsStringInputStream, NULL, nsIClassInfo::THREADSAFE, NS_STRINGINPUTSTREAM_CID) -NS_IMPL_QUERY_INTERFACE5_CI(nsStringInputStream, +NS_IMPL_QUERY_INTERFACE6_CI(nsStringInputStream, nsIStringInputStream, nsIInputStream, nsISupportsCString, nsISeekableStream, - nsIIPCSerializable) -NS_IMPL_CI_INTERFACE_GETTER5(nsStringInputStream, + nsIIPCSerializableObsolete, + nsIIPCSerializableInputStream) +NS_IMPL_CI_INTERFACE_GETTER4(nsStringInputStream, nsIStringInputStream, nsIInputStream, nsISupportsCString, - nsISeekableStream, - nsIIPCSerializable) + nsISeekableStream) ///////// // nsISupportsCString implementation @@ -288,7 +294,7 @@ nsStringInputStream::SetEOF() } ///////// -// nsIIPCSerializable implementation +// nsIIPCSerializableObsolete implementation ///////// bool @@ -316,6 +322,33 @@ nsStringInputStream::Write(IPC::Message *aMsg) WriteParam(aMsg, static_cast(PromiseFlatCString(mData))); } +void +nsStringInputStream::Serialize(InputStreamParams& aParams) +{ + StringInputStreamParams params; + params.data() = PromiseFlatCString(mData); + aParams = params; +} + +bool +nsStringInputStream::Deserialize(const InputStreamParams& aParams) +{ + if (aParams.type() != InputStreamParams::TStringInputStreamParams) { + NS_ERROR("Received unknown parameters from the other process!"); + return false; + } + + const StringInputStreamParams& params = + aParams.get_StringInputStreamParams(); + + if (NS_FAILED(SetData(params.data()))) { + NS_WARNING("SetData failed!"); + return false; + } + + return true; +} + nsresult NS_NewByteInputStream(nsIInputStream** aStreamResult, const char* aStringToRead, PRInt32 aLength,