/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 |