Source code

Revision control

Copy as Markdown

Other Tools

/* -*- 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/. */
#ifndef mozilla_RemoteLazyInputStream_h
#define mozilla_RemoteLazyInputStream_h
#include "chrome/common/ipc_message_utils.h"
#include "mozilla/Mutex.h"
#include "mozIRemoteLazyInputStream.h"
#include "nsIAsyncInputStream.h"
#include "nsICloneableInputStream.h"
#include "nsIFileStreams.h"
#include "nsIIPCSerializableInputStream.h"
#include "nsIInputStreamLength.h"
#include "nsCOMPtr.h"
namespace mozilla {
class RemoteLazyInputStreamChild;
class RemoteLazyInputStream final : public nsIAsyncInputStream,
public nsIInputStreamCallback,
public nsICloneableInputStreamWithRange,
public nsIIPCSerializableInputStream,
public nsIAsyncFileMetadata,
public nsIInputStreamLength,
public nsIAsyncInputStreamLength,
public mozIRemoteLazyInputStream {
public:
NS_DECL_THREADSAFE_ISUPPORTS
NS_DECL_NSIINPUTSTREAM
NS_DECL_NSIASYNCINPUTSTREAM
NS_DECL_NSIINPUTSTREAMCALLBACK
NS_DECL_NSICLONEABLEINPUTSTREAM
NS_DECL_NSICLONEABLEINPUTSTREAMWITHRANGE
NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
NS_DECL_NSIFILEMETADATA
NS_DECL_NSIASYNCFILEMETADATA
NS_DECL_NSIINPUTSTREAMLENGTH
NS_DECL_NSIASYNCINPUTSTREAMLENGTH
// Create a new lazy RemoteLazyInputStream, and move the provided aInputStream
// into storage as referenced by it. May only be called in processes with
// RemoteLazyInputStreamStorage.
static already_AddRefed<RemoteLazyInputStream> WrapStream(
nsIInputStream* aInputStream);
// mozIRemoteLazyInputStream
NS_IMETHOD TakeInternalStream(nsIInputStream** aStream) override;
NS_IMETHOD GetInternalStreamID(nsID& aID) override;
private:
friend struct IPC::ParamTraits<mozilla::RemoteLazyInputStream*>;
// Constructor for an already-closed RemoteLazyInputStream.
RemoteLazyInputStream() = default;
explicit RemoteLazyInputStream(RemoteLazyInputStreamChild* aActor,
uint64_t aStart = 0,
uint64_t aLength = UINT64_MAX);
explicit RemoteLazyInputStream(nsIInputStream* aStream);
~RemoteLazyInputStream();
void StreamNeeded() MOZ_REQUIRES(mMutex);
// Upon receiving the stream from our actor, we will not wrap it into an async
// stream until needed. This allows callers to get access to the underlying
// potentially-sync stream using `TakeInternalStream` before reading.
nsresult EnsureAsyncRemoteStream() MOZ_REQUIRES(mMutex);
// Note that data has been read from our input stream, and disconnect from our
// remote actor.
void MarkConsumed();
void IPCWrite(IPC::MessageWriter* aWriter);
static already_AddRefed<RemoteLazyInputStream> IPCRead(
IPC::MessageReader* aReader);
// Helper method to generate a description of a stream for use in loggging.
nsCString Describe() MOZ_REQUIRES(mMutex);
// Start and length of the slice to apply on this RemoteLazyInputStream when
// fetching the underlying stream with `SendStreamNeeded`.
const uint64_t mStart = 0;
const uint64_t mLength = UINT64_MAX;
// Any non-const member of this class is protected by mutex because it is
// touched on multiple threads.
Mutex mMutex{"RemoteLazyInputStream::mMutex"};
// This is the list of possible states.
enum {
// The initial state. Only ::Available() can be used without receiving an
// error. The available size is known by the actor.
eInit,
// AsyncWait() has been called for the first time. SendStreamNeeded() has
// been called and we are waiting for the 'real' inputStream.
ePending,
// When the child receives the stream from the parent, we move to this
// state. The received stream is stored in mInnerStream. From now on, any
// method call will be forwared to mInnerStream or mAsyncInnerStream.
eRunning,
// If Close() or CloseWithStatus() is called, we move to this state.
// mInnerStream is released and any method will return
// NS_BASE_STREAM_CLOSED.
eClosed,
} mState MOZ_GUARDED_BY(mMutex) = eClosed;
// The actor which will be used to provide the underlying stream or length
// information when needed, as well as to efficiently allow transferring the
// stream over IPC.
//
// The connection to our actor will be cleared once the stream has been closed
// or has started reading, at which point this stream will be serialized and
// cloned as-if it was the underlying stream.
RefPtr<RemoteLazyInputStreamChild> mActor MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIInputStream> mInnerStream MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIAsyncInputStream> mAsyncInnerStream MOZ_GUARDED_BY(mMutex);
// These 2 values are set only if mState is ePending or eRunning.
// RefPtr is used instead of nsCOMPtr to avoid invoking QueryInterface when
// assigning in debug builds, as `mInputStreamCallback` may not be threadsafe.
RefPtr<nsIInputStreamCallback> mInputStreamCallback MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIEventTarget> mInputStreamCallbackEventTarget
MOZ_GUARDED_BY(mMutex);
uint32_t mInputStreamCallbackFlags MOZ_GUARDED_BY(mMutex) = 0;
uint32_t mInputStreamCallbackRequestedCount MOZ_GUARDED_BY(mMutex) = 0;
// These 2 values are set only if mState is ePending.
nsCOMPtr<nsIFileMetadataCallback> mFileMetadataCallback
MOZ_GUARDED_BY(mMutex);
nsCOMPtr<nsIEventTarget> mFileMetadataCallbackEventTarget
MOZ_GUARDED_BY(mMutex);
};
} // namespace mozilla
template <>
struct IPC::ParamTraits<mozilla::RemoteLazyInputStream*> {
static void Write(IPC::MessageWriter* aWriter,
mozilla::RemoteLazyInputStream* aParam);
static bool Read(IPC::MessageReader* aReader,
RefPtr<mozilla::RemoteLazyInputStream>* aResult);
};
#endif // mozilla_RemoteLazyInputStream_h