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 "nsSocketTransportService2.h"
19
20 using mozilla::ipc::BackgroundChild;
21 using mozilla::ipc::IPCResult;
22
23 namespace mozilla {
24 namespace net {
25
26 // HttpBackgroundChannelChild
HttpBackgroundChannelChild()27 HttpBackgroundChannelChild::HttpBackgroundChannelChild() {}
28
~HttpBackgroundChannelChild()29 HttpBackgroundChannelChild::~HttpBackgroundChannelChild() {}
30
Init(HttpChannelChild * aChannelChild)31 nsresult HttpBackgroundChannelChild::Init(HttpChannelChild* aChannelChild) {
32 LOG(
33 ("HttpBackgroundChannelChild::Init [this=%p httpChannel=%p "
34 "channelId=%" PRIu64 "]\n",
35 this, aChannelChild, aChannelChild->ChannelId()));
36 MOZ_ASSERT(OnSocketThread());
37 NS_ENSURE_ARG(aChannelChild);
38
39 mChannelChild = aChannelChild;
40
41 if (NS_WARN_IF(!CreateBackgroundChannel())) {
42 mChannelChild = nullptr;
43 return NS_ERROR_FAILURE;
44 }
45
46 return NS_OK;
47 }
48
OnChannelClosed()49 void HttpBackgroundChannelChild::OnChannelClosed() {
50 LOG(("HttpBackgroundChannelChild::OnChannelClosed [this=%p]\n", this));
51 MOZ_ASSERT(OnSocketThread());
52
53 // HttpChannelChild is not going to handle any incoming message.
54 mChannelChild = nullptr;
55
56 // Remove pending IPC messages as well.
57 mQueuedRunnables.Clear();
58 }
59
OnStartRequestReceived()60 void HttpBackgroundChannelChild::OnStartRequestReceived() {
61 LOG(("HttpBackgroundChannelChild::OnStartRequestReceived [this=%p]\n", this));
62 MOZ_ASSERT(OnSocketThread());
63 MOZ_ASSERT(mChannelChild);
64 MOZ_ASSERT(!mStartReceived); // Should only be called once.
65
66 mStartReceived = true;
67
68 nsTArray<nsCOMPtr<nsIRunnable>> runnables;
69 runnables.SwapElements(mQueuedRunnables);
70
71 for (auto event : runnables) {
72 // Note: these runnables call Recv* methods on HttpBackgroundChannelChild
73 // but not the Process* methods on HttpChannelChild.
74 event->Run();
75 }
76
77 // Ensure no new message is enqueued.
78 MOZ_ASSERT(mQueuedRunnables.IsEmpty());
79 }
80
CreateBackgroundChannel()81 bool HttpBackgroundChannelChild::CreateBackgroundChannel() {
82 LOG(("HttpBackgroundChannelChild::CreateBackgroundChannel [this=%p]\n",
83 this));
84 MOZ_ASSERT(OnSocketThread());
85 MOZ_ASSERT(mChannelChild);
86
87 PBackgroundChild* actorChild = BackgroundChild::GetOrCreateForCurrentThread();
88 if (NS_WARN_IF(!actorChild)) {
89 return false;
90 }
91
92 const uint64_t channelId = mChannelChild->ChannelId();
93 if (!actorChild->SendPHttpBackgroundChannelConstructor(this, channelId)) {
94 return false;
95 }
96
97 // hold extra reference for IPDL
98 RefPtr<HttpBackgroundChannelChild> self = this;
99 Unused << self.forget().take();
100
101 mChannelChild->OnBackgroundChildReady(this);
102 return true;
103 }
104
IsWaitingOnStartRequest()105 bool HttpBackgroundChannelChild::IsWaitingOnStartRequest() {
106 MOZ_ASSERT(OnSocketThread());
107 // Need to wait for OnStartRequest if it is sent by
108 // parent process but not received by content process.
109 return (mStartSent && !mStartReceived);
110 }
111
112 // PHttpBackgroundChannelChild
RecvOnStartRequestSent()113 IPCResult HttpBackgroundChannelChild::RecvOnStartRequestSent() {
114 LOG(("HttpBackgroundChannelChild::RecvOnStartRequestSent [this=%p]\n", this));
115 MOZ_ASSERT(OnSocketThread());
116 MOZ_ASSERT(!mStartSent); // Should only receive this message once.
117
118 mStartSent = true;
119 return IPC_OK();
120 }
121
RecvOnTransportAndData(const nsresult & aChannelStatus,const nsresult & aTransportStatus,const uint64_t & aOffset,const uint32_t & aCount,const nsCString & aData)122 IPCResult HttpBackgroundChannelChild::RecvOnTransportAndData(
123 const nsresult& aChannelStatus, const nsresult& aTransportStatus,
124 const uint64_t& aOffset, const uint32_t& aCount, const nsCString& aData) {
125 LOG(("HttpBackgroundChannelChild::RecvOnTransportAndData [this=%p]\n", this));
126 MOZ_ASSERT(OnSocketThread());
127
128 if (NS_WARN_IF(!mChannelChild)) {
129 return IPC_OK();
130 }
131
132 if (IsWaitingOnStartRequest()) {
133 LOG((" > pending until OnStartRequest [offset=%" PRIu64 " count=%" PRIu32
134 "]\n",
135 aOffset, aCount));
136
137 mQueuedRunnables.AppendElement(
138 NewRunnableMethod<const nsresult, const nsresult, const uint64_t,
139 const uint32_t, const nsCString>(
140 "HttpBackgroundChannelChild::RecvOnTransportAndData", this,
141 &HttpBackgroundChannelChild::RecvOnTransportAndData, aChannelStatus,
142 aTransportStatus, aOffset, aCount, aData));
143
144 return IPC_OK();
145 }
146
147 mChannelChild->ProcessOnTransportAndData(aChannelStatus, aTransportStatus,
148 aOffset, aCount, aData);
149
150 return IPC_OK();
151 }
152
RecvOnStopRequest(const nsresult & aChannelStatus,const ResourceTimingStruct & aTiming,const TimeStamp & aLastActiveTabOptHit,const nsHttpHeaderArray & aResponseTrailers)153 IPCResult HttpBackgroundChannelChild::RecvOnStopRequest(
154 const nsresult& aChannelStatus, const ResourceTimingStruct& aTiming,
155 const TimeStamp& aLastActiveTabOptHit,
156 const nsHttpHeaderArray& aResponseTrailers) {
157 LOG(("HttpBackgroundChannelChild::RecvOnStopRequest [this=%p]\n", this));
158 MOZ_ASSERT(OnSocketThread());
159
160 // It's enough to set this from (just before) OnStopRequest notification,
161 // since we don't need this value sooner than a channel was done loading -
162 // everything this timestamp affects takes place only after a channel's
163 // OnStopRequest.
164 nsHttp::SetLastActiveTabLoadOptimizationHit(aLastActiveTabOptHit);
165
166 if (NS_WARN_IF(!mChannelChild)) {
167 return IPC_OK();
168 }
169
170 if (IsWaitingOnStartRequest()) {
171 LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
172 static_cast<uint32_t>(aChannelStatus)));
173
174 mQueuedRunnables.AppendElement(
175 NewRunnableMethod<const nsresult, const ResourceTimingStruct,
176 const TimeStamp, const nsHttpHeaderArray>(
177 "HttpBackgroundChannelChild::RecvOnStopRequest", this,
178 &HttpBackgroundChannelChild::RecvOnStopRequest, aChannelStatus,
179 aTiming, aLastActiveTabOptHit, aResponseTrailers));
180
181 return IPC_OK();
182 }
183
184 mChannelChild->ProcessOnStopRequest(aChannelStatus, aTiming,
185 aResponseTrailers);
186
187 return IPC_OK();
188 }
189
RecvOnProgress(const int64_t & aProgress,const int64_t & aProgressMax)190 IPCResult HttpBackgroundChannelChild::RecvOnProgress(
191 const int64_t& aProgress, const int64_t& aProgressMax) {
192 LOG(("HttpBackgroundChannelChild::RecvOnProgress [this=%p progress=%" PRId64
193 " max=%" PRId64 "]\n",
194 this, aProgress, aProgressMax));
195 MOZ_ASSERT(OnSocketThread());
196
197 if (NS_WARN_IF(!mChannelChild)) {
198 return IPC_OK();
199 }
200
201 if (IsWaitingOnStartRequest()) {
202 LOG((" > pending until OnStartRequest [progress=%" PRId64 " max=%" PRId64
203 "]\n",
204 aProgress, aProgressMax));
205
206 mQueuedRunnables.AppendElement(
207 NewRunnableMethod<const int64_t, const int64_t>(
208 "HttpBackgroundChannelChild::RecvOnProgress", this,
209 &HttpBackgroundChannelChild::RecvOnProgress, aProgress,
210 aProgressMax));
211
212 return IPC_OK();
213 }
214
215 mChannelChild->ProcessOnProgress(aProgress, aProgressMax);
216
217 return IPC_OK();
218 }
219
RecvOnStatus(const nsresult & aStatus)220 IPCResult HttpBackgroundChannelChild::RecvOnStatus(const nsresult& aStatus) {
221 LOG(("HttpBackgroundChannelChild::RecvOnStatus [this=%p status=%" PRIx32
222 "]\n",
223 this, static_cast<uint32_t>(aStatus)));
224 MOZ_ASSERT(OnSocketThread());
225
226 if (NS_WARN_IF(!mChannelChild)) {
227 return IPC_OK();
228 }
229
230 if (IsWaitingOnStartRequest()) {
231 LOG((" > pending until OnStartRequest [status=%" PRIx32 "]\n",
232 static_cast<uint32_t>(aStatus)));
233
234 mQueuedRunnables.AppendElement(NewRunnableMethod<const nsresult>(
235 "HttpBackgroundChannelChild::RecvOnStatus", this,
236 &HttpBackgroundChannelChild::RecvOnStatus, aStatus));
237
238 return IPC_OK();
239 }
240
241 mChannelChild->ProcessOnStatus(aStatus);
242
243 return IPC_OK();
244 }
245
RecvFlushedForDiversion()246 IPCResult HttpBackgroundChannelChild::RecvFlushedForDiversion() {
247 LOG(("HttpBackgroundChannelChild::RecvFlushedForDiversion [this=%p]\n",
248 this));
249 MOZ_ASSERT(OnSocketThread());
250
251 if (NS_WARN_IF(!mChannelChild)) {
252 return IPC_OK();
253 }
254
255 if (IsWaitingOnStartRequest()) {
256 LOG((" > pending until OnStartRequest\n"));
257
258 mQueuedRunnables.AppendElement(NewRunnableMethod(
259 "HttpBackgroundChannelChild::RecvFlushedForDiversion", this,
260 &HttpBackgroundChannelChild::RecvFlushedForDiversion));
261
262 return IPC_OK();
263 }
264
265 mChannelChild->ProcessFlushedForDiversion();
266
267 return IPC_OK();
268 }
269
RecvDivertMessages()270 IPCResult HttpBackgroundChannelChild::RecvDivertMessages() {
271 LOG(("HttpBackgroundChannelChild::RecvDivertMessages [this=%p]\n", this));
272 MOZ_ASSERT(OnSocketThread());
273
274 if (NS_WARN_IF(!mChannelChild)) {
275 return IPC_OK();
276 }
277
278 if (IsWaitingOnStartRequest()) {
279 LOG((" > pending until OnStartRequest\n"));
280
281 mQueuedRunnables.AppendElement(NewRunnableMethod(
282 "HttpBackgroundChannelChild::RecvDivertMessages", this,
283 &HttpBackgroundChannelChild::RecvDivertMessages));
284
285 return IPC_OK();
286 }
287
288 mChannelChild->ProcessDivertMessages();
289
290 return IPC_OK();
291 }
292
RecvNotifyTrackingProtectionDisabled()293 IPCResult HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled() {
294 LOG(
295 ("HttpBackgroundChannelChild::RecvNotifyTrackingProtectionDisabled "
296 "[this=%p]\n",
297 this));
298 MOZ_ASSERT(OnSocketThread());
299
300 if (NS_WARN_IF(!mChannelChild)) {
301 return IPC_OK();
302 }
303
304 // NotifyTrackingProtectionDisabled has no order dependency to OnStartRequest.
305 // It this be handled as soon as possible
306 mChannelChild->ProcessNotifyTrackingProtectionDisabled();
307
308 return IPC_OK();
309 }
310
RecvNotifyTrackingResource()311 IPCResult HttpBackgroundChannelChild::RecvNotifyTrackingResource() {
312 LOG(("HttpBackgroundChannelChild::RecvNotifyTrackingResource [this=%p]\n",
313 this));
314 MOZ_ASSERT(OnSocketThread());
315
316 if (NS_WARN_IF(!mChannelChild)) {
317 return IPC_OK();
318 }
319
320 // NotifyTrackingResource has no order dependency to OnStartRequest.
321 // It this be handled as soon as possible
322 mChannelChild->ProcessNotifyTrackingResource();
323
324 return IPC_OK();
325 }
326
RecvSetClassifierMatchedInfo(const ClassifierInfo & info)327 IPCResult HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo(
328 const ClassifierInfo& info) {
329 LOG(("HttpBackgroundChannelChild::RecvSetClassifierMatchedInfo [this=%p]\n",
330 this));
331 MOZ_ASSERT(OnSocketThread());
332
333 if (NS_WARN_IF(!mChannelChild)) {
334 return IPC_OK();
335 }
336
337 // SetClassifierMatchedInfo has no order dependency to OnStartRequest.
338 // It this be handled as soon as possible
339 mChannelChild->ProcessSetClassifierMatchedInfo(info.list(), info.provider(),
340 info.fullhash());
341
342 return IPC_OK();
343 }
344
ActorDestroy(ActorDestroyReason aWhy)345 void HttpBackgroundChannelChild::ActorDestroy(ActorDestroyReason aWhy) {
346 LOG(("HttpBackgroundChannelChild::ActorDestroy[this=%p]\n", this));
347 // This function might be called during shutdown phase, so OnSocketThread()
348 // might return false even on STS thread. Use IsOnCurrentThreadInfallible()
349 // to get correct information.
350 MOZ_ASSERT(gSocketTransportService);
351 MOZ_ASSERT(gSocketTransportService->IsOnCurrentThreadInfallible());
352
353 // Ensure all IPC messages received before ActorDestroy can be
354 // handled correctly. If there is any pending IPC message, destroyed
355 // mChannelChild until those messages are flushed.
356 // If background channel is not closed by normal IPDL actor deletion,
357 // remove the HttpChannelChild reference and notify background channel
358 // destroyed immediately.
359 if (aWhy == Deletion && !mQueuedRunnables.IsEmpty()) {
360 LOG((" > pending until queued messages are flushed\n"));
361 RefPtr<HttpBackgroundChannelChild> self = this;
362 mQueuedRunnables.AppendElement(NS_NewRunnableFunction(
363 "HttpBackgroundChannelChild::ActorDestroy", [self]() {
364 MOZ_ASSERT(OnSocketThread());
365 RefPtr<HttpChannelChild> channelChild = self->mChannelChild.forget();
366
367 if (channelChild) {
368 channelChild->OnBackgroundChildDestroyed(self);
369 }
370 }));
371 return;
372 }
373
374 if (mChannelChild) {
375 RefPtr<HttpChannelChild> channelChild = mChannelChild.forget();
376
377 channelChild->OnBackgroundChildDestroyed(this);
378 }
379 }
380
381 } // namespace net
382 } // namespace mozilla
383