From ee501c8947f07834402b7d36a667672515bcab51 Mon Sep 17 00:00:00 2001 From: Josh Matthews Date: Fri, 23 Sep 2016 10:34:42 -0400 Subject: [PATCH] Bug 1167730 - Make nsTemporaryFileStream serializable. r=baku --- dom/ipc/tests/blob_verify.sjs | 20 +++++ dom/ipc/tests/mochitest.ini | 4 + dom/ipc/tests/test_temporaryfile_stream.html | 80 ++++++++++++++++++++ ipc/glue/InputStreamParams.ipdlh | 8 ++ ipc/glue/InputStreamUtils.cpp | 4 + netwerk/base/nsTemporaryFileInputStream.cpp | 77 ++++++++++++++++++- netwerk/base/nsTemporaryFileInputStream.h | 4 + 7 files changed, 196 insertions(+), 1 deletion(-) create mode 100644 dom/ipc/tests/blob_verify.sjs create mode 100644 dom/ipc/tests/test_temporaryfile_stream.html diff --git a/dom/ipc/tests/blob_verify.sjs b/dom/ipc/tests/blob_verify.sjs new file mode 100644 index 000000000000..62b82359e593 --- /dev/null +++ b/dom/ipc/tests/blob_verify.sjs @@ -0,0 +1,20 @@ +const CC = Components.Constructor; +const BinaryInputStream = CC("@mozilla.org/binaryinputstream;1", + "nsIBinaryInputStream", + "setInputStream"); +const BinaryOutputStream = CC("@mozilla.org/binaryoutputstream;1", + "nsIBinaryOutputStream", + "setOutputStream"); + +function handleRequest(request, response) { + var bodyStream = new BinaryInputStream(request.bodyInputStream); + var bodyBytes = []; + while ((bodyAvail = bodyStream.available()) > 0) + Array.prototype.push.apply(bodyBytes, bodyStream.readByteArray(bodyAvail)); + + var bos = new BinaryOutputStream(response.bodyOutputStream); + + response.processAsync(); + bos.writeByteArray(bodyBytes, bodyBytes.length); + response.finish(); +} diff --git a/dom/ipc/tests/mochitest.ini b/dom/ipc/tests/mochitest.ini index 8032f4414605..1c1cb4ed2353 100644 --- a/dom/ipc/tests/mochitest.ini +++ b/dom/ipc/tests/mochitest.ini @@ -53,3 +53,7 @@ support-files = test_permission_helper.js test_permission_embed.html test_permission_framescript.js +[test_temporaryfile_stream.html] +support-files = + blob_verify.sjs + !/dom/canvas/test/captureStream_common.js \ No newline at end of file diff --git a/dom/ipc/tests/test_temporaryfile_stream.html b/dom/ipc/tests/test_temporaryfile_stream.html new file mode 100644 index 000000000000..e05accbdf1ba --- /dev/null +++ b/dom/ipc/tests/test_temporaryfile_stream.html @@ -0,0 +1,80 @@ + + + + Send an nsTemporaryFileInputStream cross-process + + + + + +
+
+
+ +
+ + diff --git a/ipc/glue/InputStreamParams.ipdlh b/ipc/glue/InputStreamParams.ipdlh index bfe03bf71c08..eb6869c17028 100644 --- a/ipc/glue/InputStreamParams.ipdlh +++ b/ipc/glue/InputStreamParams.ipdlh @@ -30,6 +30,13 @@ struct PartialFileInputStreamParams uint64_t length; }; +struct TemporaryFileInputStreamParams +{ + uint32_t fileDescriptorIndex; + uint64_t startPos; + uint64_t endPos; +}; + struct MultiplexInputStreamParams { InputStreamParams[] streams; @@ -56,6 +63,7 @@ union InputStreamParams StringInputStreamParams; FileInputStreamParams; PartialFileInputStreamParams; + TemporaryFileInputStreamParams; BufferedInputStreamParams; MIMEInputStreamParams; MultiplexInputStreamParams; diff --git a/ipc/glue/InputStreamUtils.cpp b/ipc/glue/InputStreamUtils.cpp index dd3f8710225d..bbc863efd6bd 100644 --- a/ipc/glue/InputStreamUtils.cpp +++ b/ipc/glue/InputStreamUtils.cpp @@ -93,6 +93,10 @@ DeserializeInputStream(const InputStreamParams& aParams, serializable = do_CreateInstance(kPartialFileInputStreamCID); break; + case InputStreamParams::TTemporaryFileInputStreamParams: + serializable = new nsTemporaryFileInputStream(); + break; + case InputStreamParams::TBufferedInputStreamParams: serializable = do_CreateInstance(kBufferedInputStreamCID); break; diff --git a/netwerk/base/nsTemporaryFileInputStream.cpp b/netwerk/base/nsTemporaryFileInputStream.cpp index c237f64e3570..88f7fac8cfb3 100644 --- a/netwerk/base/nsTemporaryFileInputStream.cpp +++ b/netwerk/base/nsTemporaryFileInputStream.cpp @@ -7,7 +7,12 @@ #include "nsStreamUtils.h" #include -NS_IMPL_ISUPPORTS(nsTemporaryFileInputStream, nsIInputStream, nsISeekableStream) +typedef mozilla::ipc::FileDescriptor::PlatformHandleType FileHandleType; + +NS_IMPL_ISUPPORTS(nsTemporaryFileInputStream, + nsIInputStream, + nsISeekableStream, + nsIIPCSerializableInputStream) nsTemporaryFileInputStream::nsTemporaryFileInputStream(FileDescOwner* aFileDescOwner, uint64_t aStartPos, uint64_t aEndPos) : mFileDescOwner(aFileDescOwner), @@ -19,6 +24,14 @@ nsTemporaryFileInputStream::nsTemporaryFileInputStream(FileDescOwner* aFileDescO NS_ASSERTION(aStartPos <= aEndPos, "StartPos should less equal than EndPos!"); } +nsTemporaryFileInputStream::nsTemporaryFileInputStream() + : mStartPos(0), + mCurPos(0), + mEndPos(0), + mClosed(false) +{ +} + NS_IMETHODIMP nsTemporaryFileInputStream::Close() { @@ -164,3 +177,65 @@ nsTemporaryFileInputStream::SetEOF() return Close(); } + +void +nsTemporaryFileInputStream::Serialize(InputStreamParams& aParams, + FileDescriptorArray& aFileDescriptors) +{ + TemporaryFileInputStreamParams params; + + MutexAutoLock lock(mFileDescOwner->FileMutex()); + MOZ_ASSERT(mFileDescOwner->mFD); + if (!mClosed) { + FileHandleType fd = FileHandleType(PR_FileDesc2NativeHandle(mFileDescOwner->mFD)); + NS_ASSERTION(fd, "This should never be null!"); + + DebugOnly dbgFD = aFileDescriptors.AppendElement(fd); + NS_ASSERTION(dbgFD->IsValid(), "Sending an invalid file descriptor!"); + + params.fileDescriptorIndex() = aFileDescriptors.Length() - 1; + + Close(); + } else { + NS_WARNING("The stream is already closed. " + "Sending an invalid file descriptor to the other process!"); + + params.fileDescriptorIndex() = UINT32_MAX; + } + params.startPos() = mCurPos; + params.endPos() = mEndPos; + aParams = params; +} + +bool +nsTemporaryFileInputStream::Deserialize(const InputStreamParams& aParams, + const FileDescriptorArray& aFileDescriptors) +{ + const TemporaryFileInputStreamParams& params = aParams.get_TemporaryFileInputStreamParams(); + + uint32_t fileDescriptorIndex = params.fileDescriptorIndex(); + FileDescriptor fd; + if (fileDescriptorIndex < aFileDescriptors.Length()) { + fd = aFileDescriptors[fileDescriptorIndex]; + NS_WARNING_ASSERTION(fd.IsValid(), + "Received an invalid file descriptor!"); + } else { + NS_WARNING("Received a bad file descriptor index!"); + } + + if (fd.IsValid()) { + auto rawFD = fd.ClonePlatformHandle(); + PRFileDesc* fileDesc = PR_ImportFile(PROsfd(rawFD.release())); + if (!fileDesc) { + NS_WARNING("Failed to import file handle!"); + return false; + } + mFileDescOwner = new FileDescOwner(fileDesc); + } else { + mClosed = true; + } + + mStartPos = mCurPos = params.startPos(); + mEndPos = params.endPos(); + return true; +} diff --git a/netwerk/base/nsTemporaryFileInputStream.h b/netwerk/base/nsTemporaryFileInputStream.h index 8299daa7d36b..950b26c29ac0 100644 --- a/netwerk/base/nsTemporaryFileInputStream.h +++ b/netwerk/base/nsTemporaryFileInputStream.h @@ -9,11 +9,13 @@ #include "mozilla/Mutex.h" #include "nsAutoPtr.h" #include "nsIInputStream.h" +#include "nsIIPCSerializableInputStream.h" #include "nsISeekableStream.h" #include "prio.h" class nsTemporaryFileInputStream : public nsIInputStream , public nsISeekableStream + , public nsIIPCSerializableInputStream { public: //used to release a PRFileDesc @@ -42,10 +44,12 @@ public: }; nsTemporaryFileInputStream(FileDescOwner* aFileDescOwner, uint64_t aStartPos, uint64_t aEndPos); + nsTemporaryFileInputStream(); NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSIINPUTSTREAM NS_DECL_NSISEEKABLESTREAM + NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM private: virtual ~nsTemporaryFileInputStream() { }