Line data Source code
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 "IPCBlobInputStreamStorage.h"
8 :
9 : #include "mozilla/dom/ContentParent.h"
10 : #include "mozilla/StaticMutex.h"
11 : #include "mozilla/StaticPtr.h"
12 : #include "nsIPropertyBag2.h"
13 : #include "nsStreamUtils.h"
14 :
15 : namespace mozilla {
16 :
17 : using namespace hal;
18 :
19 : namespace dom {
20 :
21 : namespace {
22 3 : StaticMutex gMutex;
23 3 : StaticRefPtr<IPCBlobInputStreamStorage> gStorage;
24 : }
25 :
26 0 : NS_INTERFACE_MAP_BEGIN(IPCBlobInputStreamStorage)
27 0 : NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIObserver)
28 0 : NS_INTERFACE_MAP_ENTRY(nsIObserver)
29 0 : NS_INTERFACE_MAP_END
30 :
31 9 : NS_IMPL_ADDREF(IPCBlobInputStreamStorage)
32 0 : NS_IMPL_RELEASE(IPCBlobInputStreamStorage)
33 :
34 3 : IPCBlobInputStreamStorage::IPCBlobInputStreamStorage()
35 3 : {}
36 :
37 0 : IPCBlobInputStreamStorage::~IPCBlobInputStreamStorage()
38 0 : {}
39 :
40 : /* static */ IPCBlobInputStreamStorage*
41 0 : IPCBlobInputStreamStorage::Get()
42 : {
43 0 : return gStorage;
44 : }
45 :
46 : /* static */ void
47 3 : IPCBlobInputStreamStorage::Initialize()
48 : {
49 3 : MOZ_ASSERT(!gStorage);
50 :
51 3 : gStorage = new IPCBlobInputStreamStorage();
52 :
53 6 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
54 3 : if (obs) {
55 3 : obs->AddObserver(gStorage, "xpcom-shutdown", false);
56 3 : obs->AddObserver(gStorage, "ipc:content-shutdown", false);
57 : }
58 3 : }
59 :
60 : NS_IMETHODIMP
61 0 : IPCBlobInputStreamStorage::Observe(nsISupports* aSubject, const char* aTopic,
62 : const char16_t* aData)
63 : {
64 0 : if (!strcmp(aTopic, "xpcom-shutdown")) {
65 0 : nsCOMPtr<nsIObserverService> obs = mozilla::services::GetObserverService();
66 0 : if (obs) {
67 0 : obs->RemoveObserver(this, "xpcom-shutdown");
68 0 : obs->RemoveObserver(this, "ipc:content-shutdown");
69 : }
70 :
71 0 : gStorage = nullptr;
72 0 : return NS_OK;
73 : }
74 :
75 0 : MOZ_ASSERT(!strcmp(aTopic, "ipc:content-shutdown"));
76 :
77 0 : nsCOMPtr<nsIPropertyBag2> props = do_QueryInterface(aSubject);
78 0 : if (NS_WARN_IF(!props)) {
79 0 : return NS_ERROR_FAILURE;
80 : }
81 :
82 0 : uint64_t childID = CONTENT_PROCESS_ID_UNKNOWN;
83 0 : props->GetPropertyAsUint64(NS_LITERAL_STRING("childID"), &childID);
84 0 : if (NS_WARN_IF(childID == CONTENT_PROCESS_ID_UNKNOWN)) {
85 0 : return NS_ERROR_FAILURE;
86 : }
87 :
88 0 : mozilla::StaticMutexAutoLock lock(gMutex);
89 :
90 0 : for (auto iter = mStorage.Iter(); !iter.Done(); iter.Next()) {
91 0 : if (iter.Data()->mChildID == childID) {
92 0 : iter.Remove();
93 : }
94 : }
95 :
96 0 : return NS_OK;
97 : }
98 :
99 : void
100 0 : IPCBlobInputStreamStorage::AddStream(nsIInputStream* aInputStream,
101 : const nsID& aID,
102 : uint64_t aChildID)
103 : {
104 0 : MOZ_ASSERT(aInputStream);
105 :
106 0 : StreamData* data = new StreamData();
107 0 : data->mInputStream = aInputStream;
108 0 : data->mChildID = aChildID;
109 :
110 0 : mozilla::StaticMutexAutoLock lock(gMutex);
111 0 : mStorage.Put(aID, data);
112 0 : }
113 :
114 : void
115 0 : IPCBlobInputStreamStorage::ForgetStream(const nsID& aID)
116 : {
117 0 : mozilla::StaticMutexAutoLock lock(gMutex);
118 0 : mStorage.Remove(aID);
119 0 : }
120 :
121 : void
122 0 : IPCBlobInputStreamStorage::GetStream(const nsID& aID,
123 : nsIInputStream** aInputStream)
124 : {
125 0 : *aInputStream = nullptr;
126 :
127 0 : nsCOMPtr<nsIInputStream> inputStream;
128 :
129 : // NS_CloneInputStream cannot be called when the mutex is locked because it
130 : // can, recursively call GetStream() in case the child actor lives on the
131 : // parent process.
132 : {
133 0 : mozilla::StaticMutexAutoLock lock(gMutex);
134 0 : StreamData* data = mStorage.Get(aID);
135 0 : if (!data) {
136 0 : return;
137 : }
138 :
139 0 : inputStream = data->mInputStream;
140 : }
141 :
142 0 : MOZ_ASSERT(inputStream);
143 :
144 : // We cannot return always the same inputStream because not all of them are
145 : // able to be reused. Better to clone them.
146 :
147 0 : nsCOMPtr<nsIInputStream> clonedStream;
148 0 : nsCOMPtr<nsIInputStream> replacementStream;
149 :
150 : nsresult rv =
151 0 : NS_CloneInputStream(inputStream, getter_AddRefs(clonedStream),
152 0 : getter_AddRefs(replacementStream));
153 0 : if (NS_WARN_IF(NS_FAILED(rv))) {
154 0 : return;
155 : }
156 :
157 0 : if (replacementStream) {
158 0 : mozilla::StaticMutexAutoLock lock(gMutex);
159 0 : StreamData* data = mStorage.Get(aID);
160 : // data can be gone in the meantime.
161 0 : if (!data) {
162 0 : return;
163 : }
164 :
165 0 : data->mInputStream = replacementStream;
166 : }
167 :
168 0 : clonedStream.forget(aInputStream);
169 : }
170 :
171 : void
172 0 : IPCBlobInputStreamStorage::StoreCallback(const nsID& aID,
173 : IPCBlobInputStreamParentCallback* aCallback)
174 : {
175 0 : MOZ_ASSERT(aCallback);
176 :
177 0 : mozilla::StaticMutexAutoLock lock(gMutex);
178 0 : StreamData* data = mStorage.Get(aID);
179 0 : if (data) {
180 0 : MOZ_ASSERT(!data->mCallback);
181 0 : data->mCallback = aCallback;
182 : }
183 0 : }
184 :
185 : already_AddRefed<IPCBlobInputStreamParentCallback>
186 0 : IPCBlobInputStreamStorage::TakeCallback(const nsID& aID)
187 : {
188 0 : mozilla::StaticMutexAutoLock lock(gMutex);
189 0 : StreamData* data = mStorage.Get(aID);
190 0 : if (!data) {
191 0 : return nullptr;
192 : }
193 :
194 0 : RefPtr<IPCBlobInputStreamParentCallback> callback;
195 0 : data->mCallback.swap(callback);
196 0 : return callback.forget();
197 : }
198 :
199 : } // namespace dom
200 : } // namespace mozilla
|