Line data Source code
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 file,
5 : * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 :
7 : #include "FileSnapshot.h"
8 :
9 : #include "IDBDatabase.h"
10 : #include "IDBFileHandle.h"
11 : #include "IDBMutableFile.h"
12 : #include "mozilla/Assertions.h"
13 : #include "nsIAsyncInputStream.h"
14 : #include "nsICloneableInputStream.h"
15 : #include "nsIIPCSerializableInputStream.h"
16 :
17 : namespace mozilla {
18 : namespace dom {
19 : namespace indexedDB {
20 :
21 : using namespace mozilla::ipc;
22 :
23 : namespace {
24 :
25 : class StreamWrapper final
26 : : public nsIAsyncInputStream
27 : , public nsIInputStreamCallback
28 : , public nsICloneableInputStream
29 : , public nsIIPCSerializableInputStream
30 : {
31 : class CloseRunnable;
32 :
33 : nsCOMPtr<nsIEventTarget> mOwningThread;
34 : nsCOMPtr<nsIInputStream> mInputStream;
35 : RefPtr<IDBFileHandle> mFileHandle;
36 : bool mFinished;
37 :
38 : // This is needed to call OnInputStreamReady() with the correct inputStream.
39 : nsCOMPtr<nsIInputStreamCallback> mAsyncWaitCallback;
40 :
41 : public:
42 0 : StreamWrapper(nsIInputStream* aInputStream,
43 : IDBFileHandle* aFileHandle)
44 0 : : mOwningThread(aFileHandle->GetMutableFile()->Database()->EventTarget())
45 : , mInputStream(aInputStream)
46 : , mFileHandle(aFileHandle)
47 0 : , mFinished(false)
48 : {
49 0 : AssertIsOnOwningThread();
50 0 : MOZ_ASSERT(aInputStream);
51 0 : MOZ_ASSERT(aFileHandle);
52 0 : aFileHandle->AssertIsOnOwningThread();
53 :
54 0 : mFileHandle->OnNewRequest();
55 0 : }
56 :
57 : private:
58 : virtual ~StreamWrapper();
59 :
60 : bool
61 0 : IsOnOwningThread() const
62 : {
63 0 : MOZ_ASSERT(mOwningThread);
64 :
65 : bool current;
66 0 : return NS_SUCCEEDED(mOwningThread->
67 0 : IsOnCurrentThread(¤t)) && current;
68 : }
69 :
70 : void
71 0 : AssertIsOnOwningThread() const
72 : {
73 0 : MOZ_ASSERT(IsOnOwningThread());
74 0 : }
75 :
76 : void
77 0 : Finish()
78 : {
79 0 : AssertIsOnOwningThread();
80 :
81 0 : if (mFinished) {
82 0 : return;
83 : }
84 :
85 0 : mFinished = true;
86 :
87 0 : mFileHandle->OnRequestFinished(/* aActorDestroyedNormally */ true);
88 : }
89 :
90 : void
91 0 : Destroy()
92 : {
93 0 : if (IsOnOwningThread()) {
94 0 : delete this;
95 0 : return;
96 : }
97 :
98 : RefPtr<Runnable> destroyRunnable =
99 0 : NewNonOwningRunnableMethod("StreamWrapper::Destroy",
100 : this,
101 0 : &StreamWrapper::Destroy);
102 :
103 0 : MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(destroyRunnable,
104 : NS_DISPATCH_NORMAL));
105 : }
106 :
107 : bool
108 0 : IsCloneableInputStream() const
109 : {
110 : nsCOMPtr<nsICloneableInputStream> stream =
111 0 : do_QueryInterface(mInputStream);
112 0 : return !!stream;
113 : }
114 :
115 : bool
116 0 : IsIPCSerializableInputStream() const
117 : {
118 : nsCOMPtr<nsIIPCSerializableInputStream> stream =
119 0 : do_QueryInterface(mInputStream);
120 0 : return !!stream;
121 : }
122 :
123 : bool
124 0 : IsAsyncInputStream() const
125 : {
126 0 : nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
127 0 : return !!stream;
128 : }
129 :
130 : NS_DECL_THREADSAFE_ISUPPORTS
131 : NS_DECL_NSIINPUTSTREAM
132 : NS_DECL_NSIASYNCINPUTSTREAM
133 : NS_DECL_NSIINPUTSTREAMCALLBACK
134 : NS_DECL_NSICLONEABLEINPUTSTREAM
135 : NS_DECL_NSIIPCSERIALIZABLEINPUTSTREAM
136 : };
137 :
138 : class StreamWrapper::CloseRunnable final
139 : : public Runnable
140 : {
141 : friend class StreamWrapper;
142 :
143 : RefPtr<StreamWrapper> mStreamWrapper;
144 :
145 : public:
146 : NS_DECL_ISUPPORTS_INHERITED
147 :
148 : private:
149 : explicit
150 0 : CloseRunnable(StreamWrapper* aStreamWrapper)
151 0 : : Runnable("StreamWrapper::CloseRunnable")
152 0 : , mStreamWrapper(aStreamWrapper)
153 0 : { }
154 :
155 0 : ~CloseRunnable()
156 0 : { }
157 :
158 : NS_IMETHOD
159 : Run() override;
160 : };
161 :
162 : } // anonymous namespace
163 :
164 0 : BlobImplSnapshot::BlobImplSnapshot(BlobImpl* aFileImpl,
165 0 : IDBFileHandle* aFileHandle)
166 0 : : mBlobImpl(aFileImpl)
167 : {
168 0 : MOZ_ASSERT(aFileImpl);
169 0 : MOZ_ASSERT(aFileHandle);
170 :
171 : mFileHandle =
172 0 : do_GetWeakReference(NS_ISUPPORTS_CAST(EventTarget*, aFileHandle));
173 0 : }
174 :
175 0 : BlobImplSnapshot::BlobImplSnapshot(BlobImpl* aFileImpl,
176 0 : nsIWeakReference* aFileHandle)
177 : : mBlobImpl(aFileImpl)
178 0 : , mFileHandle(aFileHandle)
179 : {
180 0 : MOZ_ASSERT(aFileImpl);
181 0 : MOZ_ASSERT(aFileHandle);
182 0 : }
183 :
184 0 : BlobImplSnapshot::~BlobImplSnapshot()
185 : {
186 0 : }
187 :
188 0 : NS_IMPL_ISUPPORTS_INHERITED(BlobImplSnapshot, BlobImpl, PIBlobImplSnapshot)
189 :
190 : already_AddRefed<BlobImpl>
191 0 : BlobImplSnapshot::CreateSlice(uint64_t aStart,
192 : uint64_t aLength,
193 : const nsAString& aContentType,
194 : ErrorResult& aRv)
195 : {
196 : RefPtr<BlobImpl> blobImpl =
197 0 : mBlobImpl->CreateSlice(aStart, aLength, aContentType, aRv);
198 :
199 0 : if (NS_WARN_IF(aRv.Failed())) {
200 0 : return nullptr;
201 : }
202 :
203 0 : blobImpl = new BlobImplSnapshot(blobImpl, mFileHandle);
204 0 : return blobImpl.forget();
205 : }
206 :
207 : void
208 0 : BlobImplSnapshot::GetInternalStream(nsIInputStream** aStream, ErrorResult& aRv)
209 : {
210 0 : nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
211 0 : RefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
212 0 : if (!fileHandle || !fileHandle->IsOpen()) {
213 0 : aRv.Throw(NS_ERROR_DOM_FILEHANDLE_INACTIVE_ERR);
214 0 : return;
215 : }
216 :
217 0 : nsCOMPtr<nsIInputStream> stream;
218 0 : mBlobImpl->GetInternalStream(getter_AddRefs(stream), aRv);
219 0 : if (NS_WARN_IF(aRv.Failed())) {
220 0 : return;
221 : }
222 :
223 0 : RefPtr<StreamWrapper> wrapper = new StreamWrapper(stream, fileHandle);
224 :
225 0 : wrapper.forget(aStream);
226 : }
227 :
228 : BlobImpl*
229 0 : BlobImplSnapshot::GetBlobImpl() const
230 : {
231 0 : nsCOMPtr<EventTarget> et = do_QueryReferent(mFileHandle);
232 0 : RefPtr<IDBFileHandle> fileHandle = static_cast<IDBFileHandle*>(et.get());
233 0 : if (!fileHandle || !fileHandle->IsOpen()) {
234 0 : return nullptr;
235 : }
236 :
237 0 : return mBlobImpl;
238 : }
239 :
240 0 : StreamWrapper::~StreamWrapper()
241 : {
242 0 : AssertIsOnOwningThread();
243 :
244 0 : Finish();
245 0 : }
246 :
247 0 : NS_IMPL_ADDREF(StreamWrapper)
248 0 : NS_IMPL_RELEASE_WITH_DESTROY(StreamWrapper, Destroy())
249 :
250 0 : NS_INTERFACE_MAP_BEGIN(StreamWrapper)
251 0 : NS_INTERFACE_MAP_ENTRY(nsIInputStream)
252 0 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIAsyncInputStream,
253 : IsAsyncInputStream())
254 0 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIInputStreamCallback,
255 : IsAsyncInputStream())
256 0 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsICloneableInputStream,
257 : IsCloneableInputStream())
258 0 : NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream,
259 : IsIPCSerializableInputStream())
260 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream)
261 0 : NS_INTERFACE_MAP_END
262 :
263 : NS_IMETHODIMP
264 0 : StreamWrapper::Close()
265 : {
266 0 : RefPtr<CloseRunnable> closeRunnable = new CloseRunnable(this);
267 :
268 0 : MOZ_ALWAYS_SUCCEEDS(mOwningThread->Dispatch(closeRunnable,
269 : NS_DISPATCH_NORMAL));
270 :
271 0 : return NS_OK;
272 : }
273 :
274 : NS_IMETHODIMP
275 0 : StreamWrapper::Available(uint64_t* _retval)
276 : {
277 0 : return mInputStream->Available(_retval);
278 : }
279 :
280 : NS_IMETHODIMP
281 0 : StreamWrapper::Read(char* aBuf, uint32_t aCount, uint32_t* _retval)
282 : {
283 0 : return mInputStream->Read(aBuf, aCount, _retval);
284 : }
285 :
286 : NS_IMETHODIMP
287 0 : StreamWrapper::ReadSegments(nsWriteSegmentFun aWriter, void* aClosure,
288 : uint32_t aCount, uint32_t* _retval)
289 : {
290 0 : return mInputStream->ReadSegments(aWriter, aClosure, aCount, _retval);
291 : }
292 :
293 : NS_IMETHODIMP
294 0 : StreamWrapper::IsNonBlocking(bool* _retval)
295 : {
296 0 : return mInputStream->IsNonBlocking(_retval);
297 : }
298 :
299 : void
300 0 : StreamWrapper::Serialize(InputStreamParams& aParams,
301 : FileDescriptorArray& aFileDescriptors)
302 : {
303 : nsCOMPtr<nsIIPCSerializableInputStream> stream =
304 0 : do_QueryInterface(mInputStream);
305 :
306 0 : if (stream) {
307 0 : stream->Serialize(aParams, aFileDescriptors);
308 : }
309 0 : }
310 :
311 : bool
312 0 : StreamWrapper::Deserialize(const InputStreamParams& aParams,
313 : const FileDescriptorArray& aFileDescriptors)
314 : {
315 0 : MOZ_CRASH("This method should never be called");
316 : return false;
317 : }
318 :
319 : Maybe<uint64_t>
320 0 : StreamWrapper::ExpectedSerializedLength()
321 : {
322 : nsCOMPtr<nsIIPCSerializableInputStream> stream =
323 0 : do_QueryInterface(mInputStream);
324 :
325 0 : if (stream) {
326 0 : return stream->ExpectedSerializedLength();
327 : }
328 0 : return Nothing();
329 : }
330 :
331 : NS_IMETHODIMP
332 0 : StreamWrapper::CloseWithStatus(nsresult aStatus)
333 : {
334 0 : nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
335 0 : if (!stream) {
336 0 : return NS_ERROR_NO_INTERFACE;
337 : }
338 :
339 0 : nsresult rv = stream->CloseWithStatus(aStatus);
340 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
341 0 : return rv;
342 : }
343 :
344 0 : return Close();
345 : }
346 :
347 : NS_IMETHODIMP
348 0 : StreamWrapper::AsyncWait(nsIInputStreamCallback* aCallback,
349 : uint32_t aFlags,
350 : uint32_t aRequestedCount,
351 : nsIEventTarget* aEventTarget)
352 : {
353 0 : nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
354 0 : if (!stream) {
355 0 : return NS_ERROR_NO_INTERFACE;
356 : }
357 :
358 0 : if (mAsyncWaitCallback && aCallback) {
359 0 : return NS_ERROR_FAILURE;
360 : }
361 :
362 0 : mAsyncWaitCallback = aCallback;
363 :
364 0 : if (!mAsyncWaitCallback) {
365 0 : return NS_OK;
366 : }
367 :
368 0 : return stream->AsyncWait(this, aFlags, aRequestedCount, aEventTarget);
369 : }
370 :
371 : // nsIInputStreamCallback
372 :
373 : NS_IMETHODIMP
374 0 : StreamWrapper::OnInputStreamReady(nsIAsyncInputStream* aStream)
375 : {
376 0 : nsCOMPtr<nsIAsyncInputStream> stream = do_QueryInterface(mInputStream);
377 0 : if (!stream) {
378 0 : return NS_ERROR_NO_INTERFACE;
379 : }
380 :
381 : // We have been canceled in the meanwhile.
382 0 : if (!mAsyncWaitCallback) {
383 0 : return NS_OK;
384 : }
385 :
386 0 : nsCOMPtr<nsIInputStreamCallback> callback;
387 0 : callback.swap(mAsyncWaitCallback);
388 :
389 0 : return callback->OnInputStreamReady(this);
390 : }
391 :
392 : // nsICloneableInputStream
393 :
394 : NS_IMETHODIMP
395 0 : StreamWrapper::GetCloneable(bool* aCloneable)
396 : {
397 0 : nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mInputStream);
398 0 : if (!stream) {
399 0 : *aCloneable = false;
400 0 : return NS_ERROR_NO_INTERFACE;
401 : }
402 :
403 0 : return stream->GetCloneable(aCloneable);
404 : }
405 :
406 : NS_IMETHODIMP
407 0 : StreamWrapper::Clone(nsIInputStream** aResult)
408 : {
409 0 : nsCOMPtr<nsICloneableInputStream> stream = do_QueryInterface(mInputStream);
410 0 : if (!stream) {
411 0 : return NS_ERROR_NO_INTERFACE;
412 : }
413 :
414 0 : return stream->Clone(aResult);
415 : }
416 :
417 0 : NS_IMPL_ISUPPORTS_INHERITED0(StreamWrapper::CloseRunnable,
418 : Runnable)
419 :
420 : NS_IMETHODIMP
421 0 : StreamWrapper::
422 : CloseRunnable::Run()
423 : {
424 0 : mStreamWrapper->Finish();
425 :
426 0 : return NS_OK;
427 : }
428 :
429 : } // namespace indexedDB
430 : } // namespace dom
431 : } // namespace mozilla
|