summaryrefslogtreecommitdiffstats
path: root/dom/file/ipc/RemoteLazyInputStream.h
blob: 08bb168e275788d59613ace8e73eeae348309328 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
/* -*- 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