зеркало из https://github.com/mozilla/gecko-dev.git
382 строки
12 KiB
C++
382 строки
12 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::dom::ContentChild* 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::PBackgroundChild* 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::dom::ContentParent* 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::PBackgroundParent* 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
|