dom/ipc/Blob.cpp

changeset 0
6474c204b198
equal deleted inserted replaced
-1:000000000000 0:79514a7239d0
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 }

mercurial