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