Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/netwerk/base/PartiallySeekableInputStream.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2
/* This Source Code Form is subject to the terms of the Mozilla Public
3
 * License, v. 2.0. If a copy of the MPL was not distributed with this
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "PartiallySeekableInputStream.h"
7
#include "mozilla/ipc/InputStreamUtils.h"
8
#include "nsISeekableStream.h"
9
#include "nsStreamUtils.h"
10
11
namespace mozilla {
12
namespace net {
13
14
NS_IMPL_ADDREF(PartiallySeekableInputStream);
15
NS_IMPL_RELEASE(PartiallySeekableInputStream);
16
17
0
NS_INTERFACE_MAP_BEGIN(PartiallySeekableInputStream)
18
0
  NS_INTERFACE_MAP_ENTRY(nsIInputStream)
19
0
  NS_INTERFACE_MAP_ENTRY(nsISeekableStream)
20
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
21
0
                                     mWeakCloneableInputStream)
22
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
23
0
                                     mWeakIPCSerializableInputStream)
24
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
25
0
                                     mWeakAsyncInputStream)
26
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
27
0
                                     mWeakAsyncInputStream)
28
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLength,
29
0
                                     mWeakInputStreamLength)
30
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStreamLength,
31
0
                                     mWeakAsyncInputStreamLength)
32
0
  NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamLengthCallback,
33
0
                                     mWeakAsyncInputStreamLength)
34
0
  NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
35
0
NS_INTERFACE_MAP_END
36
37
PartiallySeekableInputStream::PartiallySeekableInputStream(already_AddRefed<nsIInputStream> aInputStream,
38
                                                           uint64_t aBufferSize)
39
  : mInputStream(std::move(aInputStream))
40
  , mWeakCloneableInputStream(nullptr)
41
  , mWeakIPCSerializableInputStream(nullptr)
42
  , mWeakAsyncInputStream(nullptr)
43
  , mWeakInputStreamLength(nullptr)
44
  , mWeakAsyncInputStreamLength(nullptr)
45
  , mBufferSize(aBufferSize)
46
  , mPos(0)
47
  , mClosed(false)
48
  , mMutex("PartiallySeekableInputStream::mMutex")
49
0
{
50
0
  Init();
51
0
}
52
53
PartiallySeekableInputStream::PartiallySeekableInputStream(already_AddRefed<nsIInputStream> aClonedBaseStream,
54
                                                           PartiallySeekableInputStream* aClonedFrom)
55
  : mInputStream(std::move(aClonedBaseStream))
56
  , mWeakCloneableInputStream(nullptr)
57
  , mWeakIPCSerializableInputStream(nullptr)
58
  , mWeakAsyncInputStream(nullptr)
59
  , mCachedBuffer(aClonedFrom->mCachedBuffer)
60
  , mBufferSize(aClonedFrom->mBufferSize)
61
  , mPos(aClonedFrom->mPos)
62
  , mClosed(aClonedFrom->mClosed)
63
  , mMutex("PartiallySeekableInputStream::mMutex")
64
0
{
65
0
  Init();
66
0
}
67
68
void
69
PartiallySeekableInputStream::Init()
70
0
{
71
0
  MOZ_ASSERT(mInputStream);
72
0
73
#ifdef DEBUG
74
  nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(mInputStream);
75
  MOZ_ASSERT(!seekableStream);
76
#endif
77
78
0
  nsCOMPtr<nsICloneableInputStream> cloneableStream =
79
0
    do_QueryInterface(mInputStream);
80
0
  if (cloneableStream && SameCOMIdentity(mInputStream, cloneableStream)) {
81
0
    mWeakCloneableInputStream = cloneableStream;
82
0
  }
83
0
84
0
  nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
85
0
    do_QueryInterface(mInputStream);
86
0
  if (serializableStream &&
87
0
      SameCOMIdentity(mInputStream, serializableStream)) {
88
0
    mWeakIPCSerializableInputStream = serializableStream;
89
0
  }
90
0
91
0
  nsCOMPtr<nsIAsyncInputStream> asyncInputStream =
92
0
    do_QueryInterface(mInputStream);
93
0
  if (asyncInputStream && SameCOMIdentity(mInputStream, asyncInputStream)) {
94
0
    mWeakAsyncInputStream = asyncInputStream;
95
0
  }
96
0
97
0
  nsCOMPtr<nsIInputStreamLength> inputStreamLength =
98
0
    do_QueryInterface(mInputStream);
99
0
  if (inputStreamLength && SameCOMIdentity(mInputStream, inputStreamLength)) {
100
0
    mWeakInputStreamLength = inputStreamLength;
101
0
  }
102
0
103
0
  nsCOMPtr<nsIAsyncInputStreamLength> asyncInputStreamLength =
104
0
    do_QueryInterface(mInputStream);
105
0
  if (asyncInputStreamLength &&
106
0
      SameCOMIdentity(mInputStream, asyncInputStreamLength)) {
107
0
    mWeakAsyncInputStreamLength = asyncInputStreamLength;
108
0
  }
109
0
}
110
111
NS_IMETHODIMP
112
PartiallySeekableInputStream::Close()
113
0
{
114
0
  mInputStream->Close();
115
0
  mCachedBuffer.Clear();
116
0
  mPos = 0;
117
0
  mClosed = true;
118
0
  return NS_OK;
119
0
}
120
121
// nsIInputStream interface
122
123
NS_IMETHODIMP
124
PartiallySeekableInputStream::Available(uint64_t* aLength)
125
0
{
126
0
  if (mClosed) {
127
0
    return NS_BASE_STREAM_CLOSED;
128
0
  }
129
0
130
0
  nsresult rv = mInputStream->Available(aLength);
131
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
132
0
    return rv;
133
0
  }
134
0
135
0
  if (mPos < mCachedBuffer.Length()) {
136
0
    *aLength += mCachedBuffer.Length() - mPos;
137
0
  }
138
0
139
0
  return NS_OK;
140
0
}
141
142
NS_IMETHODIMP
143
PartiallySeekableInputStream::Read(char* aBuffer, uint32_t aCount,
144
                                   uint32_t* aReadCount)
145
0
{
146
0
  *aReadCount = 0;
147
0
148
0
  if (mClosed) {
149
0
    return NS_OK;
150
0
  }
151
0
152
0
  uint32_t byteRead = 0;
153
0
154
0
  if (mPos < mCachedBuffer.Length()) {
155
0
    // We are reading from the cached buffer.
156
0
    byteRead = XPCOM_MIN(mCachedBuffer.Length() - mPos, (uint64_t)aCount);
157
0
    memcpy(aBuffer, mCachedBuffer.Elements() + mPos, byteRead);
158
0
    *aReadCount = byteRead;
159
0
    mPos += byteRead;
160
0
  }
161
0
162
0
  if (byteRead < aCount) {
163
0
    MOZ_ASSERT(mPos >= mCachedBuffer.Length());
164
0
    MOZ_ASSERT_IF(mPos > mCachedBuffer.Length(),
165
0
                  mCachedBuffer.Length() == mBufferSize);
166
0
167
0
    // We can read from the stream.
168
0
    uint32_t byteWritten;
169
0
    nsresult rv = mInputStream->Read(aBuffer + byteRead, aCount - byteRead,
170
0
                                     &byteWritten);
171
0
    if (NS_WARN_IF(NS_FAILED(rv)) || byteWritten == 0) {
172
0
      return rv;
173
0
    }
174
0
175
0
    *aReadCount += byteWritten;
176
0
177
0
    // Maybe we have to cache something.
178
0
    if (mPos < mBufferSize) {
179
0
      uint32_t size = XPCOM_MIN(mPos + byteWritten, mBufferSize);
180
0
      mCachedBuffer.SetLength(size);
181
0
      memcpy(mCachedBuffer.Elements() + mPos, aBuffer + byteRead, size - mPos);
182
0
    }
183
0
184
0
    mPos += byteWritten;
185
0
  }
186
0
187
0
  return NS_OK;
188
0
}
189
190
NS_IMETHODIMP
191
PartiallySeekableInputStream::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
192
                                           uint32_t aCount, uint32_t *aResult)
193
0
{
194
0
  return NS_ERROR_NOT_IMPLEMENTED;
195
0
}
196
197
NS_IMETHODIMP
198
PartiallySeekableInputStream::IsNonBlocking(bool* aNonBlocking)
199
0
{
200
0
  return mInputStream->IsNonBlocking(aNonBlocking);
201
0
}
202
203
// nsICloneableInputStream interface
204
205
NS_IMETHODIMP
206
PartiallySeekableInputStream::GetCloneable(bool* aCloneable)
207
0
{
208
0
  NS_ENSURE_STATE(mWeakCloneableInputStream);
209
0
210
0
  return mWeakCloneableInputStream->GetCloneable(aCloneable);
211
0
}
212
213
NS_IMETHODIMP
214
PartiallySeekableInputStream::Clone(nsIInputStream** aResult)
215
0
{
216
0
  NS_ENSURE_STATE(mWeakCloneableInputStream);
217
0
218
0
  nsCOMPtr<nsIInputStream> clonedStream;
219
0
  nsresult rv = mWeakCloneableInputStream->Clone(getter_AddRefs(clonedStream));
220
0
  if (NS_WARN_IF(NS_FAILED(rv))) {
221
0
    return rv;
222
0
  }
223
0
224
0
  nsCOMPtr<nsIInputStream> stream =
225
0
    new PartiallySeekableInputStream(clonedStream.forget(), this);
226
0
227
0
  stream.forget(aResult);
228
0
  return NS_OK;
229
0
}
230
231
// nsIAsyncInputStream interface
232
233
NS_IMETHODIMP
234
PartiallySeekableInputStream::CloseWithStatus(nsresult aStatus)
235
0
{
236
0
  NS_ENSURE_STATE(mWeakAsyncInputStream);
237
0
238
0
  return mWeakAsyncInputStream->CloseWithStatus(aStatus);
239
0
}
240
241
NS_IMETHODIMP
242
PartiallySeekableInputStream::AsyncWait(nsIInputStreamCallback* aCallback,
243
                                        uint32_t aFlags,
244
                                        uint32_t aRequestedCount,
245
                                        nsIEventTarget* aEventTarget)
246
0
{
247
0
  if (mClosed) {
248
0
    return NS_BASE_STREAM_CLOSED;
249
0
  }
250
0
251
0
  NS_ENSURE_STATE(mWeakAsyncInputStream);
252
0
253
0
  nsCOMPtr<nsIInputStreamCallback> callback = aCallback ? this : nullptr;
254
0
  {
255
0
    MutexAutoLock lock(mMutex);
256
0
    if (mAsyncWaitCallback && aCallback) {
257
0
      return NS_ERROR_FAILURE;
258
0
    }
259
0
260
0
    mAsyncWaitCallback = aCallback;
261
0
  }
262
0
263
0
  return mWeakAsyncInputStream->AsyncWait(callback, aFlags, aRequestedCount,
264
0
                                          aEventTarget);
265
0
}
266
267
// nsIInputStreamCallback
268
269
NS_IMETHODIMP
270
PartiallySeekableInputStream::OnInputStreamReady(nsIAsyncInputStream* aStream)
271
0
{
272
0
  MOZ_ASSERT(mWeakAsyncInputStream);
273
0
  MOZ_ASSERT(mWeakAsyncInputStream == aStream);
274
0
275
0
  nsCOMPtr<nsIInputStreamCallback> callback;
276
0
277
0
  {
278
0
    MutexAutoLock lock(mMutex);
279
0
280
0
    // We have been canceled in the meanwhile.
281
0
    if (!mAsyncWaitCallback) {
282
0
      return NS_OK;
283
0
    }
284
0
285
0
    callback.swap(mAsyncWaitCallback);
286
0
  }
287
0
288
0
  MOZ_ASSERT(callback);
289
0
  return callback->OnInputStreamReady(this);
290
0
}
291
292
// nsIIPCSerializableInputStream
293
294
void
295
PartiallySeekableInputStream::Serialize(mozilla::ipc::InputStreamParams& aParams,
296
                                        FileDescriptorArray& aFileDescriptors)
297
0
{
298
0
  MOZ_ASSERT(mWeakIPCSerializableInputStream);
299
0
  MOZ_DIAGNOSTIC_ASSERT(mCachedBuffer.IsEmpty());
300
0
  mozilla::ipc::InputStreamHelper::SerializeInputStream(mInputStream, aParams,
301
0
                                                        aFileDescriptors);
302
0
}
303
304
bool
305
PartiallySeekableInputStream::Deserialize(const mozilla::ipc::InputStreamParams& aParams,
306
                                          const FileDescriptorArray& aFileDescriptors)
307
0
{
308
0
  MOZ_CRASH("This method should never be called!");
309
0
  return false;
310
0
}
311
312
mozilla::Maybe<uint64_t>
313
PartiallySeekableInputStream::ExpectedSerializedLength()
314
0
{
315
0
  if (!mWeakIPCSerializableInputStream) {
316
0
    return mozilla::Nothing();
317
0
  }
318
0
319
0
  return mWeakIPCSerializableInputStream->ExpectedSerializedLength();
320
0
}
321
322
// nsISeekableStream
323
324
NS_IMETHODIMP
325
PartiallySeekableInputStream::Seek(int32_t aWhence, int64_t aOffset)
326
0
{
327
0
  if (mClosed) {
328
0
    return NS_BASE_STREAM_CLOSED;
329
0
  }
330
0
331
0
  int64_t offset;
332
0
333
0
  switch (aWhence) {
334
0
    case NS_SEEK_SET:
335
0
      offset = aOffset;
336
0
      break;
337
0
    case NS_SEEK_CUR:
338
0
      offset = mPos + aOffset;
339
0
      break;
340
0
    case NS_SEEK_END: {
341
0
      return NS_ERROR_NOT_IMPLEMENTED;
342
0
    }
343
0
    default:
344
0
      return NS_ERROR_ILLEGAL_VALUE;
345
0
  }
346
0
347
0
  if (offset < 0) {
348
0
    return NS_ERROR_ILLEGAL_VALUE;
349
0
  }
350
0
351
0
  if ((uint64_t)offset >= mCachedBuffer.Length() || mPos > mBufferSize) {
352
0
    return NS_ERROR_NOT_IMPLEMENTED;
353
0
  }
354
0
355
0
  mPos = offset;
356
0
  return NS_OK;
357
0
}
358
359
NS_IMETHODIMP
360
PartiallySeekableInputStream::Tell(int64_t *aResult)
361
0
{
362
0
  if (mClosed) {
363
0
    return NS_BASE_STREAM_CLOSED;
364
0
  }
365
0
366
0
  *aResult = mPos;
367
0
  return NS_OK;
368
0
}
369
370
NS_IMETHODIMP
371
PartiallySeekableInputStream::SetEOF()
372
0
{
373
0
  return Close();
374
0
}
375
376
// nsIInputStreamLength
377
378
NS_IMETHODIMP
379
PartiallySeekableInputStream::Length(int64_t* aLength)
380
0
{
381
0
  NS_ENSURE_STATE(mWeakInputStreamLength);
382
0
  return mWeakInputStreamLength->Length(aLength);
383
0
}
384
385
// nsIAsyncInputStreamLength
386
387
NS_IMETHODIMP
388
PartiallySeekableInputStream::AsyncLengthWait(nsIInputStreamLengthCallback* aCallback,
389
                                              nsIEventTarget* aEventTarget)
390
0
{
391
0
  NS_ENSURE_STATE(mWeakAsyncInputStreamLength);
392
0
393
0
  nsCOMPtr<nsIInputStreamLengthCallback> callback = aCallback ? this : nullptr;
394
0
  {
395
0
    MutexAutoLock lock(mMutex);
396
0
    mAsyncInputStreamLengthCallback = aCallback;
397
0
  }
398
0
399
0
  return mWeakAsyncInputStreamLength->AsyncLengthWait(callback, aEventTarget);
400
0
}
401
402
NS_IMETHODIMP
403
PartiallySeekableInputStream::OnInputStreamLengthReady(nsIAsyncInputStreamLength* aStream,
404
                                                       int64_t aLength)
405
0
{
406
0
  nsCOMPtr<nsIInputStreamLengthCallback> callback;
407
0
  {
408
0
    MutexAutoLock lock(mMutex);
409
0
    // We have been canceled in the meanwhile.
410
0
    if (!mAsyncInputStreamLengthCallback) {
411
0
      return NS_OK;
412
0
    }
413
0
414
0
    callback.swap(mAsyncInputStreamLengthCallback);
415
0
  }
416
0
417
0
  return callback->OnInputStreamLengthReady(this, aLength);
418
0
}
419
420
} // net namespace
421
} // mozilla namespace