Source code

Revision control

Other Tools

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