summaryrefslogtreecommitdiffstats
path: root/xpcom/io/InputStreamLengthWrapper.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'xpcom/io/InputStreamLengthWrapper.cpp')
-rw-r--r--xpcom/io/InputStreamLengthWrapper.cpp363
1 files changed, 363 insertions, 0 deletions
diff --git a/xpcom/io/InputStreamLengthWrapper.cpp b/xpcom/io/InputStreamLengthWrapper.cpp
new file mode 100644
index 0000000000..4014e90768
--- /dev/null
+++ b/xpcom/io/InputStreamLengthWrapper.cpp
@@ -0,0 +1,363 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "InputStreamLengthWrapper.h"
+#include "mozilla/ipc/InputStreamUtils.h"
+#include "nsISeekableStream.h"
+#include "nsStreamUtils.h"
+
+namespace mozilla {
+
+using namespace ipc;
+
+NS_IMPL_ADDREF(InputStreamLengthWrapper);
+NS_IMPL_RELEASE(InputStreamLengthWrapper);
+
+NS_INTERFACE_MAP_BEGIN(InputStreamLengthWrapper)
+ NS_INTERFACE_MAP_ENTRY(nsIInputStream)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
+ mWeakCloneableInputStream || !mInputStream)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
+ nsIIPCSerializableInputStream,
+ mWeakIPCSerializableInputStream || !mInputStream)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream,
+ mWeakSeekableInputStream || !mInputStream)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITellableStream,
+ mWeakTellableInputStream || !mInputStream)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
+ mWeakAsyncInputStream || !mInputStream)
+ NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
+ mWeakAsyncInputStream || !mInputStream)
+ NS_INTERFACE_MAP_ENTRY(nsIInputStreamLength)
+ NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
+NS_INTERFACE_MAP_END
+
+/* static */
+already_AddRefed<nsIInputStream> InputStreamLengthWrapper::MaybeWrap(
+ already_AddRefed<nsIInputStream> aInputStream, int64_t aLength) {
+ nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
+ MOZ_ASSERT(inputStream);
+
+ nsCOMPtr<nsIInputStreamLength> length = do_QueryInterface(inputStream);
+ if (length) {
+ return inputStream.forget();
+ }
+
+ nsCOMPtr<nsIAsyncInputStreamLength> asyncLength =
+ do_QueryInterface(inputStream);
+ if (asyncLength) {
+ return inputStream.forget();
+ }
+
+ nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(inputStream);
+ if (!asyncStream) {
+ return inputStream.forget();
+ }
+
+ inputStream = new InputStreamLengthWrapper(inputStream.forget(), aLength);
+ return inputStream.forget();
+}
+
+InputStreamLengthWrapper::InputStreamLengthWrapper(
+ already_AddRefed<nsIInputStream> aInputStream, int64_t aLength)
+ : mWeakCloneableInputStream(nullptr),
+ mWeakIPCSerializableInputStream(nullptr),
+ mWeakSeekableInputStream(nullptr),
+ mWeakTellableInputStream(nullptr),
+ mWeakAsyncInputStream(nullptr),
+ mLength(aLength),
+ mConsumed(false),
+ mMutex("InputStreamLengthWrapper::mMutex") {
+ MOZ_ASSERT(mLength >= 0);
+
+ nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
+ SetSourceStream(inputStream.forget());
+}
+
+InputStreamLengthWrapper::InputStreamLengthWrapper()
+ : mWeakCloneableInputStream(nullptr),
+ mWeakIPCSerializableInputStream(nullptr),
+ mWeakSeekableInputStream(nullptr),
+ mWeakTellableInputStream(nullptr),
+ mWeakAsyncInputStream(nullptr),
+ mLength(-1),
+ mConsumed(false),
+ mMutex("InputStreamLengthWrapper::mMutex") {}
+
+InputStreamLengthWrapper::~InputStreamLengthWrapper() = default;
+
+void InputStreamLengthWrapper::SetSourceStream(
+ already_AddRefed<nsIInputStream> aInputStream) {
+ MOZ_ASSERT(!mInputStream);
+
+ mInputStream = std::move(aInputStream);
+
+ nsCOMPtr<nsICloneableInputStream> cloneableStream =
+ do_QueryInterface(mInputStream);
+ if (cloneableStream && SameCOMIdentity(mInputStream, cloneableStream)) {
+ mWeakCloneableInputStream = cloneableStream;
+ }
+
+ nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
+ do_QueryInterface(mInputStream);
+ if (serializableStream && SameCOMIdentity(mInputStream, serializableStream)) {
+ mWeakIPCSerializableInputStream = serializableStream;
+ }
+
+ nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mInputStream);
+ if (seekableStream && SameCOMIdentity(mInputStream, seekableStream)) {
+ mWeakSeekableInputStream = seekableStream;
+ }
+
+ nsCOMPtr<nsITellableStream> tellableStream = do_QueryInterface(mInputStream);
+ if (tellableStream && SameCOMIdentity(mInputStream, tellableStream)) {
+ mWeakTellableInputStream = tellableStream;
+ }
+
+ nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
+ do_QueryInterface(mInputStream);
+ if (asyncInputStream && SameCOMIdentity(mInputStream, asyncInputStream)) {
+ mWeakAsyncInputStream = asyncInputStream;
+ }
+}
+
+// nsIInputStream interface
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Close() {
+ NS_ENSURE_STATE(mInputStream);
+ return mInputStream->Close();
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Available(uint64_t* aLength) {
+ NS_ENSURE_STATE(mInputStream);
+ return mInputStream->Available(aLength);
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Read(char* aBuffer, uint32_t aCount,
+ uint32_t* aReadCount) {
+ NS_ENSURE_STATE(mInputStream);
+ mConsumed = true;
+ return mInputStream->Read(aBuffer, aCount, aReadCount);
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::ReadSegments(nsWriteSegmentFun aWriter,
+ void* aClosure, uint32_t aCount,
+ uint32_t* aResult) {
+ return NS_ERROR_NOT_IMPLEMENTED;
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::IsNonBlocking(bool* aNonBlocking) {
+ NS_ENSURE_STATE(mInputStream);
+ return mInputStream->IsNonBlocking(aNonBlocking);
+}
+
+// nsICloneableInputStream interface
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::GetCloneable(bool* aCloneable) {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakCloneableInputStream);
+ mWeakCloneableInputStream->GetCloneable(aCloneable);
+ return NS_OK;
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Clone(nsIInputStream** aResult) {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakCloneableInputStream);
+
+ nsCOMPtr<nsIInputStream> clonedStream;
+ nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+
+ nsCOMPtr<nsIInputStream> stream =
+ new InputStreamLengthWrapper(clonedStream.forget(), mLength);
+
+ stream.forget(aResult);
+ return NS_OK;
+}
+
+// nsIAsyncInputStream interface
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::CloseWithStatus(nsresult aStatus) {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakAsyncInputStream);
+
+ mConsumed = true;
+ return mWeakAsyncInputStream->CloseWithStatus(aStatus);
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::AsyncWait(nsIInputStreamCallback* aCallback,
+ uint32_t aFlags, uint32_t aRequestedCount,
+ nsIEventTarget* aEventTarget) {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakAsyncInputStream);
+
+ nsCOMPtr<nsIInputStreamCallback> callback = this;
+ {
+ MutexAutoLock lock(mMutex);
+
+ if (mAsyncWaitCallback && aCallback) {
+ return NS_ERROR_FAILURE;
+ }
+
+ bool hadCallback = !!mAsyncWaitCallback;
+ mAsyncWaitCallback = aCallback;
+
+ if (!mAsyncWaitCallback) {
+ if (!hadCallback) {
+ // No pending operation.
+ return NS_OK;
+ }
+
+ // Abort current operation.
+ callback = nullptr;
+ }
+ }
+
+ return mWeakAsyncInputStream->AsyncWait(callback, aFlags, aRequestedCount,
+ aEventTarget);
+}
+
+// nsIInputStreamCallback
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::OnInputStreamReady(nsIAsyncInputStream* aStream) {
+ MOZ_ASSERT(mInputStream);
+ MOZ_ASSERT(mWeakAsyncInputStream);
+ MOZ_ASSERT(mWeakAsyncInputStream == aStream);
+
+ nsCOMPtr<nsIInputStreamCallback> callback;
+ {
+ MutexAutoLock lock(mMutex);
+ // We have been canceled in the meanwhile.
+ if (!mAsyncWaitCallback) {
+ return NS_OK;
+ }
+
+ callback.swap(mAsyncWaitCallback);
+ }
+
+ MOZ_ASSERT(callback);
+ return callback->OnInputStreamReady(this);
+}
+
+// nsIIPCSerializableInputStream
+
+void InputStreamLengthWrapper::Serialize(
+ mozilla::ipc::InputStreamParams& aParams,
+ FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+ uint32_t aMaxSize, uint32_t* aSizeUsed,
+ mozilla::ipc::ParentToChildStreamActorManager* aManager) {
+ SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+ aSizeUsed, aManager);
+}
+
+void InputStreamLengthWrapper::Serialize(
+ mozilla::ipc::InputStreamParams& aParams,
+ FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+ uint32_t aMaxSize, uint32_t* aSizeUsed,
+ mozilla::ipc::ChildToParentStreamActorManager* aManager) {
+ SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
+ aSizeUsed, aManager);
+}
+
+template <typename M>
+void InputStreamLengthWrapper::SerializeInternal(
+ mozilla::ipc::InputStreamParams& aParams,
+ FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
+ uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
+ MOZ_ASSERT(mInputStream);
+ MOZ_ASSERT(mWeakIPCSerializableInputStream);
+
+ InputStreamLengthWrapperParams params;
+ InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
+ aFileDescriptors, aDelayedStart,
+ aMaxSize, aSizeUsed, aManager);
+ params.length() = mLength;
+ params.consumed() = mConsumed;
+
+ aParams = params;
+}
+
+bool InputStreamLengthWrapper::Deserialize(
+ const mozilla::ipc::InputStreamParams& aParams,
+ const FileDescriptorArray& aFileDescriptors) {
+ MOZ_ASSERT(!mInputStream);
+ MOZ_ASSERT(!mWeakIPCSerializableInputStream);
+
+ if (aParams.type() != InputStreamParams::TInputStreamLengthWrapperParams) {
+ NS_ERROR("Received unknown parameters from the other process!");
+ return false;
+ }
+
+ const InputStreamLengthWrapperParams& params =
+ aParams.get_InputStreamLengthWrapperParams();
+
+ nsCOMPtr<nsIInputStream> stream = InputStreamHelper::DeserializeInputStream(
+ params.stream(), aFileDescriptors);
+ if (!stream) {
+ NS_WARNING("Deserialize failed!");
+ return false;
+ }
+
+ SetSourceStream(stream.forget());
+
+ mLength = params.length();
+ mConsumed = params.consumed();
+
+ return true;
+}
+
+// nsISeekableStream
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Seek(int32_t aWhence, int64_t aOffset) {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakSeekableInputStream);
+
+ mConsumed = true;
+ return mWeakSeekableInputStream->Seek(aWhence, aOffset);
+}
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::SetEOF() {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakSeekableInputStream);
+
+ mConsumed = true;
+ return mWeakSeekableInputStream->SetEOF();
+}
+
+// nsITellableStream
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Tell(int64_t* aResult) {
+ NS_ENSURE_STATE(mInputStream);
+ NS_ENSURE_STATE(mWeakTellableInputStream);
+
+ return mWeakTellableInputStream->Tell(aResult);
+}
+
+// nsIInputStreamLength
+
+NS_IMETHODIMP
+InputStreamLengthWrapper::Length(int64_t* aLength) {
+ NS_ENSURE_STATE(mInputStream);
+ *aLength = mLength;
+ return NS_OK;
+}
+
+} // namespace mozilla