Line data Source code
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 "HttpBackgroundChannelChild.h"
12 :
13 : #include "HttpChannelChild.h"
14 : #include "mozilla/ipc/BackgroundChild.h"
15 : #include "mozilla/ipc/PBackgroundChild.h"
16 : #include "mozilla/IntegerPrintfMacros.h"
17 : #include "mozilla/Unused.h"
18 : #include "nsIIPCBackgroundChildCreateCallback.h"
19 : #include "nsSocketTransportService2.h"
20 :
21 : using mozilla::ipc::BackgroundChild;
22 : using mozilla::ipc::IPCResult;
23 :
24 : namespace mozilla {
25 : namespace net {
26 :
27 : // Callbacks for PBackgroundChild creation
28 : class BackgroundChannelCreateCallback final
29 : : public nsIIPCBackgroundChildCreateCallback
30 : {
31 : public:
32 : NS_DECL_ISUPPORTS
33 : NS_DECL_NSIIPCBACKGROUNDCHILDCREATECALLBACK
34 :
35 3 : explicit BackgroundChannelCreateCallback(HttpBackgroundChannelChild* aBgChild)
36 3 : : mBgChild(aBgChild)
37 : {
38 3 : MOZ_ASSERT(OnSocketThread());
39 3 : MOZ_ASSERT(aBgChild);
40 3 : }
41 :
42 : private:
43 9 : virtual ~BackgroundChannelCreateCallback() { }
44 :
45 : RefPtr<HttpBackgroundChannelChild> mBgChild;
46 : };
47 :
48 30 : NS_IMPL_ISUPPORTS(BackgroundChannelCreateCallback,
49 : nsIIPCBackgroundChildCreateCallback)
50 :
51 : void
52 3 : BackgroundChannelCreateCallback::ActorCreated(PBackgroundChild* aActor)
53 : {
54 3 : MOZ_ASSERT(OnSocketThread());
55 3 : MOZ_ASSERT(aActor);
56 3 : MOZ_ASSERT(mBgChild);
57 :
58 3 : if (!mBgChild->mChannelChild) {
59 : // HttpChannelChild is closed during PBackground creation,
60 : // abort the rest of steps.
61 0 : return;
62 : }
63 :
64 3 : const uint64_t channelId = mBgChild->mChannelChild->ChannelId();
65 3 : if (!aActor->SendPHttpBackgroundChannelConstructor(mBgChild,
66 3 : channelId)) {
67 0 : ActorFailed();
68 0 : return;
69 : }
70 :
71 : // hold extra reference for IPDL
72 6 : RefPtr<HttpBackgroundChannelChild> child = mBgChild;
73 3 : Unused << child.forget().take();
74 :
75 3 : mBgChild->mChannelChild->OnBackgroundChildReady(mBgChild);
76 : }
77 :
78 : void
79 0 : BackgroundChannelCreateCallback::ActorFailed()
80 : {
81 0 : MOZ_ASSERT(OnSocketThread());
82 0 : MOZ_ASSERT(mBgChild);
83 :
84 0 : mBgChild->OnBackgroundChannelCreationFailed();
85 0 : }
86 :
87 : // HttpBackgroundChannelChild
88 3 : HttpBackgroundChannelChild::HttpBackgroundChannelChild()
89 : {
90 3 : }
91 :
92 6 : HttpBackgroundChannelChild::~HttpBackgroundChannelChild()
93 : {
94 9 : }
95 :
96 : nsresult
97 3 : HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild)
98 : {
99 3 : LOG(("HttpBackgroundChannelChild::Init [this=%p httpChannel=%p channelId=%"
100 : PRIu64 "]\n", this, aChannelChild, aChannelChild->ChannelId()));
101 3 : MOZ_ASSERT(OnSocketThread());
102 3 : NS_ENSURE_ARG(aChannelChild);
103 :
104 3 : mChannelChild = aChannelChild;
105 :
106 3 : if (NS_WARN_IF(!CreateBackgroundChannel())) {
107 0 : mChannelChild = nullptr;
108 0 : return NS_ERROR_FAILURE;
109 : }
110 :
111 3 : return NS_OK;
112 : }
113 :
114 : void
115 3 : HttpBackgroundChannelChild::OnChannelClosed()
116 : {
117 3 : LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this));
118 3 : MOZ_ASSERT(OnSocketThread());
119 :
120 : // HttpChannelChild is not going to handle any incoming message.
121 3 : mChannelChild = nullptr;
122 3 : }
123 :
124 : void
125 3 : HttpBackgroundChannelChild::OnStartRequestReceived()
126 : {
127 3 : LOG(("HttpBackgroundChannelChild::OnStartRequestReceived [this=%p]\n", this));
128 3 : MOZ_ASSERT(OnSocketThread());
129 3 : MOZ_ASSERT(mChannelChild);
130 3 : MOZ_ASSERT(!mStartReceived); // Should only be called once.
131 :
132 3 : mStartReceived = true;
133 :
134 6 : nsTArray<nsCOMPtr<nsIRunnable>> runnables;
135 3 : runnables.SwapElements(mQueuedRunnables);
136 :
137 9 : for (auto event : runnables) {
138 : // Note: these runnables call Recv* methods on HttpBackgroundChannelChild
139 : // but not the Process* methods on HttpChannelChild.
140 6 : event->Run();
141 : }
142 :
143 : // Ensure no new message is enqueued.
144 3 : MOZ_ASSERT(mQueuedRunnables.IsEmpty());
145 3 : }
146 :
147 : void
148 0 : HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed()
149 : {
150 0 : LOG(("HttpBackgroundChannelChild::OnBackgroundChannelCreationFailed"
151 : " [this=%p]\n", this));
152 0 : MOZ_ASSERT(OnSocketThread());
153 :
154 0 : if (mChannelChild) {
155 0 : RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
156 0 : channelChild->OnBackgroundChildDestroyed(this);
157 : }
158 0 : }
159 :
160 : bool
161 3 : HttpBackgroundChannelChild::CreateBackgroundChannel()
162 : {
163 3 : LOG(("HttpBackgroundChannelChild::CreateBackgroundChannel [this=%p]\n", this));
164 3 : MOZ_ASSERT(OnSocketThread());
165 :
166 : RefPtr<BackgroundChannelCreateCallback> callback =
167 6 : new BackgroundChannelCreateCallback(this);
168 :
169 6 : return BackgroundChild::GetOrCreateForCurrentThread(callback);
170 : }
171 :
172 : bool
173 17 : HttpBackgroundChannelChild::IsWaitingOnStartRequest()
174 : {
175 17 : MOZ_ASSERT(OnSocketThread());
176 : // Need to wait for OnStartRequest if it is sent by
177 : // parent process but not received by content process.
178 17 : return (mStartSent && !mStartReceived);
179 : }
180 :
181 : // PHttpBackgroundChannelChild
182 : IPCResult
183 3 : HttpBackgroundChannelChild::RecvOnStartRequestSent()
184 : {
185 3 : LOG(("HttpBackgroundChannelChild::RecvOnStartRequestSent [this=%p]\n", this));
186 3 : MOZ_ASSERT(OnSocketThread());
187 3 : MOZ_ASSERT(!mStartSent); // Should only receive this message once.
188 :
189 3 : mStartSent = true;
190 3 : return IPC_OK();
191 : }
192 :
193 : IPCResult
194 6 : HttpBackgroundChannelChild::RecvOnTransportAndData(
195 : const nsresult& aChannelStatus,
196 : const nsresult& aTransportStatus,
197 : const uint64_t& aOffset,
198 : const uint32_t& aCount,
199 : const nsCString& aData)
200 : {
201 6 : LOG(("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p]\n", this));
202 6 : MOZ_ASSERT(OnSocketThread());
203 :
204 6 : if (NS_WARN_IF(!mChannelChild)) {
205 0 : return IPC_OK();
206 : }
207 :
208 6 : if (IsWaitingOnStartRequest()) {
209 3 : LOG((" > pending until OnStartRequest [offset=%" PRIu64 " count=%" PRIu32
210 : "]\n", aOffset, aCount));
211 :
212 3 : mQueuedRunnables.AppendElement(NewRunnableMethod<const nsresult,
213 : const nsresult,
214 : const uint64_t,
215 : const uint32_t,
216 6 : const nsCString>(
217 : "HttpBackgroundChannelChild::RecvOnTransportAndData",
218 : this,
219 : &HttpBackgroundChannelChild::RecvOnTransportAndData,
220 : aChannelStatus,
221 : aTransportStatus,
222 : aOffset,
223 : aCount,
224 3 : aData));
225 :
226 3 : return IPC_OK();
227 : }
228 :
229 3 : mChannelChild->ProcessOnTransportAndData(aChannelStatus,
230 : aTransportStatus,
231 : aOffset,
232 : aCount,
233 3 : aData);
234 :
235 3 : return IPC_OK();
236 : }
237 :
238 : IPCResult
239 6 : HttpBackgroundChannelChild::RecvOnStopRequest(
240 : const nsresult& aChannelStatus,
241 : const ResourceTimingStruct& aTiming)
242 : {
243 6 : LOG(("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p]\n", this));
244 6 : MOZ_ASSERT(OnSocketThread());
245 :
246 6 : if (NS_WARN_IF(!mChannelChild)) {
247 0 : return IPC_OK();
248 : }
249 :
250 6 : if (IsWaitingOnStartRequest()) {
251 3 : LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
252 : static_cast<uint32_t>(aChannelStatus)));
253 :
254 3 : mQueuedRunnables.AppendElement(
255 6 : NewRunnableMethod<const nsresult, const ResourceTimingStruct>(
256 : "HttpBackgroundChannelChild::RecvOnStopRequest",
257 : this,
258 : &HttpBackgroundChannelChild::RecvOnStopRequest,
259 : aChannelStatus,
260 3 : aTiming));
261 :
262 3 : return IPC_OK();
263 : }
264 :
265 3 : mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming);
266 :
267 3 : return IPC_OK();
268 : }
269 :
270 : IPCResult
271 0 : HttpBackgroundChannelChild::RecvOnProgress(const int64_t& aProgress,
272 : const int64_t& aProgressMax)
273 : {
274 0 : LOG(("HttpBackgroundChannelChild::RecvOnProgress [this=%p progress=%"
275 : PRId64 " max=%" PRId64 "]\n", this, aProgress, aProgressMax));
276 0 : MOZ_ASSERT(OnSocketThread());
277 :
278 0 : if (NS_WARN_IF(!mChannelChild)) {
279 0 : return IPC_OK();
280 : }
281 :
282 0 : if (IsWaitingOnStartRequest()) {
283 0 : LOG((" > pending until OnStartRequest [progress=%" PRId64 " max=%"
284 : PRId64 "]\n", aProgress, aProgressMax));
285 :
286 0 : mQueuedRunnables.AppendElement(
287 0 : NewRunnableMethod<const int64_t, const int64_t>(
288 : "HttpBackgroundChannelChild::RecvOnProgress",
289 : this,
290 : &HttpBackgroundChannelChild::RecvOnProgress,
291 : aProgress,
292 0 : aProgressMax));
293 :
294 0 : return IPC_OK();
295 : }
296 :
297 0 : mChannelChild->ProcessOnProgress(aProgress, aProgressMax);
298 :
299 0 : return IPC_OK();
300 : }
301 :
302 : IPCResult
303 5 : HttpBackgroundChannelChild::RecvOnStatus(const nsresult& aStatus)
304 : {
305 5 : LOG(("HttpBackgroundChannelChild::RecvOnStatus [this=%p status=%"
306 : PRIx32 "]\n", this, static_cast<uint32_t>(aStatus)));
307 5 : MOZ_ASSERT(OnSocketThread());
308 :
309 5 : if (NS_WARN_IF(!mChannelChild)) {
310 0 : return IPC_OK();
311 : }
312 :
313 5 : if (IsWaitingOnStartRequest()) {
314 0 : LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
315 : static_cast<uint32_t>(aStatus)));
316 :
317 0 : mQueuedRunnables.AppendElement(NewRunnableMethod<const nsresult>(
318 : "HttpBackgroundChannelChild::RecvOnStatus",
319 : this,
320 : &HttpBackgroundChannelChild::RecvOnStatus,
321 0 : aStatus));
322 :
323 0 : return IPC_OK();
324 : }
325 :
326 5 : mChannelChild->ProcessOnStatus(aStatus);
327 :
328 5 : return IPC_OK();
329 : }
330 :
331 : IPCResult
332 0 : HttpBackgroundChannelChild::RecvFlushedForDiversion()
333 : {
334 0 : LOG(("HttpBackgroundChannelChild::RecvFlushedForDiversion [this=%p]\n", this));
335 0 : MOZ_ASSERT(OnSocketThread());
336 :
337 0 : if (NS_WARN_IF(!mChannelChild)) {
338 0 : return IPC_OK();
339 : }
340 :
341 0 : if (IsWaitingOnStartRequest()) {
342 0 : LOG((" > pending until OnStartRequest\n"));
343 :
344 0 : mQueuedRunnables.AppendElement(NewRunnableMethod(
345 : "HttpBackgroundChannelChild::RecvFlushedForDiversion",
346 : this,
347 0 : &HttpBackgroundChannelChild::RecvFlushedForDiversion));
348 :
349 0 : return IPC_OK();
350 : }
351 :
352 0 : mChannelChild->ProcessFlushedForDiversion();
353 :
354 0 : return IPC_OK();
355 : }
356 :
357 : IPCResult
358 0 : HttpBackgroundChannelChild::RecvDivertMessages()
359 : {
360 0 : LOG(("HttpBackgroundChannelChild::RecvDivertMessages [this=%p]\n", this));
361 0 : MOZ_ASSERT(OnSocketThread());
362 :
363 0 : if (NS_WARN_IF(!mChannelChild)) {
364 0 : return IPC_OK();
365 : }
366 :
367 0 : if (IsWaitingOnStartRequest()) {
368 0 : LOG((" > pending until OnStartRequest\n"));
369 :
370 0 : mQueuedRunnables.AppendElement(
371 0 : NewRunnableMethod("HttpBackgroundChannelChild::RecvDivertMessages",
372 : this,
373 0 : &HttpBackgroundChannelChild::RecvDivertMessages));
374 :
375 0 : return IPC_OK();
376 : }
377 :
378 0 : mChannelChild->ProcessDivertMessages();
379 :
380 0 : return IPC_OK();
381 : }
382 :
383 : IPCResult
384 0 : HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled()
385 : {
386 0 : LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled [this=%p]\n", this));
387 0 : MOZ_ASSERT(OnSocketThread());
388 :
389 0 : if (NS_WARN_IF(!mChannelChild)) {
390 0 : return IPC_OK();
391 : }
392 :
393 : // NotifyTrackingProtectionDisabled has no order dependency to OnStartRequest.
394 : // It this be handled as soon as possible
395 0 : mChannelChild->ProcessNotifyTrackingProtectionDisabled();
396 :
397 0 : return IPC_OK();
398 : }
399 :
400 : IPCResult
401 0 : HttpBackgroundChannelChild::RecvNotifyTrackingResource()
402 : {
403 0 : LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingResource [this=%p]\n", this));
404 0 : MOZ_ASSERT(OnSocketThread());
405 :
406 0 : if (NS_WARN_IF(!mChannelChild)) {
407 0 : return IPC_OK();
408 : }
409 :
410 : // NotifyTrackingResource has no order dependency to OnStartRequest.
411 : // It this be handled as soon as possible
412 0 : mChannelChild->ProcessNotifyTrackingResource();
413 :
414 0 : return IPC_OK();
415 : }
416 :
417 : IPCResult
418 0 : HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo(const ClassifierInfo& info)
419 : {
420 0 : LOG(("HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo [this=%p]\n", this));
421 0 : MOZ_ASSERT(OnSocketThread());
422 :
423 0 : if (NS_WARN_IF(!mChannelChild)) {
424 0 : return IPC_OK();
425 : }
426 :
427 : // SetClassifierMatchedInfo has no order dependency to OnStartRequest.
428 : // It this be handled as soon as possible
429 0 : mChannelChild->ProcessSetClassifierMatchedInfo(info.list(), info.provider(), info.prefix());
430 :
431 0 : return IPC_OK();
432 : }
433 :
434 : void
435 3 : HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy)
436 : {
437 3 : LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this));
438 : // This function might be called during shutdown phase, so OnSocketThread()
439 : // might return false even on STS thread. Use IsOnCurrentThreadInfallible()
440 : // to get correct information.
441 3 : MOZ_ASSERT(gSocketTransportService);
442 3 : MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible());
443 :
444 : // Ensure all IPC messages received before ActorDestroy can be
445 : // handled correctly. If there is any pending IPC message, destroyed
446 : // mChannelChild until those messages are flushed.
447 : // If background channel is not closed by normal IPDL actor deletion,
448 : // remove the HttpChannelChild reference and notify background channel
449 : // destroyed immediately.
450 3 : if (aWhy == Deletion && !mQueuedRunnables.IsEmpty()) {
451 0 : LOG((" > pending until queued messages are flushed\n"));
452 0 : RefPtr<HttpBackgroundChannelChild> self = this;
453 0 : mQueuedRunnables.AppendElement(NS_NewRunnableFunction(
454 0 : "HttpBackgroundChannelChild::ActorDestroy", [self]() {
455 0 : MOZ_ASSERT(NS_IsMainThread());
456 0 : RefPtr<HttpChannelChild> channelChild = self->mChannelChild.forget();
457 :
458 0 : if (channelChild) {
459 0 : channelChild->OnBackgroundChildDestroyed(self);
460 : }
461 0 : }));
462 0 : return;
463 : }
464 :
465 3 : if (mChannelChild) {
466 0 : RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
467 :
468 0 : channelChild->OnBackgroundChildDestroyed(this);
469 : }
470 : }
471 :
472 : } // namespace net
473 : } // namespace mozilla
|