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 "mozilla/net/BackgroundChannelRegistrar.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 BackgroundChannelRegistrar::GetOrCreate();
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
OnStartRequest(const nsHttpResponseHead & aResponseHead,const bool & aUseResponseHead,const nsHttpHeaderArray & aRequestHeaders,const HttpChannelOnStartRequestArgs & aArgs)145 bool HttpBackgroundChannelParent::OnStartRequest(
146 const nsHttpResponseHead& aResponseHead, const bool& aUseResponseHead,
147 const nsHttpHeaderArray& aRequestHeaders,
148 const HttpChannelOnStartRequestArgs& aArgs) {
149 LOG(("HttpBackgroundChannelParent::OnStartRequest [this=%p]\n", this));
150 AssertIsInMainProcess();
151
152 if (NS_WARN_IF(!mIPCOpened)) {
153 return false;
154 }
155
156 if (!IsOnBackgroundThread()) {
157 MutexAutoLock lock(mBgThreadMutex);
158 nsresult rv = mBackgroundThread->Dispatch(
159 NewRunnableMethod<const nsHttpResponseHead, const bool,
160 const nsHttpHeaderArray,
161 const HttpChannelOnStartRequestArgs>(
162 "net::HttpBackgroundChannelParent::OnStartRequest", this,
163 &HttpBackgroundChannelParent::OnStartRequest, aResponseHead,
164 aUseResponseHead, aRequestHeaders, aArgs),
165 NS_DISPATCH_NORMAL);
166
167 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
168
169 return NS_SUCCEEDED(rv);
170 }
171
172 return SendOnStartRequest(aResponseHead, aUseResponseHead, aRequestHeaders,
173 aArgs);
174 }
175
OnTransportAndData(const nsresult & aChannelStatus,const nsresult & aTransportStatus,const uint64_t & aOffset,const uint32_t & aCount,const nsCString & aData)176 bool HttpBackgroundChannelParent::OnTransportAndData(
177 const nsresult& aChannelStatus, const nsresult& aTransportStatus,
178 const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) {
179 LOG(("HttpBackgroundChannelParent::OnTransportAndData [this=%p]\n", this));
180 AssertIsInMainProcess();
181
182 if (NS_WARN_IF(!mIPCOpened)) {
183 return false;
184 }
185
186 if (!IsOnBackgroundThread()) {
187 MutexAutoLock lock(mBgThreadMutex);
188 nsresult rv = mBackgroundThread->Dispatch(
189 NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
190 const uint32_t, const nsCString>(
191 "net::HttpBackgroundChannelParent::OnTransportAndData", this,
192 &HttpBackgroundChannelParent::OnTransportAndData, aChannelStatus,
193 aTransportStatus, aOffset, aCount, aData),
194 NS_DISPATCH_NORMAL);
195
196 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
197
198 return NS_SUCCEEDED(rv);
199 }
200
201 nsHttp::SendFunc<nsDependentCSubstring> sendFunc =
202 [self = UnsafePtr<HttpBackgroundChannelParent>(this), aChannelStatus,
203 aTransportStatus](const nsDependentCSubstring& aData, uint64_t aOffset,
204 uint32_t aCount) {
205 return self->SendOnTransportAndData(aChannelStatus, aTransportStatus,
206 aOffset, aCount, aData, false);
207 };
208
209 return nsHttp::SendDataInChunks(aData, aOffset, aCount, sendFunc);
210 }
211
OnStopRequest(const nsresult & aChannelStatus,const ResourceTimingStructArgs & aTiming,const nsHttpHeaderArray & aResponseTrailers,const nsTArray<ConsoleReportCollected> & aConsoleReports)212 bool HttpBackgroundChannelParent::OnStopRequest(
213 const nsresult& aChannelStatus, const ResourceTimingStructArgs& aTiming,
214 const nsHttpHeaderArray& aResponseTrailers,
215 const nsTArray<ConsoleReportCollected>& aConsoleReports) {
216 LOG(
217 ("HttpBackgroundChannelParent::OnStopRequest [this=%p "
218 "status=%" PRIx32 "]\n",
219 this, static_cast<uint32_t>(aChannelStatus)));
220 AssertIsInMainProcess();
221
222 if (NS_WARN_IF(!mIPCOpened)) {
223 return false;
224 }
225
226 if (!IsOnBackgroundThread()) {
227 MutexAutoLock lock(mBgThreadMutex);
228 nsresult rv = mBackgroundThread->Dispatch(
229 NewRunnableMethod<const nsresult, const ResourceTimingStructArgs,
230 const nsHttpHeaderArray,
231 const CopyableTArray<ConsoleReportCollected>>(
232 "net::HttpBackgroundChannelParent::OnStopRequest", this,
233 &HttpBackgroundChannelParent::OnStopRequest, aChannelStatus,
234 aTiming, aResponseTrailers, aConsoleReports),
235 NS_DISPATCH_NORMAL);
236
237 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
238
239 return NS_SUCCEEDED(rv);
240 }
241
242 // See the child code for why we do this.
243 TimeStamp lastActTabOpt = nsHttp::GetLastActiveTabLoadOptimizationHit();
244
245 return SendOnStopRequest(aChannelStatus, aTiming, lastActTabOpt,
246 aResponseTrailers, aConsoleReports, false);
247 }
248
OnConsoleReport(const nsTArray<ConsoleReportCollected> & aConsoleReports)249 bool HttpBackgroundChannelParent::OnConsoleReport(
250 const nsTArray<ConsoleReportCollected>& aConsoleReports) {
251 LOG(("HttpBackgroundChannelParent::OnConsoleReport [this=%p]", this));
252 AssertIsInMainProcess();
253
254 if (NS_WARN_IF(!mIPCOpened)) {
255 return false;
256 }
257
258 if (!IsOnBackgroundThread()) {
259 MutexAutoLock lock(mBgThreadMutex);
260 nsresult rv = mBackgroundThread->Dispatch(
261 NewRunnableMethod<const CopyableTArray<ConsoleReportCollected>>(
262 "net::HttpBackgroundChannelParent::OnConsoleReport", this,
263 &HttpBackgroundChannelParent::OnConsoleReport, aConsoleReports),
264 NS_DISPATCH_NORMAL);
265
266 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
267
268 return NS_SUCCEEDED(rv);
269 }
270
271 return SendOnConsoleReport(aConsoleReports);
272 }
273
OnAfterLastPart(const nsresult aStatus)274 bool HttpBackgroundChannelParent::OnAfterLastPart(const nsresult aStatus) {
275 LOG(("HttpBackgroundChannelParent::OnAfterLastPart [this=%p]\n", this));
276 AssertIsInMainProcess();
277
278 if (NS_WARN_IF(!mIPCOpened)) {
279 return false;
280 }
281
282 if (!IsOnBackgroundThread()) {
283 MutexAutoLock lock(mBgThreadMutex);
284 nsresult rv = mBackgroundThread->Dispatch(
285 NewRunnableMethod<const nsresult>(
286 "net::HttpBackgroundChannelParent::OnAfterLastPart", this,
287 &HttpBackgroundChannelParent::OnAfterLastPart, aStatus),
288 NS_DISPATCH_NORMAL);
289
290 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
291
292 return NS_SUCCEEDED(rv);
293 }
294
295 return SendOnAfterLastPart(aStatus);
296 }
297
OnProgress(const int64_t aProgress,const int64_t aProgressMax)298 bool HttpBackgroundChannelParent::OnProgress(const int64_t aProgress,
299 const int64_t aProgressMax) {
300 LOG(("HttpBackgroundChannelParent::OnProgress [this=%p]\n", this));
301 AssertIsInMainProcess();
302
303 if (NS_WARN_IF(!mIPCOpened)) {
304 return false;
305 }
306
307 if (!IsOnBackgroundThread()) {
308 MutexAutoLock lock(mBgThreadMutex);
309 nsresult rv = mBackgroundThread->Dispatch(
310 NewRunnableMethod<const int64_t, const int64_t>(
311 "net::HttpBackgroundChannelParent::OnProgress", this,
312 &HttpBackgroundChannelParent::OnProgress, aProgress, aProgressMax),
313 NS_DISPATCH_NORMAL);
314
315 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
316
317 return NS_SUCCEEDED(rv);
318 }
319
320 return SendOnProgress(aProgress, aProgressMax);
321 }
322
OnStatus(const nsresult aStatus)323 bool HttpBackgroundChannelParent::OnStatus(const nsresult aStatus) {
324 LOG(("HttpBackgroundChannelParent::OnStatus [this=%p]\n", this));
325 AssertIsInMainProcess();
326
327 if (NS_WARN_IF(!mIPCOpened)) {
328 return false;
329 }
330
331 if (!IsOnBackgroundThread()) {
332 MutexAutoLock lock(mBgThreadMutex);
333 nsresult rv = mBackgroundThread->Dispatch(
334 NewRunnableMethod<const nsresult>(
335 "net::HttpBackgroundChannelParent::OnStatus", this,
336 &HttpBackgroundChannelParent::OnStatus, aStatus),
337 NS_DISPATCH_NORMAL);
338
339 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
340
341 return NS_SUCCEEDED(rv);
342 }
343
344 return SendOnStatus(aStatus);
345 }
346
OnNotifyClassificationFlags(uint32_t aClassificationFlags,bool aIsThirdParty)347 bool HttpBackgroundChannelParent::OnNotifyClassificationFlags(
348 uint32_t aClassificationFlags, bool aIsThirdParty) {
349 LOG(
350 ("HttpBackgroundChannelParent::OnNotifyClassificationFlags "
351 "classificationFlags=%" PRIu32 ", thirdparty=%d [this=%p]\n",
352 aClassificationFlags, static_cast<int>(aIsThirdParty), this));
353 AssertIsInMainProcess();
354
355 if (NS_WARN_IF(!mIPCOpened)) {
356 return false;
357 }
358
359 if (!IsOnBackgroundThread()) {
360 MutexAutoLock lock(mBgThreadMutex);
361 nsresult rv = mBackgroundThread->Dispatch(
362 NewRunnableMethod<uint32_t, bool>(
363 "net::HttpBackgroundChannelParent::OnNotifyClassificationFlags",
364 this, &HttpBackgroundChannelParent::OnNotifyClassificationFlags,
365 aClassificationFlags, aIsThirdParty),
366 NS_DISPATCH_NORMAL);
367
368 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
369
370 return NS_SUCCEEDED(rv);
371 }
372
373 return SendNotifyClassificationFlags(aClassificationFlags, aIsThirdParty);
374 }
375
OnNotifyFlashPluginStateChanged(nsIHttpChannel::FlashPluginState aState)376 bool HttpBackgroundChannelParent::OnNotifyFlashPluginStateChanged(
377 nsIHttpChannel::FlashPluginState aState) {
378 LOG(
379 ("HttpBackgroundChannelParent::OnNotifyFlashPluginStateChanged "
380 "[this=%p]\n",
381 this));
382 AssertIsInMainProcess();
383
384 if (NS_WARN_IF(!mIPCOpened)) {
385 return false;
386 }
387
388 if (!IsOnBackgroundThread()) {
389 MutexAutoLock lock(mBgThreadMutex);
390 RefPtr<HttpBackgroundChannelParent> self = this;
391 nsresult rv = mBackgroundThread->Dispatch(
392 NS_NewRunnableFunction(
393 "net::HttpBackgroundChannelParent::OnNotifyFlashPluginStateChanged",
394 [self, aState]() {
395 self->OnNotifyFlashPluginStateChanged(aState);
396 }),
397 NS_DISPATCH_NORMAL);
398
399 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
400
401 return NS_SUCCEEDED(rv);
402 }
403
404 return SendNotifyFlashPluginStateChanged(aState);
405 }
406
OnSetClassifierMatchedInfo(const nsACString & aList,const nsACString & aProvider,const nsACString & aFullHash)407 bool HttpBackgroundChannelParent::OnSetClassifierMatchedInfo(
408 const nsACString& aList, const nsACString& aProvider,
409 const nsACString& aFullHash) {
410 LOG(("HttpBackgroundChannelParent::OnSetClassifierMatchedInfo [this=%p]\n",
411 this));
412 AssertIsInMainProcess();
413
414 if (NS_WARN_IF(!mIPCOpened)) {
415 return false;
416 }
417
418 if (!IsOnBackgroundThread()) {
419 MutexAutoLock lock(mBgThreadMutex);
420 nsresult rv = mBackgroundThread->Dispatch(
421 NewRunnableMethod<const nsCString, const nsCString, const nsCString>(
422 "net::HttpBackgroundChannelParent::OnSetClassifierMatchedInfo",
423 this, &HttpBackgroundChannelParent::OnSetClassifierMatchedInfo,
424 aList, aProvider, aFullHash),
425 NS_DISPATCH_NORMAL);
426
427 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
428
429 return NS_SUCCEEDED(rv);
430 }
431
432 ClassifierInfo info;
433 info.list() = aList;
434 info.fullhash() = aFullHash;
435 info.provider() = aProvider;
436
437 return SendSetClassifierMatchedInfo(info);
438 }
439
OnSetClassifierMatchedTrackingInfo(const nsACString & aLists,const nsACString & aFullHashes)440 bool HttpBackgroundChannelParent::OnSetClassifierMatchedTrackingInfo(
441 const nsACString& aLists, const nsACString& aFullHashes) {
442 LOG(
443 ("HttpBackgroundChannelParent::OnSetClassifierMatchedTrackingInfo "
444 "[this=%p]\n",
445 this));
446 AssertIsInMainProcess();
447
448 if (NS_WARN_IF(!mIPCOpened)) {
449 return false;
450 }
451
452 if (!IsOnBackgroundThread()) {
453 MutexAutoLock lock(mBgThreadMutex);
454 nsresult rv = mBackgroundThread->Dispatch(
455 NewRunnableMethod<const nsCString, const nsCString>(
456 "net::HttpBackgroundChannelParent::"
457 "OnSetClassifierMatchedTrackingInfo",
458 this,
459 &HttpBackgroundChannelParent::OnSetClassifierMatchedTrackingInfo,
460 aLists, aFullHashes),
461 NS_DISPATCH_NORMAL);
462
463 MOZ_DIAGNOSTIC_ASSERT(NS_SUCCEEDED(rv));
464
465 return NS_SUCCEEDED(rv);
466 }
467
468 ClassifierInfo info;
469 info.list() = aLists;
470 info.fullhash() = aFullHashes;
471
472 return SendSetClassifierMatchedTrackingInfo(info);
473 }
474
GetBackgroundTarget()475 nsISerialEventTarget* HttpBackgroundChannelParent::GetBackgroundTarget() {
476 MOZ_ASSERT(mBackgroundThread);
477 return mBackgroundThread.get();
478 }
479
AttachStreamFilter(Endpoint<extensions::PStreamFilterParent> && aParentEndpoint,Endpoint<extensions::PStreamFilterChild> && aChildEndpoint)480 auto HttpBackgroundChannelParent::AttachStreamFilter(
481 Endpoint<extensions::PStreamFilterParent>&& aParentEndpoint,
482 Endpoint<extensions::PStreamFilterChild>&& aChildEndpoint)
483 -> RefPtr<ChildEndpointPromise> {
484 LOG(("HttpBackgroundChannelParent::AttachStreamFilter [this=%p]\n", this));
485 MOZ_ASSERT(IsOnBackgroundThread());
486
487 if (NS_WARN_IF(!mIPCOpened) ||
488 !SendAttachStreamFilter(std::move(aParentEndpoint))) {
489 return ChildEndpointPromise::CreateAndReject(false, __func__);
490 }
491
492 return ChildEndpointPromise::CreateAndResolve(std::move(aChildEndpoint),
493 __func__);
494 }
495
ActorDestroy(ActorDestroyReason aWhy)496 void HttpBackgroundChannelParent::ActorDestroy(ActorDestroyReason aWhy) {
497 LOG(("HttpBackgroundChannelParent::ActorDestroy [this=%p]\n", this));
498 AssertIsInMainProcess();
499 AssertIsOnBackgroundThread();
500
501 mIPCOpened = false;
502
503 RefPtr<HttpBackgroundChannelParent> self = this;
504 DebugOnly<nsresult> rv = NS_DispatchToMainThread(NS_NewRunnableFunction(
505 "net::HttpBackgroundChannelParent::ActorDestroy", [self]() {
506 MOZ_ASSERT(NS_IsMainThread());
507
508 RefPtr<HttpChannelParent> channelParent =
509 std::move(self->mChannelParent);
510
511 if (channelParent) {
512 channelParent->OnBackgroundParentDestroyed();
513 }
514 }));
515 MOZ_ASSERT(NS_SUCCEEDED(rv));
516 }
517
518 } // namespace net
519 } // namespace mozilla
520