1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set sw=2 ts=8 et tw=80 : */
3
4 /* This Source Code Form is subject to the terms of the Mozilla Public
5 * License, v. 2.0. If a copy of the MPL was not distributed with this
6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7
8 // HttpLog.h should generally be included first
9 #include "HttpLog.h"
10
11 #include "HttpBackgroundChannelParent.h"
12
13 #include "HttpChannelParent.h"
14 #include "mozilla/ipc/BackgroundParent.h"
15 #include "mozilla/IntegerPrintfMacros.h"
16 #include "mozilla/Unused.h"
17 #include "nsIBackgroundChannelRegistrar.h"
18 #include "nsNetCID.h"
19 #include "nsQueryObject.h"
20 #include "nsThreadUtils.h"
21
22 using mozilla::dom::ContentParent;
23 using mozilla::ipc::AssertIsInMainProcess;
24 using mozilla::ipc::AssertIsOnBackgroundThread;
25 using mozilla::ipc::BackgroundParent;
26 using mozilla::ipc::IPCResult;
27 using mozilla::ipc::IsOnBackgroundThread;
28
29 namespace mozilla {
30 namespace net {
31
32 /*
33 * Helper class for continuing the AsyncOpen procedure on main thread.
34 */
35 class ContinueAsyncOpenRunnable final : public Runnable {
36 public:
ContinueAsyncOpenRunnable(HttpBackgroundChannelParent * aActor,const uint64_t & aChannelId)37 ContinueAsyncOpenRunnable(HttpBackgroundChannelParent* aActor,
38 const uint64_t& aChannelId)
39 : Runnable("net::ContinueAsyncOpenRunnable"),
40 mActor(aActor),
41 mChannelId(aChannelId) {
42 AssertIsInMainProcess();
43 AssertIsOnBackgroundThread();
44 MOZ_ASSERT(mActor);
45 }
46
Run()47 NS_IMETHOD Run() override {
48 LOG(
49 ("HttpBackgroundChannelParent::ContinueAsyncOpen [this=%p "
50 "channelId=%" PRIu64 "]\n",
51 mActor.get(), mChannelId));
52 AssertIsInMainProcess();
53 MOZ_ASSERT(NS_IsMainThread());
54
55 nsCOMPtr<nsIBackgroundChannelRegistrar> registrar =
56 do_GetService(NS_BACKGROUNDCHANNELREGISTRAR_CONTRACTID);
57 MOZ_ASSERT(registrar);
58
59 registrar->LinkBackgroundChannel(mChannelId, mActor);
60 return NS_OK;
61 }
62
63 private:
64 RefPtr<HttpBackgroundChannelParent> mActor;
65 const uint64_t mChannelId;
66 };
67
HttpBackgroundChannelParent()68 HttpBackgroundChannelParent::HttpBackgroundChannelParent()
69 : mIPCOpened(true),
70 mBgThreadMutex("HttpBackgroundChannelParent::BgThreadMutex") {
71 AssertIsInMainProcess();
72 AssertIsOnBackgroundThread();
73
74 {
75 MutexAutoLock lock(mBgThreadMutex);
76 mBackgroundThread = NS_GetCurrentThread();
77 }
78 }
79
~HttpBackgroundChannelParent()80 HttpBackgroundChannelParent::~HttpBackgroundChannelParent() {
81 MOZ_ASSERT(NS_IsMainThread() || IsOnBackgroundThread());
82 MOZ_ASSERT(!mIPCOpened);
83 }
84
Init(const uint64_t & aChannelId)85 nsresult HttpBackgroundChannelParent::Init(const uint64_t& aChannelId) {
86 LOG(("HttpBackgroundChannelParent::Init [this=%p channelId=%" PRIu64 "]\n",
87 this, aChannelId));
88 AssertIsInMainProcess();
89 AssertIsOnBackgroundThread();
90
91 RefPtr<ContinueAsyncOpenRunnable> runnable =
92 new ContinueAsyncOpenRunnable(this, aChannelId);
93
94 return NS_DispatchToMainThread(runnable);
95 }
96
LinkToChannel(HttpChannelParent * aChannelParent)97 void HttpBackgroundChannelParent::LinkToChannel(
98 HttpChannelParent* aChannelParent) {
99 LOG(("HttpBackgroundChannelParent::LinkToChannel [this=%p channel=%p]\n",
100 this, aChannelParent));
101 AssertIsInMainProcess();
102 MOZ_ASSERT(NS_IsMainThread());
103
104 if (!mIPCOpened) {
105 return;
106 }
107
108 mChannelParent = aChannelParent;
109 }
110
OnChannelClosed()111 void HttpBackgroundChannelParent::OnChannelClosed() {
112 LOG(("HttpBackgroundChannelParent::OnChannelClosed [this=%p]\n", this));
113 AssertIsInMainProcess();
114 MOZ_ASSERT(NS_IsMainThread());
115
116 if (!mIPCOpened) {
117 return;
118 }
119
120 nsresult rv;
121
122 {
123 MutexAutoLock lock(mBgThreadMutex);
124 RefPtr<HttpBackgroundChannelParent> self = this;
125 rv = mBackgroundThread->Dispatch(
126 NS_NewRunnableFunction(
127 "net::HttpBackgroundChannelParent::OnChannelClosed",
128 [self]() {
129 LOG(("HttpBackgroundChannelParent::DeleteRunnable [this=%p]\n",
130 self.get()));
131 AssertIsOnBackgroundThread();
132
133 if (!self->mIPCOpened.compareExchange(true, false)) {
134 return;
135 }
136
137 Unused << self->Send__delete__(self);
138 }),
139 NS_DISPATCH_NORMAL);
140 }
141
142 Unused << NS_WARN_IF(NS_FAILED(rv));
143 }
144
OnStartRequestSent()145 bool HttpBackgroundChannelParent::OnStartRequestSent() {
146 LOG(("HttpBackgroundChannelParent::OnStartRequestSent [this=%p]\n", this));
147 AssertIsInMainProcess();
148
149 if (NS_WARN_IF(!mIPCOpened)) {
150 return false;
151 }
152
153 if (!IsOnBackgroundThread()) {
154 MutexAutoLock lock(mBgThreadMutex);
155 nsresult rv = mBackgroundThread->Dispatch(
156 NewRunnableMethod(
157 "net::HttpBackgroundChannelParent::OnStartRequestSent", this,
158 &HttpBackgroundChannelParent::OnStartRequestSent),
159 NS_DISPATCH_NORMAL);
160
161 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
162
163 return NS_SUCCEEDED(rv);
164 }
165
166 return SendOnStartRequestSent();
167 }
168
OnTransportAndData(const nsresult & aChannelStatus,const nsresult & aTransportStatus,const uint64_t & aOffset,const uint32_t & aCount,const nsCString & aData)169 bool HttpBackgroundChannelParent::OnTransportAndData(
170 const nsresult& aChannelStatus, const nsresult& aTransportStatus,
171 const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) {
172 LOG(("HttpBackgroundChannelParent::OnTransportAndData [this=%p]\n", this));
173 AssertIsInMainProcess();
174
175 if (NS_WARN_IF(!mIPCOpened)) {
176 return false;
177 }
178
179 if (!IsOnBackgroundThread()) {
180 MutexAutoLock lock(mBgThreadMutex);
181 nsresult rv = mBackgroundThread->Dispatch(
182 NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
183 const uint32_t, const nsCString>(
184 "net::HttpBackgroundChannelParent::OnTransportAndData", this,
185 &HttpBackgroundChannelParent::OnTransportAndData, aChannelStatus,
186 aTransportStatus, aOffset, aCount, aData),
187 NS_DISPATCH_NORMAL);
188
189 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
190
191 return NS_SUCCEEDED(rv);
192 }
193
194 return SendOnTransportAndData(aChannelStatus, aTransportStatus, aOffset,
195 aCount, aData);
196 }
197
OnStopRequest(const nsresult & aChannelStatus,const ResourceTimingStruct & aTiming,const nsHttpHeaderArray & aResponseTrailers)198 bool HttpBackgroundChannelParent::OnStopRequest(
199 const nsresult& aChannelStatus, const ResourceTimingStruct& aTiming,
200 const nsHttpHeaderArray& aResponseTrailers) {
201 LOG(
202 ("HttpBackgroundChannelParent::OnStopRequest [this=%p "
203 "status=%" PRIx32 "]\n",
204 this, static_cast<uint32_t>(aChannelStatus)));
205 AssertIsInMainProcess();
206
207 if (NS_WARN_IF(!mIPCOpened)) {
208 return false;
209 }
210
211 if (!IsOnBackgroundThread()) {
212 MutexAutoLock lock(mBgThreadMutex);
213 nsresult rv = mBackgroundThread->Dispatch(
214 NewRunnableMethod<const nsresult, const ResourceTimingStruct,
215 const nsHttpHeaderArray>(
216 "net::HttpBackgroundChannelParent::OnStopRequest", this,
217 &HttpBackgroundChannelParent::OnStopRequest, aChannelStatus,
218 aTiming, aResponseTrailers),
219 NS_DISPATCH_NORMAL);
220
221 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
222
223 return NS_SUCCEEDED(rv);
224 }
225
226 // See the child code for why we do this.
227 TimeStamp lastActTabOpt = nsHttp::GetLastActiveTabLoadOptimizationHit();
228
229 return SendOnStopRequest(aChannelStatus, aTiming, lastActTabOpt,
230 aResponseTrailers);
231 }
232
OnProgress(const int64_t & aProgress,const int64_t & aProgressMax)233 bool HttpBackgroundChannelParent::OnProgress(const int64_t& aProgress,
234 const int64_t& aProgressMax) {
235 LOG(("HttpBackgroundChannelParent::OnProgress [this=%p progress=%" PRId64
236 " max=%" PRId64 "]\n",
237 this, aProgress, aProgressMax));
238 AssertIsInMainProcess();
239
240 if (NS_WARN_IF(!mIPCOpened)) {
241 return false;
242 }
243
244 if (!IsOnBackgroundThread()) {
245 MutexAutoLock lock(mBgThreadMutex);
246 nsresult rv = mBackgroundThread->Dispatch(
247 NewRunnableMethod<const int64_t, const int64_t>(
248 "net::HttpBackgroundChannelParent::OnProgress", this,
249 &HttpBackgroundChannelParent::OnProgress, aProgress, aProgressMax),
250 NS_DISPATCH_NORMAL);
251
252 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
253
254 return NS_SUCCEEDED(rv);
255 }
256
257 return SendOnProgress(aProgress, aProgressMax);
258 }
259
OnStatus(const nsresult & aStatus)260 bool HttpBackgroundChannelParent::OnStatus(const nsresult& aStatus) {
261 LOG(("HttpBackgroundChannelParent::OnStatus [this=%p stauts=%" PRIx32 "]\n",
262 this, static_cast<uint32_t>(aStatus)));
263 AssertIsInMainProcess();
264
265 if (NS_WARN_IF(!mIPCOpened)) {
266 return false;
267 }
268
269 if (!IsOnBackgroundThread()) {
270 MutexAutoLock lock(mBgThreadMutex);
271 nsresult rv = mBackgroundThread->Dispatch(
272 NewRunnableMethod<const nsresult>(
273 "net::HttpBackgroundChannelParent::OnStatus", this,
274 &HttpBackgroundChannelParent::OnStatus, aStatus),
275 NS_DISPATCH_NORMAL);
276
277 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
278
279 return NS_SUCCEEDED(rv);
280 }
281
282 return SendOnStatus(aStatus);
283 }
284
OnDiversion()285 bool HttpBackgroundChannelParent::OnDiversion() {
286 LOG(("HttpBackgroundChannelParent::OnDiversion [this=%p]\n", this));
287 AssertIsInMainProcess();
288
289 if (NS_WARN_IF(!mIPCOpened)) {
290 return false;
291 }
292
293 if (!IsOnBackgroundThread()) {
294 MutexAutoLock lock(mBgThreadMutex);
295 nsresult rv = mBackgroundThread->Dispatch(
296 NewRunnableMethod("net::HttpBackgroundChannelParent::OnDiversion", this,
297 &HttpBackgroundChannelParent::OnDiversion),
298 NS_DISPATCH_NORMAL);
299
300 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
301
302 return NS_SUCCEEDED(rv);
303 }
304
305 if (!SendFlushedForDiversion()) {
306 return false;
307 }
308
309 // The listener chain should now be setup; tell HttpChannelChild to divert
310 // the OnDataAvailables and OnStopRequest to associated HttpChannelParent.
311 if (!SendDivertMessages()) {
312 return false;
313 }
314
315 return true;
316 }
317
OnNotifyTrackingProtectionDisabled()318 bool HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled() {
319 LOG(
320 ("HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled "
321 "[this=%p]\n",
322 this));
323 AssertIsInMainProcess();
324
325 if (NS_WARN_IF(!mIPCOpened)) {
326 return false;
327 }
328
329 if (!IsOnBackgroundThread()) {
330 MutexAutoLock lock(mBgThreadMutex);
331 nsresult rv = mBackgroundThread->Dispatch(
332 NewRunnableMethod(
333 "net::HttpBackgroundChannelParent::"
334 "OnNotifyTrackingProtectionDisabled",
335 this,
336 &HttpBackgroundChannelParent::OnNotifyTrackingProtectionDisabled),
337 NS_DISPATCH_NORMAL);
338
339 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
340
341 return NS_SUCCEEDED(rv);
342 }
343
344 return SendNotifyTrackingProtectionDisabled();
345 }
346
OnNotifyTrackingResource()347 bool HttpBackgroundChannelParent::OnNotifyTrackingResource() {
348 LOG(("HttpBackgroundChannelParent::OnNotifyTrackingResource [this=%p]\n",
349 this));
350 AssertIsInMainProcess();
351
352 if (NS_WARN_IF(!mIPCOpened)) {
353 return false;
354 }
355
356 if (!IsOnBackgroundThread()) {
357 MutexAutoLock lock(mBgThreadMutex);
358 nsresult rv = mBackgroundThread->Dispatch(
359 NewRunnableMethod(
360 "net::HttpBackgroundChannelParent::OnNotifyTrackingResource", this,
361 &HttpBackgroundChannelParent::OnNotifyTrackingResource),
362 NS_DISPATCH_NORMAL);
363
364 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
365
366 return NS_SUCCEEDED(rv);
367 }
368
369 return SendNotifyTrackingResource();
370 }
371
OnSetClassifierMatchedInfo(const nsACString & aList,const nsACString & aProvider,const nsACString & aFullHash)372 bool HttpBackgroundChannelParent::OnSetClassifierMatchedInfo(
373 const nsACString& aList, const nsACString& aProvider,
374 const nsACString& aFullHash) {
375 LOG(("HttpBackgroundChannelParent::OnSetClassifierMatchedInfo [this=%p]\n",
376 this));
377 AssertIsInMainProcess();
378
379 if (NS_WARN_IF(!mIPCOpened)) {
380 return false;
381 }
382
383 if (!IsOnBackgroundThread()) {
384 MutexAutoLock lock(mBgThreadMutex);
385 nsresult rv = mBackgroundThread->Dispatch(
386 NewRunnableMethod<const nsCString, const nsCString, const nsCString>(
387 "net::HttpBackgroundChannelParent::OnSetClassifierMatchedInfo",
388 this, &HttpBackgroundChannelParent::OnSetClassifierMatchedInfo,
389 aList, aProvider, aFullHash),
390 NS_DISPATCH_NORMAL);
391
392 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
393
394 return NS_SUCCEEDED(rv);
395 }
396
397 ClassifierInfo info;
398 info.list() = aList;
399 info.fullhash() = aFullHash;
400 info.provider() = aProvider;
401
402 return SendSetClassifierMatchedInfo(info);
403 }
404
ActorDestroy(ActorDestroyReason aWhy)405 void HttpBackgroundChannelParent::ActorDestroy(ActorDestroyReason aWhy) {
406 LOG(("HttpBackgroundChannelParent::ActorDestroy [this=%p]\n", this));
407 AssertIsInMainProcess();
408 AssertIsOnBackgroundThread();
409
410 mIPCOpened = false;
411
412 RefPtr<HttpBackgroundChannelParent> self = this;
413 DebugOnly<nsresult> rv = NS_DispatchToMainThread(NS_NewRunnableFunction(
414 "net::HttpBackgroundChannelParent::ActorDestroy", [self]() {
415 MOZ_ASSERT(NS_IsMainThread());
416
417 RefPtr<HttpChannelParent> channelParent = self->mChannelParent.forget();
418
419 if (channelParent) {
420 channelParent->OnBackgroundParentDestroyed();
421 }
422 }));
423 MOZ_ASSERT(NS_SUCCEEDED(rv));
424 }
425
426 } // namespace net
427 } // namespace mozilla
428