forked from mirrors/gecko-dev
		
	 f3bddbd52b
			
		
	
	
		f3bddbd52b
		
	
	
	
	
		
			
			Differential Revision: https://phabricator.services.mozilla.com/D54289 --HG-- extra : moz-landing-system : lando
		
			
				
	
	
		
			363 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			363 lines
		
	
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* -*- 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
 |