Wed, 31 Dec 2014 06:09:35 +0100
Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.
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/. */
5 #include "Blob.h"
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"
31 #define PRIVATE_REMOTE_INPUT_STREAM_IID \
32 {0x30c7699f, 0x51d2, 0x48c8, {0xad, 0x56, 0xc0, 0x16, 0xd7, 0x6f, 0x71, 0x27}}
34 using namespace mozilla;
35 using namespace mozilla::dom;
36 using namespace mozilla::ipc;
38 namespace {
40 enum ActorType
41 {
42 ChildActor,
43 ParentActor
44 };
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());
53 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
54 NS_ENSURE_TRUE_VOID(mainThread);
56 if (NS_FAILED(NS_ProxyRelease(mainThread, aDoomed, true))) {
57 NS_WARNING("Failed to proxy release to main thread!");
58 }
59 }
61 class NS_NO_VTABLE IPrivateRemoteInputStream : public nsISupports
62 {
63 public:
64 NS_DECLARE_STATIC_IID_ACCESSOR(PRIVATE_REMOTE_INPUT_STREAM_IID)
66 // This will return the underlying stream.
67 virtual nsIInputStream*
68 BlockAndGetInternalStream() = 0;
69 };
71 NS_DEFINE_STATIC_IID_ACCESSOR(IPrivateRemoteInputStream,
72 PRIVATE_REMOTE_INPUT_STREAM_IID)
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;
83 nsIMultiplexInputStream* mWeakMultiplexStream;
84 nsISeekableStream* mWeakSeekableStream;
85 nsIIPCSerializableInputStream* mWeakSerializableStream;
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)
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);
101 nsCOMPtr<nsIMultiplexInputStream> multiplexStream =
102 do_QueryInterface(aStream);
103 if (multiplexStream) {
104 MOZ_ASSERT(SameCOMIdentity(aStream, multiplexStream));
105 mWeakMultiplexStream = multiplexStream;
106 }
108 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
109 if (seekableStream) {
110 MOZ_ASSERT(SameCOMIdentity(aStream, seekableStream));
111 mWeakSeekableStream = seekableStream;
112 }
114 nsCOMPtr<nsIIPCSerializableInputStream> serializableStream =
115 do_QueryInterface(aStream);
116 if (serializableStream) {
117 MOZ_ASSERT(SameCOMIdentity(aStream, serializableStream));
118 mWeakSerializableStream = serializableStream;
119 }
120 }
122 protected:
123 virtual ~BlobInputStreamTether()
124 {
125 MOZ_ASSERT(mStream);
126 MOZ_ASSERT(mSourceBlob);
128 if (!NS_IsMainThread()) {
129 mStream = nullptr;
130 ProxyReleaseToMainThread(mSourceBlob);
131 }
132 }
133 };
135 NS_IMPL_ADDREF(BlobInputStreamTether)
136 NS_IMPL_RELEASE(BlobInputStreamTether)
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
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;
159 public:
160 NS_DECL_THREADSAFE_ISUPPORTS
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 }
170 void
171 Serialize(InputStreamParams& aParams,
172 FileDescriptorArray& /* aFileDescriptors */)
173 {
174 nsCOMPtr<nsIRemoteBlob> remote = do_QueryInterface(mSourceBlob);
175 MOZ_ASSERT(remote);
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 }
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 }
196 void
197 SetStream(nsIInputStream* aStream)
198 {
199 MOZ_ASSERT(NS_IsMainThread());
200 MOZ_ASSERT(aStream);
202 nsCOMPtr<nsIInputStream> stream = aStream;
203 nsCOMPtr<nsISeekableStream> seekableStream = do_QueryInterface(aStream);
205 MOZ_ASSERT_IF(seekableStream, SameCOMIdentity(aStream, seekableStream));
207 {
208 mozilla::MonitorAutoLock lock(mMonitor);
210 MOZ_ASSERT(!mStream);
211 MOZ_ASSERT(!mWeakSeekableStream);
213 mStream.swap(stream);
214 mWeakSeekableStream = seekableStream;
216 mMonitor.Notify();
217 }
218 }
220 NS_IMETHOD
221 Close() MOZ_OVERRIDE
222 {
223 nsresult rv = BlockAndWaitForStream();
224 NS_ENSURE_SUCCESS(rv, rv);
226 nsCOMPtr<nsIDOMBlob> sourceBlob;
227 mSourceBlob.swap(sourceBlob);
229 rv = mStream->Close();
230 NS_ENSURE_SUCCESS(rv, rv);
232 return NS_OK;
233 }
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 }
243 nsresult rv = BlockAndWaitForStream();
244 NS_ENSURE_SUCCESS(rv, rv);
246 rv = mStream->Available(aAvailable);
247 NS_ENSURE_SUCCESS(rv, rv);
249 return NS_OK;
250 }
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);
258 rv = mStream->Read(aBuffer, aCount, aResult);
259 NS_ENSURE_SUCCESS(rv, rv);
261 return NS_OK;
262 }
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);
271 rv = mStream->ReadSegments(aWriter, aClosure, aCount, aResult);
272 NS_ENSURE_SUCCESS(rv, rv);
274 return NS_OK;
275 }
277 NS_IMETHOD
278 IsNonBlocking(bool* aNonBlocking) MOZ_OVERRIDE
279 {
280 NS_ENSURE_ARG_POINTER(aNonBlocking);
282 *aNonBlocking = false;
283 return NS_OK;
284 }
286 NS_IMETHOD
287 Seek(int32_t aWhence, int64_t aOffset) MOZ_OVERRIDE
288 {
289 nsresult rv = BlockAndWaitForStream();
290 NS_ENSURE_SUCCESS(rv, rv);
292 if (!mWeakSeekableStream) {
293 NS_WARNING("Underlying blob stream is not seekable!");
294 return NS_ERROR_NO_INTERFACE;
295 }
297 rv = mWeakSeekableStream->Seek(aWhence, aOffset);
298 NS_ENSURE_SUCCESS(rv, rv);
300 return NS_OK;
301 }
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 }
314 nsresult rv = BlockAndWaitForStream();
315 NS_ENSURE_SUCCESS(rv, rv);
317 if (!mWeakSeekableStream) {
318 NS_WARNING("Underlying blob stream is not seekable!");
319 return NS_ERROR_NO_INTERFACE;
320 }
322 rv = mWeakSeekableStream->Tell(aResult);
323 NS_ENSURE_SUCCESS(rv, rv);
325 return NS_OK;
326 }
328 NS_IMETHOD
329 SetEOF()
330 {
331 nsresult rv = BlockAndWaitForStream();
332 NS_ENSURE_SUCCESS(rv, rv);
334 if (!mWeakSeekableStream) {
335 NS_WARNING("Underlying blob stream is not seekable!");
336 return NS_ERROR_NO_INTERFACE;
337 }
339 rv = mWeakSeekableStream->SetEOF();
340 NS_ENSURE_SUCCESS(rv, rv);
342 return NS_OK;
343 }
345 virtual nsIInputStream*
346 BlockAndGetInternalStream()
347 {
348 MOZ_ASSERT(!NS_IsMainThread());
350 nsresult rv = BlockAndWaitForStream();
351 NS_ENSURE_SUCCESS(rv, nullptr);
353 return mStream;
354 }
356 private:
357 virtual ~RemoteInputStream()
358 {
359 if (!NS_IsMainThread()) {
360 mStream = nullptr;
361 mWeakSeekableStream = nullptr;
362 ProxyReleaseToMainThread(mSourceBlob);
363 }
364 }
366 void
367 ReallyBlockAndWaitForStream()
368 {
369 mozilla::DebugOnly<bool> waited;
371 {
372 mozilla::MonitorAutoLock lock(mMonitor);
374 waited = !mStream;
376 while (!mStream) {
377 mMonitor.Wait();
378 }
379 }
381 MOZ_ASSERT(mStream);
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 }
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 }
401 ReallyBlockAndWaitForStream();
403 return NS_OK;
404 }
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 }
419 return !!mWeakSeekableStream;
420 }
421 };
423 NS_IMPL_ADDREF(RemoteInputStream)
424 NS_IMPL_RELEASE(RemoteInputStream)
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
434 class InputStreamChild MOZ_FINAL
435 : public PBlobStreamChild
436 {
437 nsRefPtr<RemoteInputStream> mRemoteStream;
439 public:
440 InputStreamChild(RemoteInputStream* aRemoteStream)
441 : mRemoteStream(aRemoteStream)
442 {
443 MOZ_ASSERT(NS_IsMainThread());
444 MOZ_ASSERT(aRemoteStream);
445 }
447 InputStreamChild()
448 {
449 MOZ_ASSERT(NS_IsMainThread());
450 }
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 };
459 class InputStreamParent MOZ_FINAL
460 : public PBlobStreamParent
461 {
462 nsRefPtr<RemoteInputStream> mRemoteStream;
464 public:
465 InputStreamParent(RemoteInputStream* aRemoteStream)
466 : mRemoteStream(aRemoteStream)
467 {
468 MOZ_ASSERT(NS_IsMainThread());
469 MOZ_ASSERT(aRemoteStream);
470 }
472 InputStreamParent()
473 {
474 MOZ_ASSERT(NS_IsMainThread());
475 }
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 };
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 }
493 } // anonymous namespace
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>;
506 // Only safe to access these pointers if mRevoked is false!
507 BlobParent* mBlobActor;
508 PBlobStreamParent* mStreamActor;
510 nsCOMPtr<nsIInputStream> mStream;
511 nsCOMPtr<nsIIPCSerializableInputStream> mSerializable;
512 nsCOMPtr<nsIEventTarget> mTarget;
514 bool mRevoked;
515 bool mClosing;
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 }
535 NS_IMETHOD
536 Run()
537 {
538 if (NS_IsMainThread()) {
539 return SendResponse();
540 }
542 if (!mClosing) {
543 return OpenStream();
544 }
546 return CloseStream();
547 }
549 nsresult
550 Dispatch()
551 {
552 MOZ_ASSERT(NS_IsMainThread());
553 MOZ_ASSERT(mTarget);
555 nsresult rv = mTarget->Dispatch(this, NS_DISPATCH_NORMAL);
556 NS_ENSURE_SUCCESS(rv, rv);
558 return NS_OK;
559 }
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 }
573 nsresult
574 OpenStream()
575 {
576 MOZ_ASSERT(!NS_IsMainThread());
577 MOZ_ASSERT(mStream);
579 if (!mSerializable) {
580 nsCOMPtr<IPrivateRemoteInputStream> remoteStream =
581 do_QueryInterface(mStream);
582 MOZ_ASSERT(remoteStream, "Must QI to IPrivateRemoteInputStream here!");
584 nsCOMPtr<nsIInputStream> realStream =
585 remoteStream->BlockAndGetInternalStream();
586 NS_ENSURE_TRUE(realStream, NS_ERROR_FAILURE);
588 mSerializable = do_QueryInterface(realStream);
589 if (!mSerializable) {
590 MOZ_ASSERT(false, "Must be serializable!");
591 return NS_ERROR_FAILURE;
592 }
594 mStream.swap(realStream);
595 }
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 }
604 nsresult rv = NS_DispatchToMainThread(this, NS_DISPATCH_NORMAL);
605 NS_ENSURE_SUCCESS(rv, rv);
607 return NS_OK;
608 }
610 nsresult
611 CloseStream()
612 {
613 MOZ_ASSERT(!NS_IsMainThread());
614 MOZ_ASSERT(mStream);
616 // Going to always release here.
617 nsCOMPtr<nsIInputStream> stream;
618 mStream.swap(stream);
620 nsresult rv = stream->Close();
621 NS_ENSURE_SUCCESS(rv, rv);
623 return NS_OK;
624 }
626 nsresult
627 SendResponse()
628 {
629 MOZ_ASSERT(NS_IsMainThread());
631 MOZ_ASSERT(mStream);
632 MOZ_ASSERT(mSerializable);
633 MOZ_ASSERT(mTarget);
634 MOZ_ASSERT(!mClosing);
636 nsCOMPtr<nsIIPCSerializableInputStream> serializable;
637 mSerializable.swap(serializable);
639 if (mRevoked) {
640 MOZ_ASSERT(!mBlobActor);
641 MOZ_ASSERT(!mStreamActor);
642 }
643 else {
644 MOZ_ASSERT(mBlobActor);
645 MOZ_ASSERT(mStreamActor);
647 InputStreamParams params;
648 nsAutoTArray<FileDescriptor, 10> fds;
649 serializable->Serialize(params, fds);
651 MOZ_ASSERT(params.type() != InputStreamParams::T__None);
653 PFileDescriptorSetParent* fdSet = nullptr;
655 if (!fds.IsEmpty()) {
656 auto* manager = static_cast<ContentParent*>(mBlobActor->Manager());
657 MOZ_ASSERT(manager);
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 }
667 OptionalFileDescriptorSet optionalFDs;
668 if (fdSet) {
669 optionalFDs = fdSet;
670 } else {
671 optionalFDs = mozilla::void_t();
672 }
674 unused <<
675 PBlobStreamParent::Send__delete__(mStreamActor, params, optionalFDs);
677 mBlobActor->NoteRunnableCompleted(this);
679 #ifdef DEBUG
680 mBlobActor = nullptr;
681 mStreamActor = nullptr;
682 #endif
683 }
685 mClosing = true;
687 nsCOMPtr<nsIEventTarget> target;
688 mTarget.swap(target);
690 nsresult rv = target->Dispatch(this, NS_DISPATCH_NORMAL);
691 NS_ENSURE_SUCCESS(rv, rv);
693 return NS_OK;
694 }
695 };
697 /*******************************************************************************
698 * BlobChild::RemoteBlob Declaration
699 ******************************************************************************/
701 class BlobChild::RemoteBlob MOZ_FINAL
702 : public nsDOMFile
703 , public nsIRemoteBlob
704 {
705 class StreamHelper;
706 class SliceHelper;
708 BlobChild* mActor;
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 }
721 RemoteBlob(const nsAString& aContentType, uint64_t aLength)
722 : nsDOMFile(aContentType, aLength)
723 , mActor(nullptr)
724 {
725 mImmutable = true;
726 }
728 RemoteBlob()
729 : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
730 , mActor(nullptr)
731 {
732 mImmutable = true;
733 }
735 void
736 SetActor(BlobChild* aActor)
737 {
738 MOZ_ASSERT(!aActor || !mActor);
739 mActor = aActor;
740 }
742 NS_DECL_ISUPPORTS_INHERITED
744 virtual already_AddRefed<nsIDOMBlob>
745 CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
746 MOZ_OVERRIDE;
748 NS_IMETHOD
749 GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
751 NS_IMETHOD
752 GetLastModifiedDate(JSContext* cx,
753 JS::MutableHandle<JS::Value> aLastModifiedDate)
754 MOZ_OVERRIDE;
756 virtual void*
757 GetPBlob() MOZ_OVERRIDE;
759 private:
760 ~RemoteBlob()
761 {
762 if (mActor) {
763 mActor->NoteDyingRemoteBlob();
764 }
765 }
766 };
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;
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 }
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);
798 if (NS_IsMainThread()) {
799 RunInternal(false);
800 }
801 else {
802 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
803 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
805 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
806 NS_ENSURE_SUCCESS(rv, rv);
808 {
809 MonitorAutoLock lock(mMonitor);
810 while (!mDone) {
811 lock.Wait();
812 }
813 }
814 }
816 MOZ_ASSERT(!mActor);
817 MOZ_ASSERT(mDone);
819 if (!mInputStream) {
820 return NS_ERROR_UNEXPECTED;
821 }
823 mInputStream.forget(aInputStream);
824 return NS_OK;
825 }
827 NS_IMETHOD
828 Run()
829 {
830 MOZ_ASSERT(NS_IsMainThread());
831 RunInternal(true);
832 return NS_OK;
833 }
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);
844 nsRefPtr<RemoteInputStream> stream =
845 new RemoteInputStream(mSourceBlob, ChildActor);
847 InputStreamChild* streamActor = new InputStreamChild(stream);
848 if (mActor->SendPBlobStreamConstructor(streamActor)) {
849 stream.swap(mInputStream);
850 }
852 mActor = nullptr;
854 if (aNotify) {
855 MonitorAutoLock lock(mMonitor);
856 mDone = true;
857 lock.Notify();
858 }
859 else {
860 mDone = true;
861 }
862 }
863 };
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;
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 }
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);
900 mStart = aStart;
901 mLength = aLength;
902 mContentType = aContentType;
904 if (NS_IsMainThread()) {
905 RunInternal(false);
906 }
907 else {
908 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
909 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
911 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
912 NS_ENSURE_SUCCESS(rv, rv);
914 {
915 MonitorAutoLock lock(mMonitor);
916 while (!mDone) {
917 lock.Wait();
918 }
919 }
920 }
922 MOZ_ASSERT(!mActor);
923 MOZ_ASSERT(mDone);
925 if (!mSlice) {
926 return NS_ERROR_UNEXPECTED;
927 }
929 mSlice.forget(aSlice);
930 return NS_OK;
931 }
933 NS_IMETHOD
934 Run()
935 {
936 MOZ_ASSERT(NS_IsMainThread());
937 RunInternal(true);
938 return NS_OK;
939 }
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);
950 NS_ENSURE_TRUE_VOID(mActor->Manager());
952 NormalBlobConstructorParams normalParams;
953 normalParams.contentType() = mContentType;
954 normalParams.length() = mLength;
956 auto* manager = static_cast<ContentChild*>(mActor->Manager());
957 MOZ_ASSERT(manager);
959 BlobChild* newActor = BlobChild::Create(manager, normalParams);
960 MOZ_ASSERT(newActor);
962 SlicedBlobConstructorParams slicedParams;
963 slicedParams.contentType() = mContentType;
964 slicedParams.begin() = mStart;
965 slicedParams.end() = mStart + mLength;
966 slicedParams.sourceChild() = mActor;
968 ParentBlobConstructorParams otherSideParams;
969 otherSideParams.blobParams() = slicedParams;
970 otherSideParams.optionalInputStreamParams() = mozilla::void_t();
972 if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
973 mSlice = newActor->GetBlob();
974 }
976 mActor = nullptr;
978 if (aNotify) {
979 MonitorAutoLock lock(mMonitor);
980 mDone = true;
981 lock.Notify();
982 }
983 else {
984 mDone = true;
985 }
986 }
987 };
989 /*******************************************************************************
990 * BlobChild::RemoteBlob Implementation
991 ******************************************************************************/
993 NS_IMPL_ISUPPORTS_INHERITED(BlobChild::RemoteBlob, nsDOMFile, nsIRemoteBlob)
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 }
1005 nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
1007 nsCOMPtr<nsIDOMBlob> slice;
1008 nsresult rv =
1009 helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
1010 NS_ENSURE_SUCCESS(rv, nullptr);
1012 return slice.forget();
1013 }
1015 NS_IMETHODIMP
1016 BlobChild::
1017 RemoteBlob::GetInternalStream(nsIInputStream** aStream)
1018 {
1019 if (!mActor) {
1020 return NS_ERROR_UNEXPECTED;
1021 }
1023 nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
1024 return helper->GetStream(aStream);
1025 }
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 }
1044 void*
1045 BlobChild::
1046 RemoteBlob::GetPBlob()
1047 {
1048 return static_cast<PBlobChild*>(mActor);
1049 }
1051 /*******************************************************************************
1052 * BlobChild
1053 ******************************************************************************/
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);
1066 aBlob->AddRef();
1068 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
1069 mBlobIsFile = !!file;
1070 }
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);
1083 ChildBlobConstructorParams::Type paramsType = aParams.type();
1085 mBlobIsFile =
1086 paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
1087 paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
1089 nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
1090 MOZ_ASSERT(remoteBlob);
1092 remoteBlob->SetActor(this);
1093 remoteBlob.forget(&mRemoteBlob);
1095 mBlob = mRemoteBlob;
1096 mOwnsBlob = true;
1097 }
1099 BlobChild::~BlobChild()
1100 {
1101 }
1103 BlobChild*
1104 BlobChild::Create(ContentChild* aManager,
1105 const ChildBlobConstructorParams& aParams)
1106 {
1107 MOZ_ASSERT(NS_IsMainThread());
1108 MOZ_ASSERT(aManager);
1110 switch (aParams.type()) {
1111 case ChildBlobConstructorParams::TNormalBlobConstructorParams:
1112 case ChildBlobConstructorParams::TFileBlobConstructorParams:
1113 case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
1114 return new BlobChild(aManager, aParams);
1116 case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
1117 const SlicedBlobConstructorParams& params =
1118 aParams.get_SlicedBlobConstructorParams();
1120 auto* actor =
1121 const_cast<BlobChild*>(
1122 static_cast<const BlobChild*>(params.sourceChild()));
1123 MOZ_ASSERT(actor);
1125 nsCOMPtr<nsIDOMBlob> source = actor->GetBlob();
1126 MOZ_ASSERT(source);
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);
1134 return new BlobChild(aManager, slice);
1135 }
1137 default:
1138 MOZ_CRASH("Unknown params!");
1139 }
1141 return nullptr;
1142 }
1144 already_AddRefed<nsIDOMBlob>
1145 BlobChild::GetBlob()
1146 {
1147 MOZ_ASSERT(NS_IsMainThread());
1148 MOZ_ASSERT(mBlob);
1150 nsCOMPtr<nsIDOMBlob> blob;
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 }
1163 MOZ_ASSERT(blob);
1165 return blob.forget();
1166 }
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);
1179 ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength,
1180 aLastModifiedDate);
1182 FileBlobConstructorParams params(aName, aContentType, aLength,
1183 aLastModifiedDate);
1184 return SendResolveMystery(params);
1185 }
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);
1194 nsString voidString;
1195 voidString.SetIsVoid(true);
1197 ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
1198 UINT64_MAX);
1200 NormalBlobConstructorParams params(aContentType, aLength);
1201 return SendResolveMystery(params);
1202 }
1204 already_AddRefed<BlobChild::RemoteBlob>
1205 BlobChild::CreateRemoteBlob(const ChildBlobConstructorParams& aParams)
1206 {
1207 MOZ_ASSERT(NS_IsMainThread());
1209 nsRefPtr<RemoteBlob> remoteBlob;
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 }
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 }
1228 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: {
1229 remoteBlob = new RemoteBlob();
1230 break;
1231 }
1233 default:
1234 MOZ_CRASH("Unknown params!");
1235 }
1237 MOZ_ASSERT(remoteBlob);
1239 if (NS_FAILED(remoteBlob->SetMutable(false))) {
1240 MOZ_CRASH("Failed to make remote blob immutable!");
1241 }
1243 return remoteBlob.forget();
1244 }
1246 void
1247 BlobChild::NoteDyingRemoteBlob()
1248 {
1249 MOZ_ASSERT(mBlob);
1250 MOZ_ASSERT(mRemoteBlob);
1251 MOZ_ASSERT(!mOwnsBlob);
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 }
1263 return;
1264 }
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;
1271 PBlobChild::Send__delete__(this);
1272 }
1274 void
1275 BlobChild::ActorDestroy(ActorDestroyReason aWhy)
1276 {
1277 MOZ_ASSERT(NS_IsMainThread());
1279 if (mRemoteBlob) {
1280 mRemoteBlob->SetActor(nullptr);
1281 }
1283 if (mBlob && mOwnsBlob) {
1284 mBlob->Release();
1285 }
1287 mStrongManager = nullptr;
1288 }
1290 PBlobStreamChild*
1291 BlobChild::AllocPBlobStreamChild()
1292 {
1293 MOZ_ASSERT(NS_IsMainThread());
1295 return new InputStreamChild();
1296 }
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);
1306 nsCOMPtr<nsIInputStream> stream;
1307 nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
1308 NS_ENSURE_SUCCESS(rv, false);
1310 nsCOMPtr<nsIIPCSerializableInputStream> serializable =
1311 do_QueryInterface(stream);
1312 if (!serializable) {
1313 MOZ_ASSERT(false, "Must be serializable!");
1314 return false;
1315 }
1317 InputStreamParams params;
1318 nsTArray<FileDescriptor> fds;
1319 serializable->Serialize(params, fds);
1321 MOZ_ASSERT(params.type() != InputStreamParams::T__None);
1322 MOZ_ASSERT(fds.IsEmpty());
1324 return aActor->Send__delete__(aActor, params, mozilla::void_t());
1325 }
1327 bool
1328 BlobChild::DeallocPBlobStreamChild(PBlobStreamChild* aActor)
1329 {
1330 MOZ_ASSERT(NS_IsMainThread());
1332 delete static_cast<InputStreamChild*>(aActor);
1333 return true;
1334 }
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);
1344 if (!mBlobIsFile) {
1345 MOZ_ASSERT(false, "Must always be a file!");
1346 return false;
1347 }
1349 nsDOMFileBase* blob = ToConcreteBlob(mBlob);
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 }
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 }
1370 default:
1371 MOZ_CRASH("Unknown params!");
1372 }
1374 return true;
1375 }
1377 /*******************************************************************************
1378 * BlobParent::RemoteBlob Declaration
1379 ******************************************************************************/
1381 class BlobParent::RemoteBlob MOZ_FINAL
1382 : public nsDOMFile
1383 , public nsIRemoteBlob
1384 {
1385 class StreamHelper;
1386 class SliceHelper;
1388 BlobParent* mActor;
1389 InputStreamParams mInputStreamParams;
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 }
1402 RemoteBlob(const nsAString& aContentType, uint64_t aLength)
1403 : nsDOMFile(aContentType, aLength)
1404 , mActor(nullptr)
1405 {
1406 mImmutable = true;
1407 }
1409 RemoteBlob()
1410 : nsDOMFile(EmptyString(), EmptyString(), UINT64_MAX, UINT64_MAX)
1411 , mActor(nullptr)
1412 {
1413 mImmutable = true;
1414 }
1416 void
1417 SetActor(BlobParent* aActor)
1418 {
1419 MOZ_ASSERT(!aActor || !mActor);
1420 mActor = aActor;
1421 }
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 }
1433 NS_DECL_ISUPPORTS_INHERITED
1435 virtual already_AddRefed<nsIDOMBlob>
1436 CreateSlice(uint64_t aStart, uint64_t aLength, const nsAString& aContentType)
1437 MOZ_OVERRIDE;
1439 NS_IMETHOD
1440 GetInternalStream(nsIInputStream** aStream) MOZ_OVERRIDE;
1442 NS_IMETHOD
1443 GetLastModifiedDate(JSContext* cx,
1444 JS::MutableHandle<JS::Value> aLastModifiedDate)
1445 MOZ_OVERRIDE;
1447 virtual void*
1448 GetPBlob() MOZ_OVERRIDE;
1450 private:
1451 ~RemoteBlob()
1452 {
1453 if (mActor) {
1454 mActor->NoteDyingRemoteBlob();
1455 }
1456 }
1457 };
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;
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 }
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);
1489 if (NS_IsMainThread()) {
1490 RunInternal(false);
1491 }
1492 else {
1493 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
1494 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
1496 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
1497 NS_ENSURE_SUCCESS(rv, rv);
1499 {
1500 MonitorAutoLock lock(mMonitor);
1501 while (!mDone) {
1502 lock.Wait();
1503 }
1504 }
1505 }
1507 MOZ_ASSERT(!mActor);
1508 MOZ_ASSERT(mDone);
1510 if (!mInputStream) {
1511 return NS_ERROR_UNEXPECTED;
1512 }
1514 mInputStream.forget(aInputStream);
1515 return NS_OK;
1516 }
1518 NS_IMETHOD
1519 Run()
1520 {
1521 MOZ_ASSERT(NS_IsMainThread());
1522 RunInternal(true);
1523 return NS_OK;
1524 }
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);
1535 nsRefPtr<RemoteInputStream> stream =
1536 new RemoteInputStream(mSourceBlob, ParentActor);
1538 InputStreamParent* streamActor = new InputStreamParent(stream);
1539 if (mActor->SendPBlobStreamConstructor(streamActor)) {
1540 stream.swap(mInputStream);
1541 }
1543 mActor = nullptr;
1545 if (aNotify) {
1546 MonitorAutoLock lock(mMonitor);
1547 mDone = true;
1548 lock.Notify();
1549 }
1550 else {
1551 mDone = true;
1552 }
1553 }
1554 };
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;
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 }
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);
1591 mStart = aStart;
1592 mLength = aLength;
1593 mContentType = aContentType;
1595 if (NS_IsMainThread()) {
1596 RunInternal(false);
1597 }
1598 else {
1599 nsCOMPtr<nsIThread> mainThread = do_GetMainThread();
1600 NS_ENSURE_TRUE(mainThread, NS_ERROR_FAILURE);
1602 nsresult rv = mainThread->Dispatch(this, NS_DISPATCH_NORMAL);
1603 NS_ENSURE_SUCCESS(rv, rv);
1605 {
1606 MonitorAutoLock lock(mMonitor);
1607 while (!mDone) {
1608 lock.Wait();
1609 }
1610 }
1611 }
1613 MOZ_ASSERT(!mActor);
1614 MOZ_ASSERT(mDone);
1616 if (!mSlice) {
1617 return NS_ERROR_UNEXPECTED;
1618 }
1620 mSlice.forget(aSlice);
1621 return NS_OK;
1622 }
1624 NS_IMETHOD
1625 Run()
1626 {
1627 MOZ_ASSERT(NS_IsMainThread());
1628 RunInternal(true);
1629 return NS_OK;
1630 }
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);
1641 NS_ENSURE_TRUE_VOID(mActor->Manager());
1643 NormalBlobConstructorParams normalParams;
1644 normalParams.contentType() = mContentType;
1645 normalParams.length() = mLength;
1647 ParentBlobConstructorParams params;
1648 params.blobParams() = normalParams;
1649 params.optionalInputStreamParams() = void_t();
1651 auto* manager = static_cast<ContentParent*>(mActor->Manager());
1652 MOZ_ASSERT(manager);
1654 BlobParent* newActor = BlobParent::Create(manager, params);
1655 MOZ_ASSERT(newActor);
1657 SlicedBlobConstructorParams slicedParams;
1658 slicedParams.contentType() = mContentType;
1659 slicedParams.begin() = mStart;
1660 slicedParams.end() = mStart + mLength;
1661 slicedParams.sourceParent() = mActor;
1663 ChildBlobConstructorParams otherSideParams = slicedParams;
1665 if (mActor->Manager()->SendPBlobConstructor(newActor, otherSideParams)) {
1666 mSlice = newActor->GetBlob();
1667 }
1669 mActor = nullptr;
1671 if (aNotify) {
1672 MonitorAutoLock lock(mMonitor);
1673 mDone = true;
1674 lock.Notify();
1675 }
1676 else {
1677 mDone = true;
1678 }
1679 }
1680 };
1682 /*******************************************************************************
1683 * BlobChild::RemoteBlob Implementation
1684 ******************************************************************************/
1686 NS_IMPL_ISUPPORTS_INHERITED(BlobParent::RemoteBlob, nsDOMFile, nsIRemoteBlob)
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 }
1698 nsRefPtr<SliceHelper> helper = new SliceHelper(mActor);
1700 nsCOMPtr<nsIDOMBlob> slice;
1701 nsresult rv =
1702 helper->GetSlice(aStart, aLength, aContentType, getter_AddRefs(slice));
1703 NS_ENSURE_SUCCESS(rv, nullptr);
1705 return slice.forget();
1706 }
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 }
1721 nsCOMPtr<nsIInputStream> stream =
1722 new BlobInputStreamTether(realStream, this);
1723 stream.forget(aStream);
1724 return NS_OK;
1725 }
1727 if (!mActor) {
1728 return NS_ERROR_UNEXPECTED;
1729 }
1731 nsRefPtr<StreamHelper> helper = new StreamHelper(mActor, this);
1732 return helper->GetStream(aStream);
1733 }
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 }
1752 void*
1753 BlobParent::
1754 RemoteBlob::GetPBlob()
1755 {
1756 return static_cast<PBlobParent*>(mActor);
1757 }
1759 /*******************************************************************************
1760 * BlobParent
1761 ******************************************************************************/
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);
1774 aBlob->AddRef();
1776 nsCOMPtr<nsIDOMFile> file = do_QueryInterface(aBlob);
1777 mBlobIsFile = !!file;
1778 }
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);
1791 ChildBlobConstructorParams::Type paramsType = aParams.blobParams().type();
1793 mBlobIsFile =
1794 paramsType == ChildBlobConstructorParams::TFileBlobConstructorParams ||
1795 paramsType == ChildBlobConstructorParams::TMysteryBlobConstructorParams;
1797 nsRefPtr<RemoteBlob> remoteBlob = CreateRemoteBlob(aParams);
1798 MOZ_ASSERT(remoteBlob);
1800 remoteBlob->SetActor(this);
1801 remoteBlob->MaybeSetInputStream(aParams);
1802 remoteBlob.forget(&mRemoteBlob);
1804 mBlob = mRemoteBlob;
1805 mOwnsBlob = true;
1806 }
1808 BlobParent::~BlobParent()
1809 {
1810 }
1812 BlobParent*
1813 BlobParent::Create(ContentParent* aManager,
1814 const ParentBlobConstructorParams& aParams)
1815 {
1816 MOZ_ASSERT(NS_IsMainThread());
1817 MOZ_ASSERT(aManager);
1819 const ChildBlobConstructorParams& blobParams = aParams.blobParams();
1821 switch (blobParams.type()) {
1822 case ChildBlobConstructorParams::TNormalBlobConstructorParams:
1823 case ChildBlobConstructorParams::TFileBlobConstructorParams:
1824 case ChildBlobConstructorParams::TMysteryBlobConstructorParams:
1825 return new BlobParent(aManager, aParams);
1827 case ChildBlobConstructorParams::TSlicedBlobConstructorParams: {
1828 const SlicedBlobConstructorParams& params =
1829 blobParams.get_SlicedBlobConstructorParams();
1831 auto* actor =
1832 const_cast<BlobParent*>(
1833 static_cast<const BlobParent*>(params.sourceParent()));
1834 MOZ_ASSERT(actor);
1836 nsCOMPtr<nsIDOMBlob> source = actor->GetBlob();
1837 MOZ_ASSERT(source);
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);
1845 return new BlobParent(aManager, slice);
1846 }
1848 default:
1849 MOZ_CRASH("Unknown params!");
1850 }
1852 return nullptr;
1853 }
1855 already_AddRefed<nsIDOMBlob>
1856 BlobParent::GetBlob()
1857 {
1858 MOZ_ASSERT(NS_IsMainThread());
1859 MOZ_ASSERT(mBlob);
1861 nsCOMPtr<nsIDOMBlob> blob;
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 }
1874 MOZ_ASSERT(blob);
1876 return blob.forget();
1877 }
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);
1890 ToConcreteBlob(mBlob)->SetLazyData(aName, aContentType, aLength,
1891 aLastModifiedDate);
1893 FileBlobConstructorParams params(aName, aContentType, aLength,
1894 aLastModifiedDate);
1895 return SendResolveMystery(params);
1896 }
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);
1905 nsString voidString;
1906 voidString.SetIsVoid(true);
1908 ToConcreteBlob(mBlob)->SetLazyData(voidString, aContentType, aLength,
1909 UINT64_MAX);
1911 NormalBlobConstructorParams params(aContentType, aLength);
1912 return SendResolveMystery(params);
1913 }
1915 already_AddRefed<BlobParent::RemoteBlob>
1916 BlobParent::CreateRemoteBlob(const ParentBlobConstructorParams& aParams)
1917 {
1918 MOZ_ASSERT(NS_IsMainThread());
1920 const ChildBlobConstructorParams& blobParams = aParams.blobParams();
1922 nsRefPtr<RemoteBlob> remoteBlob;
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 }
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 }
1941 case ChildBlobConstructorParams::TMysteryBlobConstructorParams: {
1942 remoteBlob = new RemoteBlob();
1943 break;
1944 }
1946 default:
1947 MOZ_CRASH("Unknown params!");
1948 }
1950 MOZ_ASSERT(remoteBlob);
1952 if (NS_FAILED(remoteBlob->SetMutable(false))) {
1953 MOZ_CRASH("Failed to make remote blob immutable!");
1954 }
1956 return remoteBlob.forget();
1957 }
1959 void
1960 BlobParent::NoteDyingRemoteBlob()
1961 {
1962 MOZ_ASSERT(mBlob);
1963 MOZ_ASSERT(mRemoteBlob);
1964 MOZ_ASSERT(!mOwnsBlob);
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 }
1976 return;
1977 }
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;
1984 mozilla::unused << PBlobParent::Send__delete__(this);
1985 }
1987 void
1988 BlobParent::NoteRunnableCompleted(OpenStreamRunnable* aRunnable)
1989 {
1990 MOZ_ASSERT(NS_IsMainThread());
1992 for (uint32_t index = 0; index < mOpenStreamRunnables.Length(); index++) {
1993 nsRevocableEventPtr<OpenStreamRunnable>& runnable =
1994 mOpenStreamRunnables[index];
1996 if (runnable.get() == aRunnable) {
1997 runnable.Forget();
1998 mOpenStreamRunnables.RemoveElementAt(index);
1999 return;
2000 }
2001 }
2003 MOZ_CRASH("Runnable not in our array!");
2004 }
2006 void
2007 BlobParent::ActorDestroy(ActorDestroyReason aWhy)
2008 {
2009 MOZ_ASSERT(NS_IsMainThread());
2011 if (mRemoteBlob) {
2012 mRemoteBlob->SetActor(nullptr);
2013 }
2015 if (mBlob && mOwnsBlob) {
2016 mBlob->Release();
2017 }
2019 mStrongManager = nullptr;
2020 }
2022 PBlobStreamParent*
2023 BlobParent::AllocPBlobStreamParent()
2024 {
2025 MOZ_ASSERT(NS_IsMainThread());
2027 return new InputStreamParent();
2028 }
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);
2038 nsCOMPtr<nsIInputStream> stream;
2039 nsresult rv = mBlob->GetInternalStream(getter_AddRefs(stream));
2040 NS_ENSURE_SUCCESS(rv, false);
2042 nsCOMPtr<nsIRemoteBlob> remoteBlob = do_QueryInterface(mBlob);
2044 nsCOMPtr<IPrivateRemoteInputStream> remoteStream;
2045 if (remoteBlob) {
2046 remoteStream = do_QueryInterface(stream);
2047 }
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 }
2070 nsCOMPtr<nsIEventTarget> target =
2071 do_GetService(NS_STREAMTRANSPORTSERVICE_CONTRACTID);
2072 NS_ENSURE_TRUE(target, false);
2074 nsRefPtr<OpenStreamRunnable> runnable =
2075 new OpenStreamRunnable(this, aActor, stream, serializableStream, target);
2077 rv = runnable->Dispatch();
2078 NS_ENSURE_SUCCESS(rv, false);
2080 // nsRevocableEventPtr lacks some of the operators needed for anything nicer.
2081 *mOpenStreamRunnables.AppendElement() = runnable;
2082 return true;
2083 }
2085 bool
2086 BlobParent::DeallocPBlobStreamParent(PBlobStreamParent* aActor)
2087 {
2088 MOZ_ASSERT(NS_IsMainThread());
2090 delete static_cast<InputStreamParent*>(aActor);
2091 return true;
2092 }
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);
2102 if (!mBlobIsFile) {
2103 MOZ_ASSERT(false, "Must always be a file!");
2104 return false;
2105 }
2107 nsDOMFileBase* blob = ToConcreteBlob(mBlob);
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 }
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 }
2128 default:
2129 MOZ_CRASH("Unknown params!");
2130 }
2132 return true;
2133 }
2135 bool
2136 InputStreamChild::Recv__delete__(const InputStreamParams& aParams,
2137 const OptionalFileDescriptorSet& aFDs)
2138 {
2139 MOZ_ASSERT(NS_IsMainThread());
2140 MOZ_ASSERT(mRemoteStream);
2142 nsTArray<FileDescriptor> fds;
2143 if (aFDs.type() == OptionalFileDescriptorSet::TPFileDescriptorSetChild) {
2144 FileDescriptorSetChild* fdSetActor =
2145 static_cast<FileDescriptorSetChild*>(aFDs.get_PFileDescriptorSetChild());
2146 MOZ_ASSERT(fdSetActor);
2148 fdSetActor->ForgetFileDescriptors(fds);
2149 MOZ_ASSERT(!fds.IsEmpty());
2151 fdSetActor->Send__delete__(fdSetActor);
2152 }
2154 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
2155 if (!stream) {
2156 return false;
2157 }
2159 mRemoteStream->SetStream(stream);
2160 return true;
2161 }
2163 bool
2164 InputStreamParent::Recv__delete__(const InputStreamParams& aParams,
2165 const OptionalFileDescriptorSet& aFDs)
2166 {
2167 MOZ_ASSERT(NS_IsMainThread());
2168 MOZ_ASSERT(mRemoteStream);
2170 if (aFDs.type() != OptionalFileDescriptorSet::Tvoid_t) {
2171 NS_WARNING("Child cannot send FileDescriptors to the parent!");
2172 return false;
2173 }
2175 nsTArray<FileDescriptor> fds;
2176 nsCOMPtr<nsIInputStream> stream = DeserializeInputStream(aParams, fds);
2177 if (!stream) {
2178 return false;
2179 }
2181 MOZ_ASSERT(fds.IsEmpty());
2183 mRemoteStream->SetStream(stream);
2184 return true;
2185 }