1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "InputStreamLengthWrapper.h"
8 #include "mozilla/ipc/InputStreamUtils.h"
9 #include "nsISeekableStream.h"
10 #include "nsStreamUtils.h"
11
12 namespace mozilla {
13
14 using namespace ipc;
15
16 NS_IMPL_ADDREF(InputStreamLengthWrapper);
17 NS_IMPL_RELEASE(InputStreamLengthWrapper);
18
19 NS_INTERFACE_MAP_BEGIN(InputStreamLengthWrapper)
NS_INTERFACE_MAP_ENTRY(nsIInputStream)20 NS_INTERFACE_MAP_ENTRY(nsIInputStream)
21 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
22 mWeakCloneableInputStream || !mInputStream)
23 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(
24 nsIIPCSerializableInputStream,
25 mWeakIPCSerializableInputStream || !mInputStream)
26 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream,
27 mWeakSeekableInputStream || !mInputStream)
28 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsITellableStream,
29 mWeakTellableInputStream || !mInputStream)
30 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
31 mWeakAsyncInputStream || !mInputStream)
32 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
33 mWeakAsyncInputStream || !mInputStream)
34 NS_INTERFACE_MAP_ENTRY(nsIInputStreamLength)
35 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
36 NS_INTERFACE_MAP_END
37
38 /* static */
39 already_AddRefed<nsIInputStream> InputStreamLengthWrapper::MaybeWrap(
40 already_AddRefed<nsIInputStream> aInputStream, int64_t aLength) {
41 nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
42 MOZ_ASSERT(inputStream);
43
44 nsCOMPtr<nsIInputStreamLength> length = do_QueryInterface(inputStream);
45 if (length) {
46 return inputStream.forget();
47 }
48
49 nsCOMPtr<nsIAsyncInputStreamLength> asyncLength =
50 do_QueryInterface(inputStream);
51 if (asyncLength) {
52 return inputStream.forget();
53 }
54
55 nsCOMPtr<nsIAsyncInputStream> asyncStream = do_QueryInterface(inputStream);
56 if (!asyncStream) {
57 return inputStream.forget();
58 }
59
60 inputStream = new InputStreamLengthWrapper(inputStream.forget(), aLength);
61 return inputStream.forget();
62 }
63
InputStreamLengthWrapper(already_AddRefed<nsIInputStream> aInputStream,int64_t aLength)64 InputStreamLengthWrapper::InputStreamLengthWrapper(
65 already_AddRefed<nsIInputStream> aInputStream, int64_t aLength)
66 : mWeakCloneableInputStream(nullptr),
67 mWeakIPCSerializableInputStream(nullptr),
68 mWeakSeekableInputStream(nullptr),
69 mWeakTellableInputStream(nullptr),
70 mWeakAsyncInputStream(nullptr),
71 mLength(aLength),
72 mConsumed(false),
73 mMutex("InputStreamLengthWrapper::mMutex") {
74 MOZ_ASSERT(mLength >= 0);
75
76 nsCOMPtr<nsIInputStream> inputStream = std::move(aInputStream);
77 SetSourceStream(inputStream.forget());
78 }
79
InputStreamLengthWrapper()80 InputStreamLengthWrapper::InputStreamLengthWrapper()
81 : mWeakCloneableInputStream(nullptr),
82 mWeakIPCSerializableInputStream(nullptr),
83 mWeakSeekableInputStream(nullptr),
84 mWeakTellableInputStream(nullptr),
85 mWeakAsyncInputStream(nullptr),
86 mLength(-1),
87 mConsumed(false),
88 mMutex("InputStreamLengthWrapper::mMutex") {}
89
90 InputStreamLengthWrapper::~InputStreamLengthWrapper() = default;
91
SetSourceStream(already_AddRefed<nsIInputStream> aInputStream)92 void InputStreamLengthWrapper::SetSourceStream(
93 already_AddRefed<nsIInputStream> aInputStream) {
94 MOZ_ASSERT(!mInputStream);
95
96 mInputStream = std::move(aInputStream);
97
98 nsCOMPtr<nsICloneableInputStream> cloneableStream =
99 do_QueryInterface(mInputStream);
100 if (cloneableStream && SameCOMIdentity(mInputStream, cloneableStream)) {
101 mWeakCloneableInputStream = cloneableStream;
102 }
103
104 nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
105 do_QueryInterface(mInputStream);
106 if (serializableStream && SameCOMIdentity(mInputStream, serializableStream)) {
107 mWeakIPCSerializableInputStream = serializableStream;
108 }
109
110 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mInputStream);
111 if (seekableStream && SameCOMIdentity(mInputStream, seekableStream)) {
112 mWeakSeekableInputStream = seekableStream;
113 }
114
115 nsCOMPtr<nsITellableStream> tellableStream = do_QueryInterface(mInputStream);
116 if (tellableStream && SameCOMIdentity(mInputStream, tellableStream)) {
117 mWeakTellableInputStream = tellableStream;
118 }
119
120 nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
121 do_QueryInterface(mInputStream);
122 if (asyncInputStream && SameCOMIdentity(mInputStream, asyncInputStream)) {
123 mWeakAsyncInputStream = asyncInputStream;
124 }
125 }
126
127 // nsIInputStream interface
128
129 NS_IMETHODIMP
Close()130 InputStreamLengthWrapper::Close() {
131 NS_ENSURE_STATE(mInputStream);
132 return mInputStream->Close();
133 }
134
135 NS_IMETHODIMP
Available(uint64_t * aLength)136 InputStreamLengthWrapper::Available(uint64_t* aLength) {
137 NS_ENSURE_STATE(mInputStream);
138 return mInputStream->Available(aLength);
139 }
140
141 NS_IMETHODIMP
Read(char * aBuffer,uint32_t aCount,uint32_t * aReadCount)142 InputStreamLengthWrapper::Read(char* aBuffer, uint32_t aCount,
143 uint32_t* aReadCount) {
144 NS_ENSURE_STATE(mInputStream);
145 mConsumed = true;
146 return mInputStream->Read(aBuffer, aCount, aReadCount);
147 }
148
149 NS_IMETHODIMP
ReadSegments(nsWriteSegmentFun aWriter,void * aClosure,uint32_t aCount,uint32_t * aResult)150 InputStreamLengthWrapper::ReadSegments(nsWriteSegmentFun aWriter,
151 void* aClosure, uint32_t aCount,
152 uint32_t* aResult) {
153 return NS_ERROR_NOT_IMPLEMENTED;
154 }
155
156 NS_IMETHODIMP
IsNonBlocking(bool * aNonBlocking)157 InputStreamLengthWrapper::IsNonBlocking(bool* aNonBlocking) {
158 NS_ENSURE_STATE(mInputStream);
159 return mInputStream->IsNonBlocking(aNonBlocking);
160 }
161
162 // nsICloneableInputStream interface
163
164 NS_IMETHODIMP
GetCloneable(bool * aCloneable)165 InputStreamLengthWrapper::GetCloneable(bool* aCloneable) {
166 NS_ENSURE_STATE(mInputStream);
167 NS_ENSURE_STATE(mWeakCloneableInputStream);
168 mWeakCloneableInputStream->GetCloneable(aCloneable);
169 return NS_OK;
170 }
171
172 NS_IMETHODIMP
Clone(nsIInputStream ** aResult)173 InputStreamLengthWrapper::Clone(nsIInputStream** aResult) {
174 NS_ENSURE_STATE(mInputStream);
175 NS_ENSURE_STATE(mWeakCloneableInputStream);
176
177 nsCOMPtr<nsIInputStream> clonedStream;
178 nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
179 if (NS_WARN_IF(NS_FAILED(rv))) {
180 return rv;
181 }
182
183 nsCOMPtr<nsIInputStream> stream =
184 new InputStreamLengthWrapper(clonedStream.forget(), mLength);
185
186 stream.forget(aResult);
187 return NS_OK;
188 }
189
190 // nsIAsyncInputStream interface
191
192 NS_IMETHODIMP
CloseWithStatus(nsresult aStatus)193 InputStreamLengthWrapper::CloseWithStatus(nsresult aStatus) {
194 NS_ENSURE_STATE(mInputStream);
195 NS_ENSURE_STATE(mWeakAsyncInputStream);
196
197 mConsumed = true;
198 return mWeakAsyncInputStream->CloseWithStatus(aStatus);
199 }
200
201 NS_IMETHODIMP
AsyncWait(nsIInputStreamCallback * aCallback,uint32_t aFlags,uint32_t aRequestedCount,nsIEventTarget * aEventTarget)202 InputStreamLengthWrapper::AsyncWait(nsIInputStreamCallback* aCallback,
203 uint32_t aFlags, uint32_t aRequestedCount,
204 nsIEventTarget* aEventTarget) {
205 NS_ENSURE_STATE(mInputStream);
206 NS_ENSURE_STATE(mWeakAsyncInputStream);
207
208 nsCOMPtr<nsIInputStreamCallback> callback = this;
209 {
210 MutexAutoLock lock(mMutex);
211
212 if (mAsyncWaitCallback && aCallback) {
213 return NS_ERROR_FAILURE;
214 }
215
216 bool hadCallback = !!mAsyncWaitCallback;
217 mAsyncWaitCallback = aCallback;
218
219 if (!mAsyncWaitCallback) {
220 if (!hadCallback) {
221 // No pending operation.
222 return NS_OK;
223 }
224
225 // Abort current operation.
226 callback = nullptr;
227 }
228 }
229
230 return mWeakAsyncInputStream->AsyncWait(callback, aFlags, aRequestedCount,
231 aEventTarget);
232 }
233
234 // nsIInputStreamCallback
235
236 NS_IMETHODIMP
OnInputStreamReady(nsIAsyncInputStream * aStream)237 InputStreamLengthWrapper::OnInputStreamReady(nsIAsyncInputStream* aStream) {
238 MOZ_ASSERT(mInputStream);
239 MOZ_ASSERT(mWeakAsyncInputStream);
240 MOZ_ASSERT(mWeakAsyncInputStream == aStream);
241
242 nsCOMPtr<nsIInputStreamCallback> callback;
243 {
244 MutexAutoLock lock(mMutex);
245 // We have been canceled in the meanwhile.
246 if (!mAsyncWaitCallback) {
247 return NS_OK;
248 }
249
250 callback.swap(mAsyncWaitCallback);
251 }
252
253 MOZ_ASSERT(callback);
254 return callback->OnInputStreamReady(this);
255 }
256
257 // nsIIPCSerializableInputStream
258
Serialize(mozilla::ipc::InputStreamParams & aParams,FileDescriptorArray & aFileDescriptors,bool aDelayedStart,uint32_t aMaxSize,uint32_t * aSizeUsed,mozilla::ipc::ParentToChildStreamActorManager * aManager)259 void InputStreamLengthWrapper::Serialize(
260 mozilla::ipc::InputStreamParams& aParams,
261 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
262 uint32_t aMaxSize, uint32_t* aSizeUsed,
263 mozilla::ipc::ParentToChildStreamActorManager* aManager) {
264 SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
265 aSizeUsed, aManager);
266 }
267
Serialize(mozilla::ipc::InputStreamParams & aParams,FileDescriptorArray & aFileDescriptors,bool aDelayedStart,uint32_t aMaxSize,uint32_t * aSizeUsed,mozilla::ipc::ChildToParentStreamActorManager * aManager)268 void InputStreamLengthWrapper::Serialize(
269 mozilla::ipc::InputStreamParams& aParams,
270 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
271 uint32_t aMaxSize, uint32_t* aSizeUsed,
272 mozilla::ipc::ChildToParentStreamActorManager* aManager) {
273 SerializeInternal(aParams, aFileDescriptors, aDelayedStart, aMaxSize,
274 aSizeUsed, aManager);
275 }
276
277 template <typename M>
SerializeInternal(mozilla::ipc::InputStreamParams & aParams,FileDescriptorArray & aFileDescriptors,bool aDelayedStart,uint32_t aMaxSize,uint32_t * aSizeUsed,M * aManager)278 void InputStreamLengthWrapper::SerializeInternal(
279 mozilla::ipc::InputStreamParams& aParams,
280 FileDescriptorArray& aFileDescriptors, bool aDelayedStart,
281 uint32_t aMaxSize, uint32_t* aSizeUsed, M* aManager) {
282 MOZ_ASSERT(mInputStream);
283 MOZ_ASSERT(mWeakIPCSerializableInputStream);
284
285 InputStreamLengthWrapperParams params;
286 InputStreamHelper::SerializeInputStream(mInputStream, params.stream(),
287 aFileDescriptors, aDelayedStart,
288 aMaxSize, aSizeUsed, aManager);
289 params.length() = mLength;
290 params.consumed() = mConsumed;
291
292 aParams = params;
293 }
294
Deserialize(const mozilla::ipc::InputStreamParams & aParams,const FileDescriptorArray & aFileDescriptors)295 bool InputStreamLengthWrapper::Deserialize(
296 const mozilla::ipc::InputStreamParams& aParams,
297 const FileDescriptorArray& aFileDescriptors) {
298 MOZ_ASSERT(!mInputStream);
299 MOZ_ASSERT(!mWeakIPCSerializableInputStream);
300
301 if (aParams.type() != InputStreamParams::TInputStreamLengthWrapperParams) {
302 NS_ERROR("Received unknown parameters from the other process!");
303 return false;
304 }
305
306 const InputStreamLengthWrapperParams& params =
307 aParams.get_InputStreamLengthWrapperParams();
308
309 nsCOMPtr<nsIInputStream> stream = InputStreamHelper::DeserializeInputStream(
310 params.stream(), aFileDescriptors);
311 if (!stream) {
312 NS_WARNING("Deserialize failed!");
313 return false;
314 }
315
316 SetSourceStream(stream.forget());
317
318 mLength = params.length();
319 mConsumed = params.consumed();
320
321 return true;
322 }
323
324 // nsISeekableStream
325
326 NS_IMETHODIMP
Seek(int32_t aWhence,int64_t aOffset)327 InputStreamLengthWrapper::Seek(int32_t aWhence, int64_t aOffset) {
328 NS_ENSURE_STATE(mInputStream);
329 NS_ENSURE_STATE(mWeakSeekableInputStream);
330
331 mConsumed = true;
332 return mWeakSeekableInputStream->Seek(aWhence, aOffset);
333 }
334
335 NS_IMETHODIMP
SetEOF()336 InputStreamLengthWrapper::SetEOF() {
337 NS_ENSURE_STATE(mInputStream);
338 NS_ENSURE_STATE(mWeakSeekableInputStream);
339
340 mConsumed = true;
341 return mWeakSeekableInputStream->SetEOF();
342 }
343
344 // nsITellableStream
345
346 NS_IMETHODIMP
Tell(int64_t * aResult)347 InputStreamLengthWrapper::Tell(int64_t* aResult) {
348 NS_ENSURE_STATE(mInputStream);
349 NS_ENSURE_STATE(mWeakTellableInputStream);
350
351 return mWeakTellableInputStream->Tell(aResult);
352 }
353
354 // nsIInputStreamLength
355
356 NS_IMETHODIMP
Length(int64_t * aLength)357 InputStreamLengthWrapper::Length(int64_t* aLength) {
358 NS_ENSURE_STATE(mInputStream);
359 *aLength = mLength;
360 return NS_OK;
361 }
362
363 } // namespace mozilla
364