Coverage Report

Created: 2018-09-25 14:53

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