|
1 /* This Source Code Form is subject to the terms of the Mozilla Public |
|
2 * License, v. 2.0. If a copy of the MPL was not distributed with this |
|
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
|
4 |
|
5 #include "Blob.h" |
|
6 |
|
7 #include "ContentChild.h" |
|
8 #include "ContentParent.h" |
|
9 #include "FileDescriptorSetChild.h" |
|
10 #include "jsapi.h" |
|
11 #include "mozilla/Assertions.h" |
|
12 #include "mozilla/DebugOnly.h" |
|
13 #include "mozilla/Monitor.h" |
|
14 #include "mozilla/unused.h" |
|
15 #include "mozilla/dom/PBlobStreamChild.h" |
|
16 #include "mozilla/dom/PBlobStreamParent.h" |
|
17 #include "mozilla/dom/PFileDescriptorSetParent.h" |
|
18 #include "mozilla/ipc/InputStreamUtils.h" |
|
19 #include "nsCOMPtr.h" |
|
20 #include "nsDOMFile.h" |
|
21 #include "nsIDOMFile.h" |
|
22 #include "nsIInputStream.h" |
|
23 #include "nsIIPCSerializableInputStream.h" |
|
24 #include "nsIMultiplexInputStream.h" |
|
25 #include "nsIRemoteBlob.h" |
|
26 #include "nsISeekableStream.h" |
|
27 #include "nsNetCID.h" |
|
28 #include "nsProxyRelease.h" |
|
29 #include "nsThreadUtils.h" |
|
30 |
|
31 #define PRIVATE_REMOTE_INPUT_STREAM_IID \ |
|
32 {0x30c7699f, 0x51d2, 0x48c8, {0xad, 0x56, 0xc0, 0x16, 0xd7, 0x6f, 0x71, 0x27}} |
|
33 |
|
34 using namespace mozilla; |
|
35 using namespace mozilla::dom; |
|
36 using namespace mozilla::ipc; |
|
37 |
|
38 namespace { |
|
39 |
|
40 enum ActorType |
|
41 { |
|
42 ChildActor, |
|
43 ParentActor |
|
44 }; |
|
45 |
|
46 // Ensure that a nsCOMPtr/nsRefPtr is released on the main thread. |
|
47 template <template <class> class SmartPtr, class T> |
|
48 void |
|
49 ProxyReleaseToMainThread(SmartPtr<T>& aDoomed) |
|
50 { |
|
51 MOZ_ASSERT(!NS_IsMainThread()); |
|
52 |
|
53 nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
|
54 NS_ENSURE_TRUE_VOID(mainThread); |
|
55 |
|
56 if (NS_FAILED(NS_ProxyRelease(mainThread, aDoomed, true))) { |
|
57 NS_WARNING("Failed to proxy release to main thread!"); |
|
58 } |
|
59 } |
|
60 |
|
61 class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports |
|
62 { |
|
63 public: |
|
64 NS_DECLARE_STATIC_IID_ACCESSOR(PRIVATE_REMOTE_INPUT_STREAM_IID) |
|
65 |
|
66 // This will return the underlying stream. |
|
67 virtual nsIInputStream* |
|
68 BlockAndGetInternalStream() = 0; |
|
69 }; |
|
70 |
|
71 NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream, |
|
72 PRIVATE_REMOTE_INPUT_STREAM_IID) |
|
73 |
|
74 // This class exists to keep a blob alive at least as long as its internal |
|
75 // stream. |
|
76 class BlobInputStreamTether : public nsIMultiplexInputStream, |
|
77 public nsISeekableStream, |
|
78 public nsIIPCSerializableInputStream |
|
79 { |
|
80 nsCOMPtr<nsIInputStream> mStream; |
|
81 nsCOMPtr<nsIDOMBlob> mSourceBlob; |
|
82 |
|
83 nsIMultiplexInputStream* mWeakMultiplexStream; |
|
84 nsISeekableStream* mWeakSeekableStream; |
|
85 nsIIPCSerializableInputStream* mWeakSerializableStream; |
|
86 |
|
87 public: |
|
88 NS_DECL_THREADSAFE_ISUPPORTS |
|
89 NS_FORWARD_NSIINPUTSTREAM(mStream->) |
|
90 NS_FORWARD_SAFE_NSIMULTIPLEXINPUTSTREAM(mWeakMultiplexStream) |
|
91 NS_FORWARD_SAFE_NSISEEKABLESTREAM(mWeakSeekableStream) |
|
92 NS_FORWARD_SAFE_NSIIPCSERIALIZABLEINPUTSTREAM(mWeakSerializableStream) |
|
93 |
|
94 BlobInputStreamTether(nsIInputStream* aStream, nsIDOMBlob* aSourceBlob) |
|
95 : mStream(aStream), mSourceBlob(aSourceBlob), mWeakMultiplexStream(nullptr), |
|
96 mWeakSeekableStream(nullptr), mWeakSerializableStream(nullptr) |
|
97 { |
|
98 MOZ_ASSERT(aStream); |
|
99 MOZ_ASSERT(aSourceBlob); |
|
100 |
|
101 nsCOMPtr<nsIMultiplexInputStream> multiplexStream = |
|
102 do_QueryInterface(aStream); |
|
103 if (multiplexStream) { |
|
104 MOZ_ASSERT(SameCOMIdentity(aStream, multiplexStream)); |
|
105 mWeakMultiplexStream = multiplexStream; |
|
106 } |
|
107 |
|
108 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream); |
|
109 if (seekableStream) { |
|
110 MOZ_ASSERT(SameCOMIdentity(aStream, seekableStream)); |
|
111 mWeakSeekableStream = seekableStream; |
|
112 } |
|
113 |
|
114 nsCOMPtr<nsIIPCSerializableInputStream> serializableStream = |
|
115 do_QueryInterface(aStream); |
|
116 if (serializableStream) { |
|
117 MOZ_ASSERT(SameCOMIdentity(aStream, serializableStream)); |
|
118 mWeakSerializableStream = serializableStream; |
|
119 } |
|
120 } |
|
121 |
|
122 protected: |
|
123 virtual ~BlobInputStreamTether() |
|
124 { |
|
125 MOZ_ASSERT(mStream); |
|
126 MOZ_ASSERT(mSourceBlob); |
|
127 |
|
128 if (!NS_IsMainThread()) { |
|
129 mStream = nullptr; |
|
130 ProxyReleaseToMainThread(mSourceBlob); |
|
131 } |
|
132 } |
|
133 }; |
|
134 |
|
135 NS_IMPL_ADDREF(BlobInputStreamTether) |
|
136 NS_IMPL_RELEASE(BlobInputStreamTether) |
|
137 |
|
138 NS_INTERFACE_MAP_BEGIN(BlobInputStreamTether) |
|
139 NS_INTERFACE_MAP_ENTRY(nsIInputStream) |
|
140 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIMultiplexInputStream, |
|
141 mWeakMultiplexStream) |
|
142 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, mWeakSeekableStream) |
|
143 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsIIPCSerializableInputStream, |
|
144 mWeakSerializableStream) |
|
145 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) |
|
146 NS_INTERFACE_MAP_END |
|
147 |
|
148 class RemoteInputStream : public nsIInputStream, |
|
149 public nsISeekableStream, |
|
150 public nsIIPCSerializableInputStream, |
|
151 public IPrivateRemoteInputStream |
|
152 { |
|
153 mozilla::Monitor mMonitor; |
|
154 nsCOMPtr<nsIInputStream> mStream; |
|
155 nsCOMPtr<nsIDOMBlob> mSourceBlob; |
|
156 nsISeekableStream* mWeakSeekableStream; |
|
157 ActorType mOrigin; |
|
158 |
|
159 public: |
|
160 NS_DECL_THREADSAFE_ISUPPORTS |
|
161 |
|
162 RemoteInputStream(nsIDOMBlob* aSourceBlob, ActorType aOrigin) |
|
163 : mMonitor("RemoteInputStream.mMonitor"), mSourceBlob(aSourceBlob), |
|
164 mWeakSeekableStream(nullptr), mOrigin(aOrigin) |
|
165 { |
|
166 MOZ_ASSERT(NS_IsMainThread()); |
|
167 MOZ_ASSERT(aSourceBlob); |
|
168 } |
|
169 |
|
170 void |
|
171 Serialize(InputStreamParams& aParams, |
|
172 FileDescriptorArray& /* aFileDescriptors */) |
|
173 { |
|
174 nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob); |
|
175 MOZ_ASSERT(remote); |
|
176 |
|
177 if (mOrigin == ParentActor) { |
|
178 aParams = RemoteInputStreamParams( |
|
179 static_cast<PBlobParent*>(remote->GetPBlob()), nullptr); |
|
180 } else { |
|
181 MOZ_ASSERT(mOrigin == ChildActor); |
|
182 aParams = RemoteInputStreamParams( |
|
183 nullptr, static_cast<PBlobChild*>(remote->GetPBlob())); |
|
184 } |
|
185 } |
|
186 |
|
187 bool |
|
188 Deserialize(const InputStreamParams& aParams, |
|
189 const FileDescriptorArray& /* aFileDescriptors */) |
|
190 { |
|
191 // See InputStreamUtils.cpp to see how deserialization of a |
|
192 // RemoteInputStream is special-cased. |
|
193 MOZ_CRASH("RemoteInputStream should never be deserialized"); |
|
194 } |
|
195 |
|
196 void |
|
197 SetStream(nsIInputStream* aStream) |
|
198 { |
|
199 MOZ_ASSERT(NS_IsMainThread()); |
|
200 MOZ_ASSERT(aStream); |
|
201 |
|
202 nsCOMPtr<nsIInputStream> stream = aStream; |
|
203 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream); |
|
204 |
|
205 MOZ_ASSERT_IF(seekableStream, SameCOMIdentity(aStream, seekableStream)); |
|
206 |
|
207 { |
|
208 mozilla::MonitorAutoLock lock(mMonitor); |
|
209 |
|
210 MOZ_ASSERT(!mStream); |
|
211 MOZ_ASSERT(!mWeakSeekableStream); |
|
212 |
|
213 mStream.swap(stream); |
|
214 mWeakSeekableStream = seekableStream; |
|
215 |
|
216 mMonitor.Notify(); |
|
217 } |
|
218 } |
|
219 |
|
220 NS_IMETHOD |
|
221 Close() MOZ_OVERRIDE |
|
222 { |
|
223 nsresult rv = BlockAndWaitForStream(); |
|
224 NS_ENSURE_SUCCESS(rv, rv); |
|
225 |
|
226 nsCOMPtr<nsIDOMBlob> sourceBlob; |
|
227 mSourceBlob.swap(sourceBlob); |
|
228 |
|
229 rv = mStream->Close(); |
|
230 NS_ENSURE_SUCCESS(rv, rv); |
|
231 |
|
232 return NS_OK; |
|
233 } |
|
234 |
|
235 NS_IMETHOD |
|
236 Available(uint64_t* aAvailable) MOZ_OVERRIDE |
|
237 { |
|
238 // See large comment in FileInputStreamWrapper::Available. |
|
239 if (NS_IsMainThread()) { |
|
240 return NS_BASE_STREAM_CLOSED; |
|
241 } |
|
242 |
|
243 nsresult rv = BlockAndWaitForStream(); |
|
244 NS_ENSURE_SUCCESS(rv, rv); |
|
245 |
|
246 rv = mStream->Available(aAvailable); |
|
247 NS_ENSURE_SUCCESS(rv, rv); |
|
248 |
|
249 return NS_OK; |
|
250 } |
|
251 |
|
252 NS_IMETHOD |
|
253 Read(char* aBuffer, uint32_t aCount, uint32_t* aResult) MOZ_OVERRIDE |
|
254 { |
|
255 nsresult rv = BlockAndWaitForStream(); |
|
256 NS_ENSURE_SUCCESS(rv, rv); |
|
257 |
|
258 rv = mStream->Read(aBuffer, aCount, aResult); |
|
259 NS_ENSURE_SUCCESS(rv, rv); |
|
260 |
|
261 return NS_OK; |
|
262 } |
|
263 |
|
264 NS_IMETHOD |
|
265 ReadSegments(nsWriteSegmentFun aWriter, void* aClosure, uint32_t aCount, |
|
266 uint32_t* aResult) MOZ_OVERRIDE |
|
267 { |
|
268 nsresult rv = BlockAndWaitForStream(); |
|
269 NS_ENSURE_SUCCESS(rv, rv); |
|
270 |
|
271 rv = mStream->ReadSegments(aWriter, aClosure, aCount, aResult); |
|
272 NS_ENSURE_SUCCESS(rv, rv); |
|
273 |
|
274 return NS_OK; |
|
275 } |
|
276 |
|
277 NS_IMETHOD |
|
278 IsNonBlocking(bool* aNonBlocking) MOZ_OVERRIDE |
|
279 { |
|
280 NS_ENSURE_ARG_POINTER(aNonBlocking); |
|
281 |
|
282 *aNonBlocking = false; |
|
283 return NS_OK; |
|
284 } |
|
285 |
|
286 NS_IMETHOD |
|
287 Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE |
|
288 { |
|
289 nsresult rv = BlockAndWaitForStream(); |
|
290 NS_ENSURE_SUCCESS(rv, rv); |
|
291 |
|
292 if (!mWeakSeekableStream) { |
|
293 NS_WARNING("Underlying blob stream is not seekable!"); |
|
294 return NS_ERROR_NO_INTERFACE; |
|
295 } |
|
296 |
|
297 rv = mWeakSeekableStream->Seek(aWhence, aOffset); |
|
298 NS_ENSURE_SUCCESS(rv, rv); |
|
299 |
|
300 return NS_OK; |
|
301 } |
|
302 |
|
303 NS_IMETHOD |
|
304 Tell(int64_t* aResult) |
|
305 { |
|
306 // We can cheat here and assume that we're going to start at 0 if we don't |
|
307 // yet have our stream. Though, really, this should abort since most input |
|
308 // streams could block here. |
|
309 if (NS_IsMainThread() && !mStream) { |
|
310 *aResult = 0; |
|
311 return NS_OK; |
|
312 } |
|
313 |
|
314 nsresult rv = BlockAndWaitForStream(); |
|
315 NS_ENSURE_SUCCESS(rv, rv); |
|
316 |
|
317 if (!mWeakSeekableStream) { |
|
318 NS_WARNING("Underlying blob stream is not seekable!"); |
|
319 return NS_ERROR_NO_INTERFACE; |
|
320 } |
|
321 |
|
322 rv = mWeakSeekableStream->Tell(aResult); |
|
323 NS_ENSURE_SUCCESS(rv, rv); |
|
324 |
|
325 return NS_OK; |
|
326 } |
|
327 |
|
328 NS_IMETHOD |
|
329 SetEOF() |
|
330 { |
|
331 nsresult rv = BlockAndWaitForStream(); |
|
332 NS_ENSURE_SUCCESS(rv, rv); |
|
333 |
|
334 if (!mWeakSeekableStream) { |
|
335 NS_WARNING("Underlying blob stream is not seekable!"); |
|
336 return NS_ERROR_NO_INTERFACE; |
|
337 } |
|
338 |
|
339 rv = mWeakSeekableStream->SetEOF(); |
|
340 NS_ENSURE_SUCCESS(rv, rv); |
|
341 |
|
342 return NS_OK; |
|
343 } |
|
344 |
|
345 virtual nsIInputStream* |
|
346 BlockAndGetInternalStream() |
|
347 { |
|
348 MOZ_ASSERT(!NS_IsMainThread()); |
|
349 |
|
350 nsresult rv = BlockAndWaitForStream(); |
|
351 NS_ENSURE_SUCCESS(rv, nullptr); |
|
352 |
|
353 return mStream; |
|
354 } |
|
355 |
|
356 private: |
|
357 virtual ~RemoteInputStream() |
|
358 { |
|
359 if (!NS_IsMainThread()) { |
|
360 mStream = nullptr; |
|
361 mWeakSeekableStream = nullptr; |
|
362 ProxyReleaseToMainThread(mSourceBlob); |
|
363 } |
|
364 } |
|
365 |
|
366 void |
|
367 ReallyBlockAndWaitForStream() |
|
368 { |
|
369 mozilla::DebugOnly<bool> waited; |
|
370 |
|
371 { |
|
372 mozilla::MonitorAutoLock lock(mMonitor); |
|
373 |
|
374 waited = !mStream; |
|
375 |
|
376 while (!mStream) { |
|
377 mMonitor.Wait(); |
|
378 } |
|
379 } |
|
380 |
|
381 MOZ_ASSERT(mStream); |
|
382 |
|
383 #ifdef DEBUG |
|
384 if (waited && mWeakSeekableStream) { |
|
385 int64_t position; |
|
386 MOZ_ASSERT(NS_SUCCEEDED(mWeakSeekableStream->Tell(&position)), |
|
387 "Failed to determine initial stream position!"); |
|
388 MOZ_ASSERT(!position, "Stream not starting at 0!"); |
|
389 } |
|
390 #endif |
|
391 } |
|
392 |
|
393 nsresult |
|
394 BlockAndWaitForStream() |
|
395 { |
|
396 if (NS_IsMainThread()) { |
|
397 NS_WARNING("Blocking the main thread is not supported!"); |
|
398 return NS_ERROR_FAILURE; |
|
399 } |
|
400 |
|
401 ReallyBlockAndWaitForStream(); |
|
402 |
|
403 return NS_OK; |
|
404 } |
|
405 |
|
406 bool |
|
407 IsSeekableStream() |
|
408 { |
|
409 if (NS_IsMainThread()) { |
|
410 if (!mStream) { |
|
411 NS_WARNING("Don't know if this stream is seekable yet!"); |
|
412 return true; |
|
413 } |
|
414 } |
|
415 else { |
|
416 ReallyBlockAndWaitForStream(); |
|
417 } |
|
418 |
|
419 return !!mWeakSeekableStream; |
|
420 } |
|
421 }; |
|
422 |
|
423 NS_IMPL_ADDREF(RemoteInputStream) |
|
424 NS_IMPL_RELEASE(RemoteInputStream) |
|
425 |
|
426 NS_INTERFACE_MAP_BEGIN(RemoteInputStream) |
|
427 NS_INTERFACE_MAP_ENTRY(nsIInputStream) |
|
428 NS_INTERFACE_MAP_ENTRY(nsIIPCSerializableInputStream) |
|
429 NS_INTERFACE_MAP_ENTRY_CONDITIONAL(nsISeekableStream, IsSeekableStream()) |
|
430 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIInputStream) |
|
431 NS_INTERFACE_MAP_ENTRY(IPrivateRemoteInputStream) |
|
432 NS_INTERFACE_MAP_END |
|
433 |
|
434 class InputStreamChild MOZ_FINAL |
|
435 : public PBlobStreamChild |
|
436 { |
|
437 nsRefPtr<RemoteInputStream> mRemoteStream; |
|
438 |
|
439 public: |
|
440 InputStreamChild(RemoteInputStream* aRemoteStream) |
|
441 : mRemoteStream(aRemoteStream) |
|
442 { |
|
443 MOZ_ASSERT(NS_IsMainThread()); |
|
444 MOZ_ASSERT(aRemoteStream); |
|
445 } |
|
446 |
|
447 InputStreamChild() |
|
448 { |
|
449 MOZ_ASSERT(NS_IsMainThread()); |
|
450 } |
|
451 |
|
452 private: |
|
453 // This method is only called by the IPDL message machinery. |
|
454 virtual bool |
|
455 Recv__delete__(const InputStreamParams& aParams, |
|
456 const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE; |
|
457 }; |
|
458 |
|
459 class InputStreamParent MOZ_FINAL |
|
460 : public PBlobStreamParent |
|
461 { |
|
462 nsRefPtr<RemoteInputStream> mRemoteStream; |
|
463 |
|
464 public: |
|
465 InputStreamParent(RemoteInputStream* aRemoteStream) |
|
466 : mRemoteStream(aRemoteStream) |
|
467 { |
|
468 MOZ_ASSERT(NS_IsMainThread()); |
|
469 MOZ_ASSERT(aRemoteStream); |
|
470 } |
|
471 |
|
472 InputStreamParent() |
|
473 { |
|
474 MOZ_ASSERT(NS_IsMainThread()); |
|
475 } |
|
476 |
|
477 private: |
|
478 // This method is only called by the IPDL message machinery. |
|
479 virtual bool |
|
480 Recv__delete__(const InputStreamParams& aParams, |
|
481 const OptionalFileDescriptorSet& aFDs) MOZ_OVERRIDE; |
|
482 }; |
|
483 |
|
484 nsDOMFileBase* |
|
485 ToConcreteBlob(nsIDOMBlob* aBlob) |
|
486 { |
|
487 // XXX This is only safe so long as all blob implementations in our tree |
|
488 // inherit nsDOMFileBase. If that ever changes then this will need to grow |
|
489 // a real interface or something. |
|
490 return static_cast<nsDOMFileBase*>(aBlob); |
|
491 } |
|
492 |
|
493 } // anonymous namespace |
|
494 |
|
495 // Each instance of this class will be dispatched to the network stream thread |
|
496 // pool to run the first time where it will open the file input stream. It will |
|
497 // then dispatch itself back to the main thread to send the child process its |
|
498 // response (assuming that the child has not crashed). The runnable will then |
|
499 // dispatch itself to the thread pool again in order to close the file input |
|
500 // stream. |
|
501 class BlobParent::OpenStreamRunnable MOZ_FINAL |
|
502 : public nsRunnable |
|
503 { |
|
504 friend class nsRevocableEventPtr<OpenStreamRunnable>; |
|
505 |
|
506 // Only safe to access these pointers if mRevoked is false! |
|
507 BlobParent* mBlobActor; |
|
508 PBlobStreamParent* mStreamActor; |
|
509 |
|
510 nsCOMPtr<nsIInputStream> mStream; |
|
511 nsCOMPtr<nsIIPCSerializableInputStream> mSerializable; |
|
512 nsCOMPtr<nsIEventTarget> mTarget; |
|
513 |
|
514 bool mRevoked; |
|
515 bool mClosing; |
|
516 |
|
517 public: |
|
518 OpenStreamRunnable(BlobParent* aBlobActor, |
|
519 PBlobStreamParent* aStreamActor, |
|
520 nsIInputStream* aStream, |
|
521 nsIIPCSerializableInputStream* aSerializable, |
|
522 nsIEventTarget* aTarget) |
|
523 : mBlobActor(aBlobActor), mStreamActor(aStreamActor), mStream(aStream), |
|
524 mSerializable(aSerializable), mTarget(aTarget), mRevoked(false), |
|
525 mClosing(false) |
|
526 { |
|
527 MOZ_ASSERT(NS_IsMainThread()); |
|
528 MOZ_ASSERT(aBlobActor); |
|
529 MOZ_ASSERT(aStreamActor); |
|
530 MOZ_ASSERT(aStream); |
|
531 // aSerializable may be null. |
|
532 MOZ_ASSERT(aTarget); |
|
533 } |
|
534 |
|
535 NS_IMETHOD |
|
536 Run() |
|
537 { |
|
538 if (NS_IsMainThread()) { |
|
539 return SendResponse(); |
|
540 } |
|
541 |
|
542 if (!mClosing) { |
|
543 return OpenStream(); |
|
544 } |
|
545 |
|
546 return CloseStream(); |
|
547 } |
|
548 |
|
549 nsresult |
|
550 Dispatch() |
|
551 { |
|
552 MOZ_ASSERT(NS_IsMainThread()); |
|
553 MOZ_ASSERT(mTarget); |
|
554 |
|
555 nsresult rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL); |
|
556 NS_ENSURE_SUCCESS(rv, rv); |
|
557 |
|
558 return NS_OK; |
|
559 } |
|
560 |
|
561 private: |
|
562 void |
|
563 Revoke() |
|
564 { |
|
565 MOZ_ASSERT(NS_IsMainThread()); |
|
566 #ifdef DEBUG |
|
567 mBlobActor = nullptr; |
|
568 mStreamActor = nullptr; |
|
569 #endif |
|
570 mRevoked = true; |
|
571 } |
|
572 |
|
573 nsresult |
|
574 OpenStream() |
|
575 { |
|
576 MOZ_ASSERT(!NS_IsMainThread()); |
|
577 MOZ_ASSERT(mStream); |
|
578 |
|
579 if (!mSerializable) { |
|
580 nsCOMPtr<IPrivateRemoteInputStream> remoteStream = |
|
581 do_QueryInterface(mStream); |
|
582 MOZ_ASSERT(remoteStream, "Must QI to IPrivateRemoteInputStream here!"); |
|
583 |
|
584 nsCOMPtr<nsIInputStream> realStream = |
|
585 remoteStream->BlockAndGetInternalStream(); |
|
586 NS_ENSURE_TRUE(realStream, NS_ERROR_FAILURE); |
|
587 |
|
588 mSerializable = do_QueryInterface(realStream); |
|
589 if (!mSerializable) { |
|
590 MOZ_ASSERT(false, "Must be serializable!"); |
|
591 return NS_ERROR_FAILURE; |
|
592 } |
|
593 |
|
594 mStream.swap(realStream); |
|
595 } |
|
596 |
|
597 // To force the stream open we call Available(). We don't actually care |
|
598 // how much data is available. |
|
599 uint64_t available; |
|
600 if (NS_FAILED(mStream->Available(&available))) { |
|
601 NS_WARNING("Available failed on this stream!"); |
|
602 } |
|
603 |
|
604 nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL); |
|
605 NS_ENSURE_SUCCESS(rv, rv); |
|
606 |
|
607 return NS_OK; |
|
608 } |
|
609 |
|
610 nsresult |
|
611 CloseStream() |
|
612 { |
|
613 MOZ_ASSERT(!NS_IsMainThread()); |
|
614 MOZ_ASSERT(mStream); |
|
615 |
|
616 // Going to always release here. |
|
617 nsCOMPtr<nsIInputStream> stream; |
|
618 mStream.swap(stream); |
|
619 |
|
620 nsresult rv = stream->Close(); |
|
621 NS_ENSURE_SUCCESS(rv, rv); |
|
622 |
|
623 return NS_OK; |
|
624 } |
|
625 |
|
626 nsresult |
|
627 SendResponse() |
|
628 { |
|
629 MOZ_ASSERT(NS_IsMainThread()); |
|
630 |
|
631 MOZ_ASSERT(mStream); |
|
632 MOZ_ASSERT(mSerializable); |
|
633 MOZ_ASSERT(mTarget); |
|
634 MOZ_ASSERT(!mClosing); |
|
635 |
|
636 nsCOMPtr<nsIIPCSerializableInputStream> serializable; |
|
637 mSerializable.swap(serializable); |
|
638 |
|
639 if (mRevoked) { |
|
640 MOZ_ASSERT(!mBlobActor); |
|
641 MOZ_ASSERT(!mStreamActor); |
|
642 } |
|
643 else { |
|
644 MOZ_ASSERT(mBlobActor); |
|
645 MOZ_ASSERT(mStreamActor); |
|
646 |
|
647 InputStreamParams params; |
|
648 nsAutoTArray<FileDescriptor, 10> fds; |
|
649 serializable->Serialize(params, fds); |
|
650 |
|
651 MOZ_ASSERT(params.type() != InputStreamParams::T__None); |
|
652 |
|
653 PFileDescriptorSetParent* fdSet = nullptr; |
|
654 |
|
655 if (!fds.IsEmpty()) { |
|
656 auto* manager = static_cast<ContentParent*>(mBlobActor->Manager()); |
|
657 MOZ_ASSERT(manager); |
|
658 |
|
659 fdSet = manager->SendPFileDescriptorSetConstructor(fds[0]); |
|
660 if (fdSet) { |
|
661 for (uint32_t index = 1; index < fds.Length(); index++) { |
|
662 unused << fdSet->SendAddFileDescriptor(fds[index]); |
|
663 } |
|
664 } |
|
665 } |
|
666 |
|
667 OptionalFileDescriptorSet optionalFDs; |
|
668 if (fdSet) { |
|
669 optionalFDs = fdSet; |
|
670 } else { |
|
671 optionalFDs = mozilla::void_t(); |
|
672 } |
|
673 |
|
674 unused << |
|
675 PBlobStreamParent::Send__delete__(mStreamActor, params, optionalFDs); |
|
676 |
|
677 mBlobActor->NoteRunnableCompleted(this); |
|
678 |
|
679 #ifdef DEBUG |
|
680 mBlobActor = nullptr; |
|
681 mStreamActor = nullptr; |
|
682 #endif |
|
683 } |
|
684 |
|
685 mClosing = true; |
|
686 |
|
687 nsCOMPtr<nsIEventTarget> target; |
|
688 mTarget.swap(target); |
|
689 |
|
690 nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL); |
|
691 NS_ENSURE_SUCCESS(rv, rv); |
|
692 |
|
693 return NS_OK; |
|
694 } |
|
695 }; |
|
696 |
|
697 /******************************************************************************* |
|
698 * BlobChild::RemoteBlob Declaration |
|
699 ******************************************************************************/ |
|
700 |
|
701 class BlobChild::RemoteBlob MOZ_FINAL |
|
702 : public nsDOMFile |
|
703 , public nsIRemoteBlob |
|
704 { |
|
705 class StreamHelper; |
|
706 class SliceHelper; |
|
707 |
|
708 BlobChild* mActor; |
|
709 |
|
710 public: |
|
711 RemoteBlob(const nsAString& aName, |
|
712 const nsAString& aContentType, |
|
713 uint64_t aLength, |
|
714 uint64_t aModDate) |
|
715 : nsDOMFile(aName, aContentType, aLength, aModDate) |
|
716 , mActor(nullptr) |
|
717 { |
|
718 mImmutable = true; |
|
719 } |
|
720 |
|
721 RemoteBlob(const nsAString& aContentType, uint64_t aLength) |
|
722 : nsDOMFile(aContentType, aLength) |
|
723 , mActor(nullptr) |
|
724 { |
|
725 mImmutable = true; |
|
726 } |
|
727 |
|
728 RemoteBlob() |
|
729 : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX) |
|
730 , mActor(nullptr) |
|
731 { |
|
732 mImmutable = true; |
|
733 } |
|
734 |
|
735 void |
|
736 SetActor(BlobChild* aActor) |
|
737 { |
|
738 MOZ_ASSERT(!aActor || !mActor); |
|
739 mActor = aActor; |
|
740 } |
|
741 |
|
742 NS_DECL_ISUPPORTS_INHERITED |
|
743 |
|
744 virtual already_AddRefed<nsIDOMBlob> |
|
745 CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) |
|
746 MOZ_OVERRIDE; |
|
747 |
|
748 NS_IMETHOD |
|
749 GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE; |
|
750 |
|
751 NS_IMETHOD |
|
752 GetLastModifiedDate(JSContext* cx, |
|
753 JS::MutableHandle<JS::Value> aLastModifiedDate) |
|
754 MOZ_OVERRIDE; |
|
755 |
|
756 virtual void* |
|
757 GetPBlob() MOZ_OVERRIDE; |
|
758 |
|
759 private: |
|
760 ~RemoteBlob() |
|
761 { |
|
762 if (mActor) { |
|
763 mActor->NoteDyingRemoteBlob(); |
|
764 } |
|
765 } |
|
766 }; |
|
767 |
|
768 class BlobChild::RemoteBlob::StreamHelper MOZ_FINAL |
|
769 : public nsRunnable |
|
770 { |
|
771 mozilla::Monitor mMonitor; |
|
772 BlobChild* mActor; |
|
773 nsCOMPtr<nsIDOMBlob> mSourceBlob; |
|
774 nsRefPtr<RemoteInputStream> mInputStream; |
|
775 bool mDone; |
|
776 |
|
777 public: |
|
778 StreamHelper(BlobChild* aActor, nsIDOMBlob* aSourceBlob) |
|
779 : mMonitor("BlobChild::RemoteBlob::StreamHelper::mMonitor") |
|
780 , mActor(aActor) |
|
781 , mSourceBlob(aSourceBlob) |
|
782 , mDone(false) |
|
783 { |
|
784 // This may be created on any thread. |
|
785 MOZ_ASSERT(aActor); |
|
786 MOZ_ASSERT(aSourceBlob); |
|
787 } |
|
788 |
|
789 nsresult |
|
790 GetStream(nsIInputStream** aInputStream) |
|
791 { |
|
792 // This may be called on any thread. |
|
793 MOZ_ASSERT(aInputStream); |
|
794 MOZ_ASSERT(mActor); |
|
795 MOZ_ASSERT(!mInputStream); |
|
796 MOZ_ASSERT(!mDone); |
|
797 |
|
798 if (NS_IsMainThread()) { |
|
799 RunInternal(false); |
|
800 } |
|
801 else { |
|
802 nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
|
803 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); |
|
804 |
|
805 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); |
|
806 NS_ENSURE_SUCCESS(rv, rv); |
|
807 |
|
808 { |
|
809 MonitorAutoLock lock(mMonitor); |
|
810 while (!mDone) { |
|
811 lock.Wait(); |
|
812 } |
|
813 } |
|
814 } |
|
815 |
|
816 MOZ_ASSERT(!mActor); |
|
817 MOZ_ASSERT(mDone); |
|
818 |
|
819 if (!mInputStream) { |
|
820 return NS_ERROR_UNEXPECTED; |
|
821 } |
|
822 |
|
823 mInputStream.forget(aInputStream); |
|
824 return NS_OK; |
|
825 } |
|
826 |
|
827 NS_IMETHOD |
|
828 Run() |
|
829 { |
|
830 MOZ_ASSERT(NS_IsMainThread()); |
|
831 RunInternal(true); |
|
832 return NS_OK; |
|
833 } |
|
834 |
|
835 private: |
|
836 void |
|
837 RunInternal(bool aNotify) |
|
838 { |
|
839 MOZ_ASSERT(NS_IsMainThread()); |
|
840 MOZ_ASSERT(mActor); |
|
841 MOZ_ASSERT(!mInputStream); |
|
842 MOZ_ASSERT(!mDone); |
|
843 |
|
844 nsRefPtr<RemoteInputStream> stream = |
|
845 new RemoteInputStream(mSourceBlob, ChildActor); |
|
846 |
|
847 InputStreamChild* streamActor = new InputStreamChild(stream); |
|
848 if (mActor->SendPBlobStreamConstructor(streamActor)) { |
|
849 stream.swap(mInputStream); |
|
850 } |
|
851 |
|
852 mActor = nullptr; |
|
853 |
|
854 if (aNotify) { |
|
855 MonitorAutoLock lock(mMonitor); |
|
856 mDone = true; |
|
857 lock.Notify(); |
|
858 } |
|
859 else { |
|
860 mDone = true; |
|
861 } |
|
862 } |
|
863 }; |
|
864 |
|
865 class BlobChild::RemoteBlob::SliceHelper MOZ_FINAL |
|
866 : public nsRunnable |
|
867 { |
|
868 mozilla::Monitor mMonitor; |
|
869 BlobChild* mActor; |
|
870 nsCOMPtr<nsIDOMBlob> mSlice; |
|
871 uint64_t mStart; |
|
872 uint64_t mLength; |
|
873 nsString mContentType; |
|
874 bool mDone; |
|
875 |
|
876 public: |
|
877 SliceHelper(BlobChild* aActor) |
|
878 : mMonitor("BlobChild::RemoteBlob::SliceHelper::mMonitor") |
|
879 , mActor(aActor) |
|
880 , mStart(0) |
|
881 , mLength(0) |
|
882 , mDone(false) |
|
883 { |
|
884 // This may be created on any thread. |
|
885 MOZ_ASSERT(aActor); |
|
886 } |
|
887 |
|
888 nsresult |
|
889 GetSlice(uint64_t aStart, |
|
890 uint64_t aLength, |
|
891 const nsAString& aContentType, |
|
892 nsIDOMBlob** aSlice) |
|
893 { |
|
894 // This may be called on any thread. |
|
895 MOZ_ASSERT(aSlice); |
|
896 MOZ_ASSERT(mActor); |
|
897 MOZ_ASSERT(!mSlice); |
|
898 MOZ_ASSERT(!mDone); |
|
899 |
|
900 mStart = aStart; |
|
901 mLength = aLength; |
|
902 mContentType = aContentType; |
|
903 |
|
904 if (NS_IsMainThread()) { |
|
905 RunInternal(false); |
|
906 } |
|
907 else { |
|
908 nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
|
909 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); |
|
910 |
|
911 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); |
|
912 NS_ENSURE_SUCCESS(rv, rv); |
|
913 |
|
914 { |
|
915 MonitorAutoLock lock(mMonitor); |
|
916 while (!mDone) { |
|
917 lock.Wait(); |
|
918 } |
|
919 } |
|
920 } |
|
921 |
|
922 MOZ_ASSERT(!mActor); |
|
923 MOZ_ASSERT(mDone); |
|
924 |
|
925 if (!mSlice) { |
|
926 return NS_ERROR_UNEXPECTED; |
|
927 } |
|
928 |
|
929 mSlice.forget(aSlice); |
|
930 return NS_OK; |
|
931 } |
|
932 |
|
933 NS_IMETHOD |
|
934 Run() |
|
935 { |
|
936 MOZ_ASSERT(NS_IsMainThread()); |
|
937 RunInternal(true); |
|
938 return NS_OK; |
|
939 } |
|
940 |
|
941 private: |
|
942 void |
|
943 RunInternal(bool aNotify) |
|
944 { |
|
945 MOZ_ASSERT(NS_IsMainThread()); |
|
946 MOZ_ASSERT(mActor); |
|
947 MOZ_ASSERT(!mSlice); |
|
948 MOZ_ASSERT(!mDone); |
|
949 |
|
950 NS_ENSURE_TRUE_VOID(mActor->Manager()); |
|
951 |
|
952 NormalBlobConstructorParams normalParams; |
|
953 normalParams.contentType() = mContentType; |
|
954 normalParams.length() = mLength; |
|
955 |
|
956 auto* manager = static_cast<ContentChild*>(mActor->Manager()); |
|
957 MOZ_ASSERT(manager); |
|
958 |
|
959 BlobChild* newActor = BlobChild::Create(manager, normalParams); |
|
960 MOZ_ASSERT(newActor); |
|
961 |
|
962 SlicedBlobConstructorParams slicedParams; |
|
963 slicedParams.contentType() = mContentType; |
|
964 slicedParams.begin() = mStart; |
|
965 slicedParams.end() = mStart + mLength; |
|
966 slicedParams.sourceChild() = mActor; |
|
967 |
|
968 ParentBlobConstructorParams otherSideParams; |
|
969 otherSideParams.blobParams() = slicedParams; |
|
970 otherSideParams.optionalInputStreamParams() = mozilla::void_t(); |
|
971 |
|
972 if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) { |
|
973 mSlice = newActor->GetBlob(); |
|
974 } |
|
975 |
|
976 mActor = nullptr; |
|
977 |
|
978 if (aNotify) { |
|
979 MonitorAutoLock lock(mMonitor); |
|
980 mDone = true; |
|
981 lock.Notify(); |
|
982 } |
|
983 else { |
|
984 mDone = true; |
|
985 } |
|
986 } |
|
987 }; |
|
988 |
|
989 /******************************************************************************* |
|
990 * BlobChild::RemoteBlob Implementation |
|
991 ******************************************************************************/ |
|
992 |
|
993 NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, nsDOMFile, nsIRemoteBlob) |
|
994 |
|
995 already_AddRefed<nsIDOMBlob> |
|
996 BlobChild:: |
|
997 RemoteBlob::CreateSlice(uint64_t aStart, |
|
998 uint64_t aLength, |
|
999 const nsAString& aContentType) |
|
1000 { |
|
1001 if (!mActor) { |
|
1002 return nullptr; |
|
1003 } |
|
1004 |
|
1005 nsRefPtr<SliceHelper> helper = new SliceHelper(mActor); |
|
1006 |
|
1007 nsCOMPtr<nsIDOMBlob> slice; |
|
1008 nsresult rv = |
|
1009 helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice)); |
|
1010 NS_ENSURE_SUCCESS(rv, nullptr); |
|
1011 |
|
1012 return slice.forget(); |
|
1013 } |
|
1014 |
|
1015 NS_IMETHODIMP |
|
1016 BlobChild:: |
|
1017 RemoteBlob::GetInternalStream(nsIInputStream** aStream) |
|
1018 { |
|
1019 if (!mActor) { |
|
1020 return NS_ERROR_UNEXPECTED; |
|
1021 } |
|
1022 |
|
1023 nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this); |
|
1024 return helper->GetStream(aStream); |
|
1025 } |
|
1026 |
|
1027 NS_IMETHODIMP |
|
1028 BlobChild:: |
|
1029 RemoteBlob::GetLastModifiedDate(JSContext* cx, |
|
1030 JS::MutableHandle<JS::Value> aLastModifiedDate) |
|
1031 { |
|
1032 if (IsDateUnknown()) { |
|
1033 aLastModifiedDate.setNull(); |
|
1034 } else { |
|
1035 JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate); |
|
1036 if (!date) { |
|
1037 return NS_ERROR_OUT_OF_MEMORY; |
|
1038 } |
|
1039 aLastModifiedDate.setObject(*date); |
|
1040 } |
|
1041 return NS_OK; |
|
1042 } |
|
1043 |
|
1044 void* |
|
1045 BlobChild:: |
|
1046 RemoteBlob::GetPBlob() |
|
1047 { |
|
1048 return static_cast<PBlobChild*>(mActor); |
|
1049 } |
|
1050 |
|
1051 /******************************************************************************* |
|
1052 * BlobChild |
|
1053 ******************************************************************************/ |
|
1054 |
|
1055 BlobChild::BlobChild(ContentChild* aManager, nsIDOMBlob* aBlob) |
|
1056 : mBlob(aBlob) |
|
1057 , mRemoteBlob(nullptr) |
|
1058 , mStrongManager(aManager) |
|
1059 , mOwnsBlob(true) |
|
1060 , mBlobIsFile(false) |
|
1061 { |
|
1062 MOZ_ASSERT(NS_IsMainThread()); |
|
1063 MOZ_ASSERT(aManager); |
|
1064 MOZ_ASSERT(aBlob); |
|
1065 |
|
1066 aBlob->AddRef(); |
|
1067 |
|
1068 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob); |
|
1069 mBlobIsFile = !!file; |
|
1070 } |
|
1071 |
|
1072 BlobChild::BlobChild(ContentChild* aManager, |
|
1073 const ChildBlobConstructorParams& aParams) |
|
1074 : mBlob(nullptr) |
|
1075 , mRemoteBlob(nullptr) |
|
1076 , mStrongManager(aManager) |
|
1077 , mOwnsBlob(false) |
|
1078 , mBlobIsFile(false) |
|
1079 { |
|
1080 MOZ_ASSERT(NS_IsMainThread()); |
|
1081 MOZ_ASSERT(aManager); |
|
1082 |
|
1083 ChildBlobConstructorParams::Type paramsType = aParams.type(); |
|
1084 |
|
1085 mBlobIsFile = |
|
1086 paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams || |
|
1087 paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams; |
|
1088 |
|
1089 nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams); |
|
1090 MOZ_ASSERT(remoteBlob); |
|
1091 |
|
1092 remoteBlob->SetActor(this); |
|
1093 remoteBlob.forget(&mRemoteBlob); |
|
1094 |
|
1095 mBlob = mRemoteBlob; |
|
1096 mOwnsBlob = true; |
|
1097 } |
|
1098 |
|
1099 BlobChild::~BlobChild() |
|
1100 { |
|
1101 } |
|
1102 |
|
1103 BlobChild* |
|
1104 BlobChild::Create(ContentChild* aManager, |
|
1105 const ChildBlobConstructorParams& aParams) |
|
1106 { |
|
1107 MOZ_ASSERT(NS_IsMainThread()); |
|
1108 MOZ_ASSERT(aManager); |
|
1109 |
|
1110 switch (aParams.type()) { |
|
1111 case ChildBlobConstructorParams::TNormalBlobConstructorParams: |
|
1112 case ChildBlobConstructorParams::TFileBlobConstructorParams: |
|
1113 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: |
|
1114 return new BlobChild(aManager, aParams); |
|
1115 |
|
1116 case ChildBlobConstructorParams::TSlicedBlobConstructorParams: { |
|
1117 const SlicedBlobConstructorParams& params = |
|
1118 aParams.get_SlicedBlobConstructorParams(); |
|
1119 |
|
1120 auto* actor = |
|
1121 const_cast<BlobChild*>( |
|
1122 static_cast<const BlobChild*>(params.sourceChild())); |
|
1123 MOZ_ASSERT(actor); |
|
1124 |
|
1125 nsCOMPtr<nsIDOMBlob> source = actor->GetBlob(); |
|
1126 MOZ_ASSERT(source); |
|
1127 |
|
1128 nsCOMPtr<nsIDOMBlob> slice; |
|
1129 nsresult rv = |
|
1130 source->Slice(params.begin(), params.end(), params.contentType(), 3, |
|
1131 getter_AddRefs(slice)); |
|
1132 NS_ENSURE_SUCCESS(rv, nullptr); |
|
1133 |
|
1134 return new BlobChild(aManager, slice); |
|
1135 } |
|
1136 |
|
1137 default: |
|
1138 MOZ_CRASH("Unknown params!"); |
|
1139 } |
|
1140 |
|
1141 return nullptr; |
|
1142 } |
|
1143 |
|
1144 already_AddRefed<nsIDOMBlob> |
|
1145 BlobChild::GetBlob() |
|
1146 { |
|
1147 MOZ_ASSERT(NS_IsMainThread()); |
|
1148 MOZ_ASSERT(mBlob); |
|
1149 |
|
1150 nsCOMPtr<nsIDOMBlob> blob; |
|
1151 |
|
1152 // Remote blobs are held alive until the first call to GetBlob. Thereafter we |
|
1153 // only hold a weak reference. Normal blobs are held alive until the actor is |
|
1154 // destroyed. |
|
1155 if (mRemoteBlob && mOwnsBlob) { |
|
1156 blob = dont_AddRef(mBlob); |
|
1157 mOwnsBlob = false; |
|
1158 } |
|
1159 else { |
|
1160 blob = mBlob; |
|
1161 } |
|
1162 |
|
1163 MOZ_ASSERT(blob); |
|
1164 |
|
1165 return blob.forget(); |
|
1166 } |
|
1167 |
|
1168 bool |
|
1169 BlobChild::SetMysteryBlobInfo(const nsString& aName, |
|
1170 const nsString& aContentType, |
|
1171 uint64_t aLength, |
|
1172 uint64_t aLastModifiedDate) |
|
1173 { |
|
1174 MOZ_ASSERT(NS_IsMainThread()); |
|
1175 MOZ_ASSERT(mBlob); |
|
1176 MOZ_ASSERT(mRemoteBlob); |
|
1177 MOZ_ASSERT(aLastModifiedDate != UINT64_MAX); |
|
1178 |
|
1179 ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength, |
|
1180 aLastModifiedDate); |
|
1181 |
|
1182 FileBlobConstructorParams params(aName, aContentType, aLength, |
|
1183 aLastModifiedDate); |
|
1184 return SendResolveMystery(params); |
|
1185 } |
|
1186 |
|
1187 bool |
|
1188 BlobChild::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength) |
|
1189 { |
|
1190 MOZ_ASSERT(NS_IsMainThread()); |
|
1191 MOZ_ASSERT(mBlob); |
|
1192 MOZ_ASSERT(mRemoteBlob); |
|
1193 |
|
1194 nsString voidString; |
|
1195 voidString.SetIsVoid(true); |
|
1196 |
|
1197 ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength, |
|
1198 UINT64_MAX); |
|
1199 |
|
1200 NormalBlobConstructorParams params(aContentType, aLength); |
|
1201 return SendResolveMystery(params); |
|
1202 } |
|
1203 |
|
1204 already_AddRefed<BlobChild::RemoteBlob> |
|
1205 BlobChild::CreateRemoteBlob(const ChildBlobConstructorParams& aParams) |
|
1206 { |
|
1207 MOZ_ASSERT(NS_IsMainThread()); |
|
1208 |
|
1209 nsRefPtr<RemoteBlob> remoteBlob; |
|
1210 |
|
1211 switch (aParams.type()) { |
|
1212 case ChildBlobConstructorParams::TNormalBlobConstructorParams: { |
|
1213 const NormalBlobConstructorParams& params = |
|
1214 aParams.get_NormalBlobConstructorParams(); |
|
1215 remoteBlob = new RemoteBlob(params.contentType(), params.length()); |
|
1216 break; |
|
1217 } |
|
1218 |
|
1219 case ChildBlobConstructorParams::TFileBlobConstructorParams: { |
|
1220 const FileBlobConstructorParams& params = |
|
1221 aParams.get_FileBlobConstructorParams(); |
|
1222 remoteBlob = |
|
1223 new RemoteBlob(params.name(), params.contentType(), params.length(), |
|
1224 params.modDate()); |
|
1225 break; |
|
1226 } |
|
1227 |
|
1228 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: { |
|
1229 remoteBlob = new RemoteBlob(); |
|
1230 break; |
|
1231 } |
|
1232 |
|
1233 default: |
|
1234 MOZ_CRASH("Unknown params!"); |
|
1235 } |
|
1236 |
|
1237 MOZ_ASSERT(remoteBlob); |
|
1238 |
|
1239 if (NS_FAILED(remoteBlob->SetMutable(false))) { |
|
1240 MOZ_CRASH("Failed to make remote blob immutable!"); |
|
1241 } |
|
1242 |
|
1243 return remoteBlob.forget(); |
|
1244 } |
|
1245 |
|
1246 void |
|
1247 BlobChild::NoteDyingRemoteBlob() |
|
1248 { |
|
1249 MOZ_ASSERT(mBlob); |
|
1250 MOZ_ASSERT(mRemoteBlob); |
|
1251 MOZ_ASSERT(!mOwnsBlob); |
|
1252 |
|
1253 // This may be called on any thread due to the fact that RemoteBlob is |
|
1254 // designed to be passed between threads. We must start the shutdown process |
|
1255 // on the main thread, so we proxy here if necessary. |
|
1256 if (!NS_IsMainThread()) { |
|
1257 nsCOMPtr<nsIRunnable> runnable = |
|
1258 NS_NewNonOwningRunnableMethod(this, &BlobChild::NoteDyingRemoteBlob); |
|
1259 if (NS_FAILED(NS_DispatchToMainThread(runnable))) { |
|
1260 MOZ_ASSERT(false, "Should never fail!"); |
|
1261 } |
|
1262 |
|
1263 return; |
|
1264 } |
|
1265 |
|
1266 // Must do this before calling Send__delete__ or we'll crash there trying to |
|
1267 // access a dangling pointer. |
|
1268 mBlob = nullptr; |
|
1269 mRemoteBlob = nullptr; |
|
1270 |
|
1271 PBlobChild::Send__delete__(this); |
|
1272 } |
|
1273 |
|
1274 void |
|
1275 BlobChild::ActorDestroy(ActorDestroyReason aWhy) |
|
1276 { |
|
1277 MOZ_ASSERT(NS_IsMainThread()); |
|
1278 |
|
1279 if (mRemoteBlob) { |
|
1280 mRemoteBlob->SetActor(nullptr); |
|
1281 } |
|
1282 |
|
1283 if (mBlob && mOwnsBlob) { |
|
1284 mBlob->Release(); |
|
1285 } |
|
1286 |
|
1287 mStrongManager = nullptr; |
|
1288 } |
|
1289 |
|
1290 PBlobStreamChild* |
|
1291 BlobChild::AllocPBlobStreamChild() |
|
1292 { |
|
1293 MOZ_ASSERT(NS_IsMainThread()); |
|
1294 |
|
1295 return new InputStreamChild(); |
|
1296 } |
|
1297 |
|
1298 bool |
|
1299 BlobChild::RecvPBlobStreamConstructor(PBlobStreamChild* aActor) |
|
1300 { |
|
1301 MOZ_ASSERT(NS_IsMainThread()); |
|
1302 MOZ_ASSERT(aActor); |
|
1303 MOZ_ASSERT(mBlob); |
|
1304 MOZ_ASSERT(!mRemoteBlob); |
|
1305 |
|
1306 nsCOMPtr<nsIInputStream> stream; |
|
1307 nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream)); |
|
1308 NS_ENSURE_SUCCESS(rv, false); |
|
1309 |
|
1310 nsCOMPtr<nsIIPCSerializableInputStream> serializable = |
|
1311 do_QueryInterface(stream); |
|
1312 if (!serializable) { |
|
1313 MOZ_ASSERT(false, "Must be serializable!"); |
|
1314 return false; |
|
1315 } |
|
1316 |
|
1317 InputStreamParams params; |
|
1318 nsTArray<FileDescriptor> fds; |
|
1319 serializable->Serialize(params, fds); |
|
1320 |
|
1321 MOZ_ASSERT(params.type() != InputStreamParams::T__None); |
|
1322 MOZ_ASSERT(fds.IsEmpty()); |
|
1323 |
|
1324 return aActor->Send__delete__(aActor, params, mozilla::void_t()); |
|
1325 } |
|
1326 |
|
1327 bool |
|
1328 BlobChild::DeallocPBlobStreamChild(PBlobStreamChild* aActor) |
|
1329 { |
|
1330 MOZ_ASSERT(NS_IsMainThread()); |
|
1331 |
|
1332 delete static_cast<InputStreamChild*>(aActor); |
|
1333 return true; |
|
1334 } |
|
1335 |
|
1336 bool |
|
1337 BlobChild::RecvResolveMystery(const ResolveMysteryParams& aParams) |
|
1338 { |
|
1339 MOZ_ASSERT(NS_IsMainThread()); |
|
1340 MOZ_ASSERT(mBlob); |
|
1341 MOZ_ASSERT(!mRemoteBlob); |
|
1342 MOZ_ASSERT(mOwnsBlob); |
|
1343 |
|
1344 if (!mBlobIsFile) { |
|
1345 MOZ_ASSERT(false, "Must always be a file!"); |
|
1346 return false; |
|
1347 } |
|
1348 |
|
1349 nsDOMFileBase* blob = ToConcreteBlob(mBlob); |
|
1350 |
|
1351 switch (aParams.type()) { |
|
1352 case ResolveMysteryParams::TNormalBlobConstructorParams: { |
|
1353 const NormalBlobConstructorParams& params = |
|
1354 aParams.get_NormalBlobConstructorParams(); |
|
1355 nsString voidString; |
|
1356 voidString.SetIsVoid(true); |
|
1357 blob->SetLazyData(voidString, params.contentType(), params.length(), |
|
1358 UINT64_MAX); |
|
1359 break; |
|
1360 } |
|
1361 |
|
1362 case ResolveMysteryParams::TFileBlobConstructorParams: { |
|
1363 const FileBlobConstructorParams& params = |
|
1364 aParams.get_FileBlobConstructorParams(); |
|
1365 blob->SetLazyData(params.name(), params.contentType(), params.length(), |
|
1366 params.modDate()); |
|
1367 break; |
|
1368 } |
|
1369 |
|
1370 default: |
|
1371 MOZ_CRASH("Unknown params!"); |
|
1372 } |
|
1373 |
|
1374 return true; |
|
1375 } |
|
1376 |
|
1377 /******************************************************************************* |
|
1378 * BlobParent::RemoteBlob Declaration |
|
1379 ******************************************************************************/ |
|
1380 |
|
1381 class BlobParent::RemoteBlob MOZ_FINAL |
|
1382 : public nsDOMFile |
|
1383 , public nsIRemoteBlob |
|
1384 { |
|
1385 class StreamHelper; |
|
1386 class SliceHelper; |
|
1387 |
|
1388 BlobParent* mActor; |
|
1389 InputStreamParams mInputStreamParams; |
|
1390 |
|
1391 public: |
|
1392 RemoteBlob(const nsAString& aName, |
|
1393 const nsAString& aContentType, |
|
1394 uint64_t aLength, |
|
1395 uint64_t aModDate) |
|
1396 : nsDOMFile(aName, aContentType, aLength, aModDate) |
|
1397 , mActor(nullptr) |
|
1398 { |
|
1399 mImmutable = true; |
|
1400 } |
|
1401 |
|
1402 RemoteBlob(const nsAString& aContentType, uint64_t aLength) |
|
1403 : nsDOMFile(aContentType, aLength) |
|
1404 , mActor(nullptr) |
|
1405 { |
|
1406 mImmutable = true; |
|
1407 } |
|
1408 |
|
1409 RemoteBlob() |
|
1410 : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX) |
|
1411 , mActor(nullptr) |
|
1412 { |
|
1413 mImmutable = true; |
|
1414 } |
|
1415 |
|
1416 void |
|
1417 SetActor(BlobParent* aActor) |
|
1418 { |
|
1419 MOZ_ASSERT(!aActor || !mActor); |
|
1420 mActor = aActor; |
|
1421 } |
|
1422 |
|
1423 void |
|
1424 MaybeSetInputStream(const ParentBlobConstructorParams& aParams) |
|
1425 { |
|
1426 if (aParams.optionalInputStreamParams().type() == |
|
1427 OptionalInputStreamParams::TInputStreamParams) { |
|
1428 mInputStreamParams = |
|
1429 aParams.optionalInputStreamParams().get_InputStreamParams(); |
|
1430 } |
|
1431 } |
|
1432 |
|
1433 NS_DECL_ISUPPORTS_INHERITED |
|
1434 |
|
1435 virtual already_AddRefed<nsIDOMBlob> |
|
1436 CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType) |
|
1437 MOZ_OVERRIDE; |
|
1438 |
|
1439 NS_IMETHOD |
|
1440 GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE; |
|
1441 |
|
1442 NS_IMETHOD |
|
1443 GetLastModifiedDate(JSContext* cx, |
|
1444 JS::MutableHandle<JS::Value> aLastModifiedDate) |
|
1445 MOZ_OVERRIDE; |
|
1446 |
|
1447 virtual void* |
|
1448 GetPBlob() MOZ_OVERRIDE; |
|
1449 |
|
1450 private: |
|
1451 ~RemoteBlob() |
|
1452 { |
|
1453 if (mActor) { |
|
1454 mActor->NoteDyingRemoteBlob(); |
|
1455 } |
|
1456 } |
|
1457 }; |
|
1458 |
|
1459 class BlobParent::RemoteBlob::StreamHelper MOZ_FINAL |
|
1460 : public nsRunnable |
|
1461 { |
|
1462 mozilla::Monitor mMonitor; |
|
1463 BlobParent* mActor; |
|
1464 nsCOMPtr<nsIDOMBlob> mSourceBlob; |
|
1465 nsRefPtr<RemoteInputStream> mInputStream; |
|
1466 bool mDone; |
|
1467 |
|
1468 public: |
|
1469 StreamHelper(BlobParent* aActor, nsIDOMBlob* aSourceBlob) |
|
1470 : mMonitor("BlobParent::RemoteBlob::StreamHelper::mMonitor") |
|
1471 , mActor(aActor) |
|
1472 , mSourceBlob(aSourceBlob) |
|
1473 , mDone(false) |
|
1474 { |
|
1475 // This may be created on any thread. |
|
1476 MOZ_ASSERT(aActor); |
|
1477 MOZ_ASSERT(aSourceBlob); |
|
1478 } |
|
1479 |
|
1480 nsresult |
|
1481 GetStream(nsIInputStream** aInputStream) |
|
1482 { |
|
1483 // This may be called on any thread. |
|
1484 MOZ_ASSERT(aInputStream); |
|
1485 MOZ_ASSERT(mActor); |
|
1486 MOZ_ASSERT(!mInputStream); |
|
1487 MOZ_ASSERT(!mDone); |
|
1488 |
|
1489 if (NS_IsMainThread()) { |
|
1490 RunInternal(false); |
|
1491 } |
|
1492 else { |
|
1493 nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
|
1494 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); |
|
1495 |
|
1496 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); |
|
1497 NS_ENSURE_SUCCESS(rv, rv); |
|
1498 |
|
1499 { |
|
1500 MonitorAutoLock lock(mMonitor); |
|
1501 while (!mDone) { |
|
1502 lock.Wait(); |
|
1503 } |
|
1504 } |
|
1505 } |
|
1506 |
|
1507 MOZ_ASSERT(!mActor); |
|
1508 MOZ_ASSERT(mDone); |
|
1509 |
|
1510 if (!mInputStream) { |
|
1511 return NS_ERROR_UNEXPECTED; |
|
1512 } |
|
1513 |
|
1514 mInputStream.forget(aInputStream); |
|
1515 return NS_OK; |
|
1516 } |
|
1517 |
|
1518 NS_IMETHOD |
|
1519 Run() |
|
1520 { |
|
1521 MOZ_ASSERT(NS_IsMainThread()); |
|
1522 RunInternal(true); |
|
1523 return NS_OK; |
|
1524 } |
|
1525 |
|
1526 private: |
|
1527 void |
|
1528 RunInternal(bool aNotify) |
|
1529 { |
|
1530 MOZ_ASSERT(NS_IsMainThread()); |
|
1531 MOZ_ASSERT(mActor); |
|
1532 MOZ_ASSERT(!mInputStream); |
|
1533 MOZ_ASSERT(!mDone); |
|
1534 |
|
1535 nsRefPtr<RemoteInputStream> stream = |
|
1536 new RemoteInputStream(mSourceBlob, ParentActor); |
|
1537 |
|
1538 InputStreamParent* streamActor = new InputStreamParent(stream); |
|
1539 if (mActor->SendPBlobStreamConstructor(streamActor)) { |
|
1540 stream.swap(mInputStream); |
|
1541 } |
|
1542 |
|
1543 mActor = nullptr; |
|
1544 |
|
1545 if (aNotify) { |
|
1546 MonitorAutoLock lock(mMonitor); |
|
1547 mDone = true; |
|
1548 lock.Notify(); |
|
1549 } |
|
1550 else { |
|
1551 mDone = true; |
|
1552 } |
|
1553 } |
|
1554 }; |
|
1555 |
|
1556 class BlobParent::RemoteBlob::SliceHelper MOZ_FINAL |
|
1557 : public nsRunnable |
|
1558 { |
|
1559 mozilla::Monitor mMonitor; |
|
1560 BlobParent* mActor; |
|
1561 nsCOMPtr<nsIDOMBlob> mSlice; |
|
1562 uint64_t mStart; |
|
1563 uint64_t mLength; |
|
1564 nsString mContentType; |
|
1565 bool mDone; |
|
1566 |
|
1567 public: |
|
1568 SliceHelper(BlobParent* aActor) |
|
1569 : mMonitor("BlobParent::RemoteBlob::SliceHelper::mMonitor") |
|
1570 , mActor(aActor) |
|
1571 , mStart(0) |
|
1572 , mLength(0) |
|
1573 , mDone(false) |
|
1574 { |
|
1575 // This may be created on any thread. |
|
1576 MOZ_ASSERT(aActor); |
|
1577 } |
|
1578 |
|
1579 nsresult |
|
1580 GetSlice(uint64_t aStart, |
|
1581 uint64_t aLength, |
|
1582 const nsAString& aContentType, |
|
1583 nsIDOMBlob** aSlice) |
|
1584 { |
|
1585 // This may be called on any thread. |
|
1586 MOZ_ASSERT(aSlice); |
|
1587 MOZ_ASSERT(mActor); |
|
1588 MOZ_ASSERT(!mSlice); |
|
1589 MOZ_ASSERT(!mDone); |
|
1590 |
|
1591 mStart = aStart; |
|
1592 mLength = aLength; |
|
1593 mContentType = aContentType; |
|
1594 |
|
1595 if (NS_IsMainThread()) { |
|
1596 RunInternal(false); |
|
1597 } |
|
1598 else { |
|
1599 nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); |
|
1600 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE); |
|
1601 |
|
1602 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL); |
|
1603 NS_ENSURE_SUCCESS(rv, rv); |
|
1604 |
|
1605 { |
|
1606 MonitorAutoLock lock(mMonitor); |
|
1607 while (!mDone) { |
|
1608 lock.Wait(); |
|
1609 } |
|
1610 } |
|
1611 } |
|
1612 |
|
1613 MOZ_ASSERT(!mActor); |
|
1614 MOZ_ASSERT(mDone); |
|
1615 |
|
1616 if (!mSlice) { |
|
1617 return NS_ERROR_UNEXPECTED; |
|
1618 } |
|
1619 |
|
1620 mSlice.forget(aSlice); |
|
1621 return NS_OK; |
|
1622 } |
|
1623 |
|
1624 NS_IMETHOD |
|
1625 Run() |
|
1626 { |
|
1627 MOZ_ASSERT(NS_IsMainThread()); |
|
1628 RunInternal(true); |
|
1629 return NS_OK; |
|
1630 } |
|
1631 |
|
1632 private: |
|
1633 void |
|
1634 RunInternal(bool aNotify) |
|
1635 { |
|
1636 MOZ_ASSERT(NS_IsMainThread()); |
|
1637 MOZ_ASSERT(mActor); |
|
1638 MOZ_ASSERT(!mSlice); |
|
1639 MOZ_ASSERT(!mDone); |
|
1640 |
|
1641 NS_ENSURE_TRUE_VOID(mActor->Manager()); |
|
1642 |
|
1643 NormalBlobConstructorParams normalParams; |
|
1644 normalParams.contentType() = mContentType; |
|
1645 normalParams.length() = mLength; |
|
1646 |
|
1647 ParentBlobConstructorParams params; |
|
1648 params.blobParams() = normalParams; |
|
1649 params.optionalInputStreamParams() = void_t(); |
|
1650 |
|
1651 auto* manager = static_cast<ContentParent*>(mActor->Manager()); |
|
1652 MOZ_ASSERT(manager); |
|
1653 |
|
1654 BlobParent* newActor = BlobParent::Create(manager, params); |
|
1655 MOZ_ASSERT(newActor); |
|
1656 |
|
1657 SlicedBlobConstructorParams slicedParams; |
|
1658 slicedParams.contentType() = mContentType; |
|
1659 slicedParams.begin() = mStart; |
|
1660 slicedParams.end() = mStart + mLength; |
|
1661 slicedParams.sourceParent() = mActor; |
|
1662 |
|
1663 ChildBlobConstructorParams otherSideParams = slicedParams; |
|
1664 |
|
1665 if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) { |
|
1666 mSlice = newActor->GetBlob(); |
|
1667 } |
|
1668 |
|
1669 mActor = nullptr; |
|
1670 |
|
1671 if (aNotify) { |
|
1672 MonitorAutoLock lock(mMonitor); |
|
1673 mDone = true; |
|
1674 lock.Notify(); |
|
1675 } |
|
1676 else { |
|
1677 mDone = true; |
|
1678 } |
|
1679 } |
|
1680 }; |
|
1681 |
|
1682 /******************************************************************************* |
|
1683 * BlobChild::RemoteBlob Implementation |
|
1684 ******************************************************************************/ |
|
1685 |
|
1686 NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, nsDOMFile, nsIRemoteBlob) |
|
1687 |
|
1688 already_AddRefed<nsIDOMBlob> |
|
1689 BlobParent:: |
|
1690 RemoteBlob::CreateSlice(uint64_t aStart, |
|
1691 uint64_t aLength, |
|
1692 const nsAString& aContentType) |
|
1693 { |
|
1694 if (!mActor) { |
|
1695 return nullptr; |
|
1696 } |
|
1697 |
|
1698 nsRefPtr<SliceHelper> helper = new SliceHelper(mActor); |
|
1699 |
|
1700 nsCOMPtr<nsIDOMBlob> slice; |
|
1701 nsresult rv = |
|
1702 helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice)); |
|
1703 NS_ENSURE_SUCCESS(rv, nullptr); |
|
1704 |
|
1705 return slice.forget(); |
|
1706 } |
|
1707 |
|
1708 NS_IMETHODIMP |
|
1709 BlobParent:: |
|
1710 RemoteBlob::GetInternalStream(nsIInputStream** aStream) |
|
1711 { |
|
1712 if (mInputStreamParams.type() != InputStreamParams::T__None) { |
|
1713 nsTArray<FileDescriptor> fds; |
|
1714 nsCOMPtr<nsIInputStream> realStream = |
|
1715 DeserializeInputStream(mInputStreamParams, fds); |
|
1716 if (!realStream) { |
|
1717 NS_WARNING("Failed to deserialize stream!"); |
|
1718 return NS_ERROR_UNEXPECTED; |
|
1719 } |
|
1720 |
|
1721 nsCOMPtr<nsIInputStream> stream = |
|
1722 new BlobInputStreamTether(realStream, this); |
|
1723 stream.forget(aStream); |
|
1724 return NS_OK; |
|
1725 } |
|
1726 |
|
1727 if (!mActor) { |
|
1728 return NS_ERROR_UNEXPECTED; |
|
1729 } |
|
1730 |
|
1731 nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this); |
|
1732 return helper->GetStream(aStream); |
|
1733 } |
|
1734 |
|
1735 NS_IMETHODIMP |
|
1736 BlobParent:: |
|
1737 RemoteBlob::GetLastModifiedDate(JSContext* cx, |
|
1738 JS::MutableHandle<JS::Value> aLastModifiedDate) |
|
1739 { |
|
1740 if (IsDateUnknown()) { |
|
1741 aLastModifiedDate.setNull(); |
|
1742 } else { |
|
1743 JSObject* date = JS_NewDateObjectMsec(cx, mLastModificationDate); |
|
1744 if (!date) { |
|
1745 return NS_ERROR_OUT_OF_MEMORY; |
|
1746 } |
|
1747 aLastModifiedDate.setObject(*date); |
|
1748 } |
|
1749 return NS_OK; |
|
1750 } |
|
1751 |
|
1752 void* |
|
1753 BlobParent:: |
|
1754 RemoteBlob::GetPBlob() |
|
1755 { |
|
1756 return static_cast<PBlobParent*>(mActor); |
|
1757 } |
|
1758 |
|
1759 /******************************************************************************* |
|
1760 * BlobParent |
|
1761 ******************************************************************************/ |
|
1762 |
|
1763 BlobParent::BlobParent(ContentParent* aManager, nsIDOMBlob* aBlob) |
|
1764 : mBlob(aBlob) |
|
1765 , mRemoteBlob(nullptr) |
|
1766 , mStrongManager(aManager) |
|
1767 , mOwnsBlob(true) |
|
1768 , mBlobIsFile(false) |
|
1769 { |
|
1770 MOZ_ASSERT(NS_IsMainThread()); |
|
1771 MOZ_ASSERT(aManager); |
|
1772 MOZ_ASSERT(aBlob); |
|
1773 |
|
1774 aBlob->AddRef(); |
|
1775 |
|
1776 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob); |
|
1777 mBlobIsFile = !!file; |
|
1778 } |
|
1779 |
|
1780 BlobParent::BlobParent(ContentParent* aManager, |
|
1781 const ParentBlobConstructorParams& aParams) |
|
1782 : mBlob(nullptr) |
|
1783 , mRemoteBlob(nullptr) |
|
1784 , mStrongManager(aManager) |
|
1785 , mOwnsBlob(false) |
|
1786 , mBlobIsFile(false) |
|
1787 { |
|
1788 MOZ_ASSERT(NS_IsMainThread()); |
|
1789 MOZ_ASSERT(aManager); |
|
1790 |
|
1791 ChildBlobConstructorParams::Type paramsType = aParams.blobParams().type(); |
|
1792 |
|
1793 mBlobIsFile = |
|
1794 paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams || |
|
1795 paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams; |
|
1796 |
|
1797 nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams); |
|
1798 MOZ_ASSERT(remoteBlob); |
|
1799 |
|
1800 remoteBlob->SetActor(this); |
|
1801 remoteBlob->MaybeSetInputStream(aParams); |
|
1802 remoteBlob.forget(&mRemoteBlob); |
|
1803 |
|
1804 mBlob = mRemoteBlob; |
|
1805 mOwnsBlob = true; |
|
1806 } |
|
1807 |
|
1808 BlobParent::~BlobParent() |
|
1809 { |
|
1810 } |
|
1811 |
|
1812 BlobParent* |
|
1813 BlobParent::Create(ContentParent* aManager, |
|
1814 const ParentBlobConstructorParams& aParams) |
|
1815 { |
|
1816 MOZ_ASSERT(NS_IsMainThread()); |
|
1817 MOZ_ASSERT(aManager); |
|
1818 |
|
1819 const ChildBlobConstructorParams& blobParams = aParams.blobParams(); |
|
1820 |
|
1821 switch (blobParams.type()) { |
|
1822 case ChildBlobConstructorParams::TNormalBlobConstructorParams: |
|
1823 case ChildBlobConstructorParams::TFileBlobConstructorParams: |
|
1824 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: |
|
1825 return new BlobParent(aManager, aParams); |
|
1826 |
|
1827 case ChildBlobConstructorParams::TSlicedBlobConstructorParams: { |
|
1828 const SlicedBlobConstructorParams& params = |
|
1829 blobParams.get_SlicedBlobConstructorParams(); |
|
1830 |
|
1831 auto* actor = |
|
1832 const_cast<BlobParent*>( |
|
1833 static_cast<const BlobParent*>(params.sourceParent())); |
|
1834 MOZ_ASSERT(actor); |
|
1835 |
|
1836 nsCOMPtr<nsIDOMBlob> source = actor->GetBlob(); |
|
1837 MOZ_ASSERT(source); |
|
1838 |
|
1839 nsCOMPtr<nsIDOMBlob> slice; |
|
1840 nsresult rv = |
|
1841 source->Slice(params.begin(), params.end(), params.contentType(), 3, |
|
1842 getter_AddRefs(slice)); |
|
1843 NS_ENSURE_SUCCESS(rv, nullptr); |
|
1844 |
|
1845 return new BlobParent(aManager, slice); |
|
1846 } |
|
1847 |
|
1848 default: |
|
1849 MOZ_CRASH("Unknown params!"); |
|
1850 } |
|
1851 |
|
1852 return nullptr; |
|
1853 } |
|
1854 |
|
1855 already_AddRefed<nsIDOMBlob> |
|
1856 BlobParent::GetBlob() |
|
1857 { |
|
1858 MOZ_ASSERT(NS_IsMainThread()); |
|
1859 MOZ_ASSERT(mBlob); |
|
1860 |
|
1861 nsCOMPtr<nsIDOMBlob> blob; |
|
1862 |
|
1863 // Remote blobs are held alive until the first call to GetBlob. Thereafter we |
|
1864 // only hold a weak reference. Normal blobs are held alive until the actor is |
|
1865 // destroyed. |
|
1866 if (mRemoteBlob && mOwnsBlob) { |
|
1867 blob = dont_AddRef(mBlob); |
|
1868 mOwnsBlob = false; |
|
1869 } |
|
1870 else { |
|
1871 blob = mBlob; |
|
1872 } |
|
1873 |
|
1874 MOZ_ASSERT(blob); |
|
1875 |
|
1876 return blob.forget(); |
|
1877 } |
|
1878 |
|
1879 bool |
|
1880 BlobParent::SetMysteryBlobInfo(const nsString& aName, |
|
1881 const nsString& aContentType, |
|
1882 uint64_t aLength, |
|
1883 uint64_t aLastModifiedDate) |
|
1884 { |
|
1885 MOZ_ASSERT(NS_IsMainThread()); |
|
1886 MOZ_ASSERT(mBlob); |
|
1887 MOZ_ASSERT(mRemoteBlob); |
|
1888 MOZ_ASSERT(aLastModifiedDate != UINT64_MAX); |
|
1889 |
|
1890 ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength, |
|
1891 aLastModifiedDate); |
|
1892 |
|
1893 FileBlobConstructorParams params(aName, aContentType, aLength, |
|
1894 aLastModifiedDate); |
|
1895 return SendResolveMystery(params); |
|
1896 } |
|
1897 |
|
1898 bool |
|
1899 BlobParent::SetMysteryBlobInfo(const nsString& aContentType, uint64_t aLength) |
|
1900 { |
|
1901 MOZ_ASSERT(NS_IsMainThread()); |
|
1902 MOZ_ASSERT(mBlob); |
|
1903 MOZ_ASSERT(mRemoteBlob); |
|
1904 |
|
1905 nsString voidString; |
|
1906 voidString.SetIsVoid(true); |
|
1907 |
|
1908 ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength, |
|
1909 UINT64_MAX); |
|
1910 |
|
1911 NormalBlobConstructorParams params(aContentType, aLength); |
|
1912 return SendResolveMystery(params); |
|
1913 } |
|
1914 |
|
1915 already_AddRefed<BlobParent::RemoteBlob> |
|
1916 BlobParent::CreateRemoteBlob(const ParentBlobConstructorParams& aParams) |
|
1917 { |
|
1918 MOZ_ASSERT(NS_IsMainThread()); |
|
1919 |
|
1920 const ChildBlobConstructorParams& blobParams = aParams.blobParams(); |
|
1921 |
|
1922 nsRefPtr<RemoteBlob> remoteBlob; |
|
1923 |
|
1924 switch (blobParams.type()) { |
|
1925 case ChildBlobConstructorParams::TNormalBlobConstructorParams: { |
|
1926 const NormalBlobConstructorParams& params = |
|
1927 blobParams.get_NormalBlobConstructorParams(); |
|
1928 remoteBlob = new RemoteBlob(params.contentType(), params.length()); |
|
1929 break; |
|
1930 } |
|
1931 |
|
1932 case ChildBlobConstructorParams::TFileBlobConstructorParams: { |
|
1933 const FileBlobConstructorParams& params = |
|
1934 blobParams.get_FileBlobConstructorParams(); |
|
1935 remoteBlob = |
|
1936 new RemoteBlob(params.name(), params.contentType(), params.length(), |
|
1937 params.modDate()); |
|
1938 break; |
|
1939 } |
|
1940 |
|
1941 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: { |
|
1942 remoteBlob = new RemoteBlob(); |
|
1943 break; |
|
1944 } |
|
1945 |
|
1946 default: |
|
1947 MOZ_CRASH("Unknown params!"); |
|
1948 } |
|
1949 |
|
1950 MOZ_ASSERT(remoteBlob); |
|
1951 |
|
1952 if (NS_FAILED(remoteBlob->SetMutable(false))) { |
|
1953 MOZ_CRASH("Failed to make remote blob immutable!"); |
|
1954 } |
|
1955 |
|
1956 return remoteBlob.forget(); |
|
1957 } |
|
1958 |
|
1959 void |
|
1960 BlobParent::NoteDyingRemoteBlob() |
|
1961 { |
|
1962 MOZ_ASSERT(mBlob); |
|
1963 MOZ_ASSERT(mRemoteBlob); |
|
1964 MOZ_ASSERT(!mOwnsBlob); |
|
1965 |
|
1966 // This may be called on any thread due to the fact that RemoteBlob is |
|
1967 // designed to be passed between threads. We must start the shutdown process |
|
1968 // on the main thread, so we proxy here if necessary. |
|
1969 if (!NS_IsMainThread()) { |
|
1970 nsCOMPtr<nsIRunnable> runnable = |
|
1971 NS_NewNonOwningRunnableMethod(this, &BlobParent::NoteDyingRemoteBlob); |
|
1972 if (NS_FAILED(NS_DispatchToMainThread(runnable))) { |
|
1973 MOZ_ASSERT(false, "Should never fail!"); |
|
1974 } |
|
1975 |
|
1976 return; |
|
1977 } |
|
1978 |
|
1979 // Must do this before calling Send__delete__ or we'll crash there trying to |
|
1980 // access a dangling pointer. |
|
1981 mBlob = nullptr; |
|
1982 mRemoteBlob = nullptr; |
|
1983 |
|
1984 mozilla::unused << PBlobParent::Send__delete__(this); |
|
1985 } |
|
1986 |
|
1987 void |
|
1988 BlobParent::NoteRunnableCompleted(OpenStreamRunnable* aRunnable) |
|
1989 { |
|
1990 MOZ_ASSERT(NS_IsMainThread()); |
|
1991 |
|
1992 for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) { |
|
1993 nsRevocableEventPtr<OpenStreamRunnable>& runnable = |
|
1994 mOpenStreamRunnables[index]; |
|
1995 |
|
1996 if (runnable.get() == aRunnable) { |
|
1997 runnable.Forget(); |
|
1998 mOpenStreamRunnables.RemoveElementAt(index); |
|
1999 return; |
|
2000 } |
|
2001 } |
|
2002 |
|
2003 MOZ_CRASH("Runnable not in our array!"); |
|
2004 } |
|
2005 |
|
2006 void |
|
2007 BlobParent::ActorDestroy(ActorDestroyReason aWhy) |
|
2008 { |
|
2009 MOZ_ASSERT(NS_IsMainThread()); |
|
2010 |
|
2011 if (mRemoteBlob) { |
|
2012 mRemoteBlob->SetActor(nullptr); |
|
2013 } |
|
2014 |
|
2015 if (mBlob && mOwnsBlob) { |
|
2016 mBlob->Release(); |
|
2017 } |
|
2018 |
|
2019 mStrongManager = nullptr; |
|
2020 } |
|
2021 |
|
2022 PBlobStreamParent* |
|
2023 BlobParent::AllocPBlobStreamParent() |
|
2024 { |
|
2025 MOZ_ASSERT(NS_IsMainThread()); |
|
2026 |
|
2027 return new InputStreamParent(); |
|
2028 } |
|
2029 |
|
2030 bool |
|
2031 BlobParent::RecvPBlobStreamConstructor(PBlobStreamParent* aActor) |
|
2032 { |
|
2033 MOZ_ASSERT(NS_IsMainThread()); |
|
2034 MOZ_ASSERT(aActor); |
|
2035 MOZ_ASSERT(mBlob); |
|
2036 MOZ_ASSERT(!mRemoteBlob); |
|
2037 |
|
2038 nsCOMPtr<nsIInputStream> stream; |
|
2039 nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream)); |
|
2040 NS_ENSURE_SUCCESS(rv, false); |
|
2041 |
|
2042 nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob); |
|
2043 |
|
2044 nsCOMPtr<IPrivateRemoteInputStream> remoteStream; |
|
2045 if (remoteBlob) { |
|
2046 remoteStream = do_QueryInterface(stream); |
|
2047 } |
|
2048 |
|
2049 // There are three cases in which we can use the stream obtained from the blob |
|
2050 // directly as our serialized stream: |
|
2051 // |
|
2052 // 1. The blob is not a remote blob. |
|
2053 // 2. The blob is a remote blob that represents this actor. |
|
2054 // 3. The blob is a remote blob representing a different actor but we |
|
2055 // already have a non-remote, i.e. serialized, serialized stream. |
|
2056 // |
|
2057 // In all other cases we need to be on a background thread before we can get |
|
2058 // to the real stream. |
|
2059 nsCOMPtr<nsIIPCSerializableInputStream> serializableStream; |
|
2060 if (!remoteBlob || |
|
2061 static_cast<PBlobParent*>(remoteBlob->GetPBlob()) == this || |
|
2062 !remoteStream) { |
|
2063 serializableStream = do_QueryInterface(stream); |
|
2064 if (!serializableStream) { |
|
2065 MOZ_ASSERT(false, "Must be serializable!"); |
|
2066 return false; |
|
2067 } |
|
2068 } |
|
2069 |
|
2070 nsCOMPtr<nsIEventTarget> target = |
|
2071 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID); |
|
2072 NS_ENSURE_TRUE(target, false); |
|
2073 |
|
2074 nsRefPtr<OpenStreamRunnable> runnable = |
|
2075 new OpenStreamRunnable(this, aActor, stream, serializableStream, target); |
|
2076 |
|
2077 rv = runnable->Dispatch(); |
|
2078 NS_ENSURE_SUCCESS(rv, false); |
|
2079 |
|
2080 // nsRevocableEventPtr lacks some of the operators needed for anything nicer. |
|
2081 *mOpenStreamRunnables.AppendElement() = runnable; |
|
2082 return true; |
|
2083 } |
|
2084 |
|
2085 bool |
|
2086 BlobParent::DeallocPBlobStreamParent(PBlobStreamParent* aActor) |
|
2087 { |
|
2088 MOZ_ASSERT(NS_IsMainThread()); |
|
2089 |
|
2090 delete static_cast<InputStreamParent*>(aActor); |
|
2091 return true; |
|
2092 } |
|
2093 |
|
2094 bool |
|
2095 BlobParent::RecvResolveMystery(const ResolveMysteryParams& aParams) |
|
2096 { |
|
2097 MOZ_ASSERT(NS_IsMainThread()); |
|
2098 MOZ_ASSERT(mBlob); |
|
2099 MOZ_ASSERT(!mRemoteBlob); |
|
2100 MOZ_ASSERT(mOwnsBlob); |
|
2101 |
|
2102 if (!mBlobIsFile) { |
|
2103 MOZ_ASSERT(false, "Must always be a file!"); |
|
2104 return false; |
|
2105 } |
|
2106 |
|
2107 nsDOMFileBase* blob = ToConcreteBlob(mBlob); |
|
2108 |
|
2109 switch (aParams.type()) { |
|
2110 case ResolveMysteryParams::TNormalBlobConstructorParams: { |
|
2111 const NormalBlobConstructorParams& params = |
|
2112 aParams.get_NormalBlobConstructorParams(); |
|
2113 nsString voidString; |
|
2114 voidString.SetIsVoid(true); |
|
2115 blob->SetLazyData(voidString, params.contentType(), |
|
2116 params.length(), UINT64_MAX); |
|
2117 break; |
|
2118 } |
|
2119 |
|
2120 case ResolveMysteryParams::TFileBlobConstructorParams: { |
|
2121 const FileBlobConstructorParams& params = |
|
2122 aParams.get_FileBlobConstructorParams(); |
|
2123 blob->SetLazyData(params.name(), params.contentType(), |
|
2124 params.length(), params.modDate()); |
|
2125 break; |
|
2126 } |
|
2127 |
|
2128 default: |
|
2129 MOZ_CRASH("Unknown params!"); |
|
2130 } |
|
2131 |
|
2132 return true; |
|
2133 } |
|
2134 |
|
2135 bool |
|
2136 InputStreamChild::Recv__delete__(const InputStreamParams& aParams, |
|
2137 const OptionalFileDescriptorSet& aFDs) |
|
2138 { |
|
2139 MOZ_ASSERT(NS_IsMainThread()); |
|
2140 MOZ_ASSERT(mRemoteStream); |
|
2141 |
|
2142 nsTArray<FileDescriptor> fds; |
|
2143 if (aFDs.type() == OptionalFileDescriptorSet::TPFileDescriptorSetChild) { |
|
2144 FileDescriptorSetChild* fdSetActor = |
|
2145 static_cast<FileDescriptorSetChild*>(aFDs.get_PFileDescriptorSetChild()); |
|
2146 MOZ_ASSERT(fdSetActor); |
|
2147 |
|
2148 fdSetActor->ForgetFileDescriptors(fds); |
|
2149 MOZ_ASSERT(!fds.IsEmpty()); |
|
2150 |
|
2151 fdSetActor->Send__delete__(fdSetActor); |
|
2152 } |
|
2153 |
|
2154 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds); |
|
2155 if (!stream) { |
|
2156 return false; |
|
2157 } |
|
2158 |
|
2159 mRemoteStream->SetStream(stream); |
|
2160 return true; |
|
2161 } |
|
2162 |
|
2163 bool |
|
2164 InputStreamParent::Recv__delete__(const InputStreamParams& aParams, |
|
2165 const OptionalFileDescriptorSet& aFDs) |
|
2166 { |
|
2167 MOZ_ASSERT(NS_IsMainThread()); |
|
2168 MOZ_ASSERT(mRemoteStream); |
|
2169 |
|
2170 if (aFDs.type() != OptionalFileDescriptorSet::Tvoid_t) { |
|
2171 NS_WARNING("Child cannot send FileDescriptors to the parent!"); |
|
2172 return false; |
|
2173 } |
|
2174 |
|
2175 nsTArray<FileDescriptor> fds; |
|
2176 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds); |
|
2177 if (!stream) { |
|
2178 return false; |
|
2179 } |
|
2180 |
|
2181 MOZ_ASSERT(fds.IsEmpty()); |
|
2182 |
|
2183 mRemoteStream->SetStream(stream); |
|
2184 return true; |
|
2185 } |