1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 
7 #include "IPCBlobInputStreamParent.h"
8 #include "IPCBlobInputStreamStorage.h"
9 #include "mozilla/ipc/IPCStreamUtils.h"
10 #include "nsContentUtils.h"
11 
12 namespace mozilla {
13 namespace dom {
14 
15 template <typename M>
Create(nsIInputStream * aInputStream,uint64_t aSize,uint64_t aChildID,nsresult * aRv,M * aManager)16 /* static */ IPCBlobInputStreamParent* IPCBlobInputStreamParent::Create(
17     nsIInputStream* aInputStream, uint64_t aSize, uint64_t aChildID,
18     nsresult* aRv, M* aManager) {
19   MOZ_ASSERT(aInputStream);
20   MOZ_ASSERT(aRv);
21 
22   nsID id;
23   *aRv = nsContentUtils::GenerateUUIDInPlace(id);
24   if (NS_WARN_IF(NS_FAILED(*aRv))) {
25     return nullptr;
26   }
27 
28   IPCBlobInputStreamStorage::Get()->AddStream(aInputStream, id, aSize,
29                                               aChildID);
30 
31   return new IPCBlobInputStreamParent(id, aSize, aManager);
32 }
33 
Create(const nsID & aID,uint64_t aSize,PBackgroundParent * aManager)34 /* static */ IPCBlobInputStreamParent* IPCBlobInputStreamParent::Create(
35     const nsID& aID, uint64_t aSize, PBackgroundParent* aManager) {
36   IPCBlobInputStreamParent* actor =
37       new IPCBlobInputStreamParent(aID, aSize, aManager);
38 
39   actor->mCallback = IPCBlobInputStreamStorage::Get()->TakeCallback(aID);
40 
41   return actor;
42 }
43 
IPCBlobInputStreamParent(const nsID & aID,uint64_t aSize,nsIContentParent * aManager)44 IPCBlobInputStreamParent::IPCBlobInputStreamParent(const nsID& aID,
45                                                    uint64_t aSize,
46                                                    nsIContentParent* aManager)
47     : mID(aID),
48       mSize(aSize),
49       mContentManager(aManager),
50       mPBackgroundManager(nullptr),
51       mMigrating(false) {}
52 
IPCBlobInputStreamParent(const nsID & aID,uint64_t aSize,PBackgroundParent * aManager)53 IPCBlobInputStreamParent::IPCBlobInputStreamParent(const nsID& aID,
54                                                    uint64_t aSize,
55                                                    PBackgroundParent* aManager)
56     : mID(aID),
57       mSize(aSize),
58       mContentManager(nullptr),
59       mPBackgroundManager(aManager),
60       mMigrating(false) {}
61 
ActorDestroy(IProtocol::ActorDestroyReason aReason)62 void IPCBlobInputStreamParent::ActorDestroy(
63     IProtocol::ActorDestroyReason aReason) {
64   MOZ_ASSERT(mContentManager || mPBackgroundManager);
65 
66   mContentManager = nullptr;
67   mPBackgroundManager = nullptr;
68 
69   RefPtr<IPCBlobInputStreamParentCallback> callback;
70   mCallback.swap(callback);
71 
72   RefPtr<IPCBlobInputStreamStorage> storage = IPCBlobInputStreamStorage::Get();
73 
74   if (mMigrating) {
75     if (callback && storage) {
76       // We need to assign this callback to the next parent.
77       IPCBlobInputStreamStorage::Get()->StoreCallback(mID, callback);
78     }
79     return;
80   }
81 
82   if (storage) {
83     storage->ForgetStream(mID);
84   }
85 
86   if (callback) {
87     callback->ActorDestroyed(mID);
88   }
89 }
90 
SetCallback(IPCBlobInputStreamParentCallback * aCallback)91 void IPCBlobInputStreamParent::SetCallback(
92     IPCBlobInputStreamParentCallback* aCallback) {
93   MOZ_ASSERT(aCallback);
94   MOZ_ASSERT(!mCallback);
95 
96   mCallback = aCallback;
97 }
98 
RecvStreamNeeded()99 mozilla::ipc::IPCResult IPCBlobInputStreamParent::RecvStreamNeeded() {
100   MOZ_ASSERT(mContentManager || mPBackgroundManager);
101 
102   nsCOMPtr<nsIInputStream> stream;
103   IPCBlobInputStreamStorage::Get()->GetStream(mID, 0, mSize,
104                                               getter_AddRefs(stream));
105   if (!stream) {
106     if (!SendStreamReady(void_t())) {
107       return IPC_FAIL(this, "SendStreamReady failed");
108     }
109 
110     return IPC_OK();
111   }
112 
113   mozilla::ipc::AutoIPCStream ipcStream;
114   bool ok = false;
115 
116   if (mContentManager) {
117     MOZ_ASSERT(NS_IsMainThread());
118     ok = ipcStream.Serialize(stream, mContentManager);
119   } else {
120     MOZ_ASSERT(mPBackgroundManager);
121     ok = ipcStream.Serialize(stream, mPBackgroundManager);
122   }
123 
124   if (NS_WARN_IF(!ok)) {
125     return IPC_FAIL(this, "SendStreamReady failed");
126   }
127 
128   if (!SendStreamReady(ipcStream.TakeValue())) {
129     return IPC_FAIL(this, "SendStreamReady failed");
130   }
131 
132   return IPC_OK();
133 }
134 
RecvClose()135 mozilla::ipc::IPCResult IPCBlobInputStreamParent::RecvClose() {
136   MOZ_ASSERT(mContentManager || mPBackgroundManager);
137 
138   Unused << Send__delete__(this);
139   return IPC_OK();
140 }
141 
Recv__delete__()142 mozilla::ipc::IPCResult IPCBlobInputStreamParent::Recv__delete__() {
143   MOZ_ASSERT(mContentManager || mPBackgroundManager);
144   mMigrating = true;
145   return IPC_OK();
146 }
147 
HasValidStream() const148 bool IPCBlobInputStreamParent::HasValidStream() const {
149   nsCOMPtr<nsIInputStream> stream;
150   IPCBlobInputStreamStorage::Get()->GetStream(mID, 0, mSize,
151                                               getter_AddRefs(stream));
152   return !!stream;
153 }
154 
155 }  // namespace dom
156 }  // namespace mozilla
157