1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* vim:set ts=4 sw=4 sts=4 et cin: */
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 // HttpLog.h should generally be included first
8 #include "HttpLog.h"
9
10 #include "HttpTransactionChild.h"
11
12 #include "mozilla/ipc/IPCStreamUtils.h"
13 #include "mozilla/ipc/BackgroundParent.h"
14 #include "mozilla/net/BackgroundDataBridgeParent.h"
15 #include "mozilla/net/ChannelEventQueue.h"
16 #include "mozilla/net/InputChannelThrottleQueueChild.h"
17 #include "mozilla/net/SocketProcessChild.h"
18 #include "mozilla/ScopeExit.h"
19 #include "mozilla/StaticPrefs_network.h"
20 #include "nsInputStreamPump.h"
21 #include "nsITransportSecurityInfo.h"
22 #include "nsHttpHandler.h"
23 #include "nsNetUtil.h"
24 #include "nsProxyInfo.h"
25 #include "nsProxyRelease.h"
26 #include "nsQueryObject.h"
27 #include "nsSerializationHelper.h"
28
29 using mozilla::ipc::BackgroundParent;
30
31 namespace mozilla {
32 namespace net {
33
34 NS_IMPL_ISUPPORTS(HttpTransactionChild, nsIRequestObserver, nsIStreamListener,
35 nsITransportEventSink, nsIThrottledInputChannel,
36 nsIThreadRetargetableStreamListener);
37
38 //-----------------------------------------------------------------------------
39 // HttpTransactionChild <public>
40 //-----------------------------------------------------------------------------
41
HttpTransactionChild()42 HttpTransactionChild::HttpTransactionChild() {
43 LOG(("Creating HttpTransactionChild @%p\n", this));
44 }
45
~HttpTransactionChild()46 HttpTransactionChild::~HttpTransactionChild() {
47 LOG(("Destroying HttpTransactionChild @%p\n", this));
48 }
49
CreateRequestContext(uint64_t aRequestContextID)50 static already_AddRefed<nsIRequestContext> CreateRequestContext(
51 uint64_t aRequestContextID) {
52 if (!aRequestContextID) {
53 return nullptr;
54 }
55
56 nsIRequestContextService* rcsvc = gHttpHandler->GetRequestContextService();
57 if (!rcsvc) {
58 return nullptr;
59 }
60
61 nsCOMPtr<nsIRequestContext> requestContext;
62 rcsvc->GetRequestContext(aRequestContextID, getter_AddRefs(requestContext));
63
64 return requestContext.forget();
65 }
66
InitInternal(uint32_t caps,const HttpConnectionInfoCloneArgs & infoArgs,nsHttpRequestHead * requestHead,nsIInputStream * requestBody,uint64_t requestContentLength,bool requestBodyHasHeaders,uint64_t topLevelOuterContentWindowId,uint8_t httpTrafficCategory,uint64_t requestContextID,uint32_t classOfService,uint32_t initialRwin,bool responseTimeoutEnabled,uint64_t channelId,bool aHasTransactionObserver,const Maybe<H2PushedStreamArg> & aPushedStreamArg)67 nsresult HttpTransactionChild::InitInternal(
68 uint32_t caps, const HttpConnectionInfoCloneArgs& infoArgs,
69 nsHttpRequestHead* requestHead, nsIInputStream* requestBody,
70 uint64_t requestContentLength, bool requestBodyHasHeaders,
71 uint64_t topLevelOuterContentWindowId, uint8_t httpTrafficCategory,
72 uint64_t requestContextID, uint32_t classOfService, uint32_t initialRwin,
73 bool responseTimeoutEnabled, uint64_t channelId,
74 bool aHasTransactionObserver,
75 const Maybe<H2PushedStreamArg>& aPushedStreamArg) {
76 LOG(("HttpTransactionChild::InitInternal [this=%p caps=%x]\n", this, caps));
77
78 RefPtr<nsHttpConnectionInfo> cinfo =
79 nsHttpConnectionInfo::DeserializeHttpConnectionInfoCloneArgs(infoArgs);
80 nsCOMPtr<nsIRequestContext> rc = CreateRequestContext(requestContextID);
81
82 HttpTransactionShell::OnPushCallback pushCallback = nullptr;
83 if (caps & NS_HTTP_ONPUSH_LISTENER) {
84 RefPtr<HttpTransactionChild> self = this;
85 pushCallback = [self](uint32_t aPushedStreamId, const nsACString& aUrl,
86 const nsACString& aRequestString,
87 HttpTransactionShell* aTransaction) {
88 bool res = false;
89 if (self->CanSend()) {
90 res =
91 self->SendOnH2PushStream(aPushedStreamId, PromiseFlatCString(aUrl),
92 PromiseFlatCString(aRequestString));
93 }
94 return res ? NS_OK : NS_ERROR_FAILURE;
95 };
96 }
97
98 std::function<void(TransactionObserverResult &&)> observer;
99 if (aHasTransactionObserver) {
100 nsMainThreadPtrHandle<HttpTransactionChild> handle(
101 new nsMainThreadPtrHolder<HttpTransactionChild>(
102 "HttpTransactionChildProxy", this, false));
103 observer = [handle](TransactionObserverResult&& aResult) {
104 handle->mTransactionObserverResult.emplace(std::move(aResult));
105 };
106 }
107
108 RefPtr<nsHttpTransaction> transWithPushedStream;
109 uint32_t pushedStreamId = 0;
110 if (aPushedStreamArg) {
111 HttpTransactionChild* transChild = static_cast<HttpTransactionChild*>(
112 aPushedStreamArg.ref().transWithPushedStreamChild());
113 transWithPushedStream = transChild->GetHttpTransaction();
114 pushedStreamId = aPushedStreamArg.ref().pushedStreamId();
115 }
116
117 nsresult rv = mTransaction->Init(
118 caps, cinfo, requestHead, requestBody, requestContentLength,
119 requestBodyHasHeaders, GetCurrentEventTarget(),
120 nullptr, // TODO: security callback, fix in bug 1512479.
121 this, topLevelOuterContentWindowId,
122 static_cast<HttpTrafficCategory>(httpTrafficCategory), rc, classOfService,
123 initialRwin, responseTimeoutEnabled, channelId, std::move(observer),
124 std::move(pushCallback), transWithPushedStream, pushedStreamId);
125 if (NS_WARN_IF(NS_FAILED(rv))) {
126 mTransaction = nullptr;
127 return rv;
128 }
129
130 Unused << mTransaction->AsyncRead(this, getter_AddRefs(mTransactionPump));
131 return rv;
132 }
133
RecvCancelPump(const nsresult & aStatus)134 mozilla::ipc::IPCResult HttpTransactionChild::RecvCancelPump(
135 const nsresult& aStatus) {
136 LOG(("HttpTransactionChild::RecvCancelPump start [this=%p]\n", this));
137 CancelInternal(aStatus);
138 return IPC_OK();
139 }
140
CancelInternal(nsresult aStatus)141 void HttpTransactionChild::CancelInternal(nsresult aStatus) {
142 MOZ_ASSERT(NS_FAILED(aStatus));
143
144 mCanceled = true;
145 mStatus = aStatus;
146 if (mTransactionPump) {
147 mTransactionPump->Cancel(mStatus);
148 }
149 }
150
RecvSuspendPump()151 mozilla::ipc::IPCResult HttpTransactionChild::RecvSuspendPump() {
152 LOG(("HttpTransactionChild::RecvSuspendPump start [this=%p]\n", this));
153
154 if (mTransactionPump) {
155 mTransactionPump->Suspend();
156 }
157 return IPC_OK();
158 }
159
RecvResumePump()160 mozilla::ipc::IPCResult HttpTransactionChild::RecvResumePump() {
161 LOG(("HttpTransactionChild::RecvResumePump start [this=%p]\n", this));
162
163 if (mTransactionPump) {
164 mTransactionPump->Resume();
165 }
166 return IPC_OK();
167 }
168
RecvInit(const uint32_t & aCaps,const HttpConnectionInfoCloneArgs & aArgs,const nsHttpRequestHead & aReqHeaders,const Maybe<IPCStream> & aRequestBody,const uint64_t & aReqContentLength,const bool & aReqBodyIncludesHeaders,const uint64_t & aTopLevelOuterContentWindowId,const uint8_t & aHttpTrafficCategory,const uint64_t & aRequestContextID,const uint32_t & aClassOfService,const uint32_t & aInitialRwin,const bool & aResponseTimeoutEnabled,const uint64_t & aChannelId,const bool & aHasTransactionObserver,const Maybe<H2PushedStreamArg> & aPushedStreamArg,const mozilla::Maybe<PInputChannelThrottleQueueChild * > & aThrottleQueue,const bool & aIsDocumentLoad,const TimeStamp & aRedirectStart,const TimeStamp & aRedirectEnd)169 mozilla::ipc::IPCResult HttpTransactionChild::RecvInit(
170 const uint32_t& aCaps, const HttpConnectionInfoCloneArgs& aArgs,
171 const nsHttpRequestHead& aReqHeaders, const Maybe<IPCStream>& aRequestBody,
172 const uint64_t& aReqContentLength, const bool& aReqBodyIncludesHeaders,
173 const uint64_t& aTopLevelOuterContentWindowId,
174 const uint8_t& aHttpTrafficCategory, const uint64_t& aRequestContextID,
175 const uint32_t& aClassOfService, const uint32_t& aInitialRwin,
176 const bool& aResponseTimeoutEnabled, const uint64_t& aChannelId,
177 const bool& aHasTransactionObserver,
178 const Maybe<H2PushedStreamArg>& aPushedStreamArg,
179 const mozilla::Maybe<PInputChannelThrottleQueueChild*>& aThrottleQueue,
180 const bool& aIsDocumentLoad, const TimeStamp& aRedirectStart,
181 const TimeStamp& aRedirectEnd) {
182 mRequestHead = aReqHeaders;
183 if (aRequestBody) {
184 mUploadStream = mozilla::ipc::DeserializeIPCStream(aRequestBody);
185 }
186
187 mTransaction = new nsHttpTransaction();
188 mChannelId = aChannelId;
189 mIsDocumentLoad = aIsDocumentLoad;
190 mRedirectStart = aRedirectStart;
191 mRedirectEnd = aRedirectEnd;
192
193 if (aThrottleQueue.isSome()) {
194 mThrottleQueue =
195 static_cast<InputChannelThrottleQueueChild*>(aThrottleQueue.ref());
196 }
197
198 nsresult rv = InitInternal(
199 aCaps, aArgs, &mRequestHead, mUploadStream, aReqContentLength,
200 aReqBodyIncludesHeaders, aTopLevelOuterContentWindowId,
201 aHttpTrafficCategory, aRequestContextID, aClassOfService, aInitialRwin,
202 aResponseTimeoutEnabled, aChannelId, aHasTransactionObserver,
203 aPushedStreamArg);
204 if (NS_FAILED(rv)) {
205 LOG(("HttpTransactionChild::RecvInit: [this=%p] InitInternal failed!\n",
206 this));
207 mTransaction = nullptr;
208 SendOnInitFailed(rv);
209 }
210 return IPC_OK();
211 }
212
RecvSetDNSWasRefreshed()213 mozilla::ipc::IPCResult HttpTransactionChild::RecvSetDNSWasRefreshed() {
214 LOG(("HttpTransactionChild::SetDNSWasRefreshed [this=%p]\n", this));
215 if (mTransaction) {
216 mTransaction->SetDNSWasRefreshed();
217 }
218 return IPC_OK();
219 }
220
RecvDontReuseConnection()221 mozilla::ipc::IPCResult HttpTransactionChild::RecvDontReuseConnection() {
222 LOG(("HttpTransactionChild::RecvDontReuseConnection [this=%p]\n", this));
223 if (mTransaction) {
224 mTransaction->DontReuseConnection();
225 }
226 return IPC_OK();
227 }
228
RecvSetH2WSConnRefTaken()229 mozilla::ipc::IPCResult HttpTransactionChild::RecvSetH2WSConnRefTaken() {
230 LOG(("HttpTransactionChild::RecvSetH2WSConnRefTaken [this=%p]\n", this));
231 if (mTransaction) {
232 mTransaction->SetH2WSConnRefTaken();
233 }
234 return IPC_OK();
235 }
236
ActorDestroy(ActorDestroyReason aWhy)237 void HttpTransactionChild::ActorDestroy(ActorDestroyReason aWhy) {
238 LOG(("HttpTransactionChild::ActorDestroy [this=%p]\n", this));
239 mTransaction = nullptr;
240 mTransactionPump = nullptr;
241 }
242
GetHttpTransaction()243 nsHttpTransaction* HttpTransactionChild::GetHttpTransaction() {
244 return mTransaction.get();
245 }
246
247 //-----------------------------------------------------------------------------
248 // HttpTransactionChild <nsIStreamListener>
249 //-----------------------------------------------------------------------------
250
251 NS_IMETHODIMP
OnDataAvailable(nsIRequest * aRequest,nsIInputStream * aInputStream,uint64_t aOffset,uint32_t aCount)252 HttpTransactionChild::OnDataAvailable(nsIRequest* aRequest,
253 nsIInputStream* aInputStream,
254 uint64_t aOffset, uint32_t aCount) {
255 LOG(("HttpTransactionChild::OnDataAvailable [this=%p, aOffset= %" PRIu64
256 " aCount=%" PRIu32 "]\n",
257 this, aOffset, aCount));
258
259 // Don't bother sending IPC if already canceled.
260 if (mCanceled) {
261 return mStatus;
262 }
263
264 // TODO: send string data in chunks and handle errors. Bug 1600129.
265 nsCString data;
266 nsresult rv = NS_ReadInputStreamToString(aInputStream, data, aCount);
267 if (NS_FAILED(rv)) {
268 return rv;
269 }
270
271 mLogicalOffset += aCount;
272
273 if (NS_IsMainThread()) {
274 if (!CanSend()) {
275 return NS_ERROR_FAILURE;
276 }
277
278 nsHttp::SendFunc<nsCString> sendFunc =
279 [self = UnsafePtr<HttpTransactionChild>(this)](
280 const nsCString& aData, uint64_t aOffset, uint32_t aCount) {
281 return self->SendOnDataAvailable(aData, aOffset, aCount);
282 };
283
284 LOG((" ODA to parent process"));
285 if (!nsHttp::SendDataInChunks(data, aOffset, aCount, sendFunc)) {
286 return NS_ERROR_FAILURE;
287 }
288 return NS_OK;
289 }
290
291 ipc::AssertIsOnBackgroundThread();
292 MOZ_ASSERT(mDataBridgeParent);
293
294 if (!mDataBridgeParent->CanSend()) {
295 return NS_ERROR_FAILURE;
296 }
297
298 nsHttp::SendFunc<nsDependentCSubstring> sendFunc =
299 [self = UnsafePtr<HttpTransactionChild>(this)](
300 const nsDependentCSubstring& aData, uint64_t aOffset,
301 uint32_t aCount) {
302 return self->mDataBridgeParent->SendOnTransportAndData(aOffset, aCount,
303 aData);
304 };
305
306 LOG((" ODA to content process"));
307 if (!nsHttp::SendDataInChunks(data, aOffset, aCount, sendFunc)) {
308 MOZ_ASSERT(false, "Send ODA to content process failed");
309 return NS_ERROR_FAILURE;
310 }
311
312 // We still need to send ODA to parent process, because the data needs to be
313 // saved in cache. Note that we set dataSentToChildProcess to true, to this
314 // ODA will not be sent to child process.
315 RefPtr<HttpTransactionChild> self = this;
316 rv = NS_DispatchToMainThread(
317 NS_NewRunnableFunction(
318 "HttpTransactionChild::OnDataAvailable",
319 [self, offset(aOffset), count(aCount), data(data)]() {
320 nsHttp::SendFunc<nsCString> sendFunc =
321 [self](const nsCString& aData, uint64_t aOffset,
322 uint32_t aCount) {
323 return self->SendOnDataAvailable(aData, aOffset, aCount);
324 };
325
326 if (!nsHttp::SendDataInChunks(data, offset, count, sendFunc)) {
327 self->CancelInternal(NS_ERROR_FAILURE);
328 }
329 }),
330 NS_DISPATCH_NORMAL);
331 MOZ_ASSERT(NS_SUCCEEDED(rv));
332
333 return NS_OK;
334 }
335
ToTimingStructArgs(TimingStruct aTiming)336 static TimingStructArgs ToTimingStructArgs(TimingStruct aTiming) {
337 TimingStructArgs args;
338 args.domainLookupStart() = aTiming.domainLookupStart;
339 args.domainLookupEnd() = aTiming.domainLookupEnd;
340 args.connectStart() = aTiming.connectStart;
341 args.tcpConnectEnd() = aTiming.tcpConnectEnd;
342 args.secureConnectionStart() = aTiming.secureConnectionStart;
343 args.connectEnd() = aTiming.connectEnd;
344 args.requestStart() = aTiming.requestStart;
345 args.responseStart() = aTiming.responseStart;
346 args.responseEnd() = aTiming.responseEnd;
347 return args;
348 }
349
350 // The maximum number of bytes to consider when attempting to sniff.
351 // See https://mimesniff.spec.whatwg.org/#reading-the-resource-header.
352 static const uint32_t MAX_BYTES_SNIFFED = 1445;
353
GetDataForSniffer(void * aClosure,const uint8_t * aData,uint32_t aCount)354 static void GetDataForSniffer(void* aClosure, const uint8_t* aData,
355 uint32_t aCount) {
356 nsTArray<uint8_t>* outData = static_cast<nsTArray<uint8_t>*>(aClosure);
357 outData->AppendElements(aData, std::min(aCount, MAX_BYTES_SNIFFED));
358 }
359
CanSendODAToContentProcessDirectly(const Maybe<nsHttpResponseHead> & aHead)360 bool HttpTransactionChild::CanSendODAToContentProcessDirectly(
361 const Maybe<nsHttpResponseHead>& aHead) {
362 if (!StaticPrefs::network_send_ODA_to_content_directly()) {
363 return false;
364 }
365
366 // If this is a document load, the content process that receives ODA is not
367 // decided yet, so don't bother to do the rest check.
368 if (mIsDocumentLoad) {
369 return false;
370 }
371
372 if (!aHead) {
373 return false;
374 }
375
376 // We only need to deliver ODA when the response is succeed.
377 if (aHead->Status() != 200) {
378 return false;
379 }
380
381 // UnknownDecoder could be used in parent process, so we can't send ODA to
382 // content process.
383 if (!aHead->HasContentType()) {
384 return false;
385 }
386
387 return true;
388 }
389
390 NS_IMETHODIMP
OnStartRequest(nsIRequest * aRequest)391 HttpTransactionChild::OnStartRequest(nsIRequest* aRequest) {
392 LOG(("HttpTransactionChild::OnStartRequest start [this=%p] mTransaction=%p\n",
393 this, mTransaction.get()));
394
395 // Don't bother sending IPC to parent process if already canceled.
396 if (mCanceled) {
397 return mStatus;
398 }
399
400 if (!CanSend()) {
401 return NS_ERROR_FAILURE;
402 }
403
404 MOZ_ASSERT(mTransaction);
405
406 nsresult status;
407 aRequest->GetStatus(&status);
408
409 mProtocolVersion.Truncate();
410
411 nsCString serializedSecurityInfoOut;
412 nsCOMPtr<nsISupports> secInfoSupp = mTransaction->SecurityInfo();
413 if (secInfoSupp) {
414 nsCOMPtr<nsITransportSecurityInfo> info = do_QueryInterface(secInfoSupp);
415 nsAutoCString protocol;
416 if (info && NS_SUCCEEDED(info->GetNegotiatedNPN(protocol)) &&
417 !protocol.IsEmpty()) {
418 mProtocolVersion.Assign(protocol);
419 }
420 nsCOMPtr<nsISerializable> secInfoSer = do_QueryInterface(secInfoSupp);
421 if (secInfoSer) {
422 NS_SerializeToString(secInfoSer, serializedSecurityInfoOut);
423 }
424 }
425
426 UniquePtr<nsHttpResponseHead> head(mTransaction->TakeResponseHead());
427 Maybe<nsHttpResponseHead> optionalHead;
428 nsTArray<uint8_t> dataForSniffer;
429 if (head) {
430 if (mProtocolVersion.IsEmpty()) {
431 HttpVersion version = head->Version();
432 mProtocolVersion.Assign(nsHttp::GetProtocolVersion(version));
433 }
434 optionalHead = Some(*head);
435 if (mTransaction->Caps() & NS_HTTP_CALL_CONTENT_SNIFFER) {
436 nsAutoCString contentTypeOptionsHeader;
437 if (!(head->GetContentTypeOptionsHeader(contentTypeOptionsHeader) &&
438 contentTypeOptionsHeader.EqualsIgnoreCase("nosniff"))) {
439 RefPtr<nsInputStreamPump> pump = do_QueryObject(mTransactionPump);
440 pump->PeekStream(GetDataForSniffer, &dataForSniffer);
441 }
442 }
443 }
444
445 Maybe<nsCString> optionalAltSvcUsed;
446 nsCString altSvcUsed;
447 if (NS_SUCCEEDED(mTransaction->RequestHead()->GetHeader(
448 nsHttp::Alternate_Service_Used, altSvcUsed)) &&
449 !altSvcUsed.IsEmpty()) {
450 optionalAltSvcUsed.emplace(altSvcUsed);
451 }
452
453 if (CanSendODAToContentProcessDirectly(optionalHead)) {
454 Maybe<RefPtr<BackgroundDataBridgeParent>> dataBridgeParent =
455 SocketProcessChild::GetSingleton()->GetAndRemoveDataBridge(mChannelId);
456 // Check if there is a registered BackgroundDataBridgeParent.
457 if (dataBridgeParent) {
458 mDataBridgeParent = std::move(dataBridgeParent.ref());
459
460 nsCOMPtr<nsIThread> backgroundThread =
461 mDataBridgeParent->GetBackgroundThread();
462 nsCOMPtr<nsIThreadRetargetableRequest> retargetableTransactionPump;
463 retargetableTransactionPump = do_QueryObject(mTransactionPump);
464 // nsInputStreamPump should implement this interface.
465 MOZ_ASSERT(retargetableTransactionPump);
466
467 nsresult rv =
468 retargetableTransactionPump->RetargetDeliveryTo(backgroundThread);
469 LOG((" Retarget to background thread [this=%p rv=%08x]\n", this,
470 static_cast<uint32_t>(rv)));
471 if (NS_FAILED(rv)) {
472 mDataBridgeParent->Destroy();
473 mDataBridgeParent = nullptr;
474 }
475 }
476 }
477
478 int32_t proxyConnectResponseCode =
479 mTransaction->GetProxyConnectResponseCode();
480
481 Unused << SendOnStartRequest(
482 status, optionalHead, serializedSecurityInfoOut,
483 mTransaction->ProxyConnectFailed(),
484 ToTimingStructArgs(mTransaction->Timings()), proxyConnectResponseCode,
485 dataForSniffer, optionalAltSvcUsed, !!mDataBridgeParent,
486 mTransaction->TakeRestartedState(), mTransaction->HTTPSSVCReceivedStage(),
487 mTransaction->GetSupportsHTTP3());
488 return NS_OK;
489 }
490
GetTimingAttributes()491 ResourceTimingStructArgs HttpTransactionChild::GetTimingAttributes() {
492 // Note that not all fields in ResourceTimingStructArgs are filled, since
493 // we only need some in HttpChannelChild::OnStopRequest.
494 ResourceTimingStructArgs args;
495 args.domainLookupStart() = mTransaction->GetDomainLookupStart();
496 args.domainLookupEnd() = mTransaction->GetDomainLookupEnd();
497 args.connectStart() = mTransaction->GetConnectStart();
498 args.tcpConnectEnd() = mTransaction->GetTcpConnectEnd();
499 args.secureConnectionStart() = mTransaction->GetSecureConnectionStart();
500 args.connectEnd() = mTransaction->GetConnectEnd();
501 args.requestStart() = mTransaction->GetRequestStart();
502 args.responseStart() = mTransaction->GetResponseStart();
503 args.responseEnd() = mTransaction->GetResponseEnd();
504 args.transferSize() = mTransaction->GetTransferSize();
505 args.encodedBodySize() = mLogicalOffset;
506 args.redirectStart() = mRedirectStart;
507 args.redirectEnd() = mRedirectEnd;
508 args.protocolVersion() = mProtocolVersion;
509 return args;
510 }
511
512 NS_IMETHODIMP
OnStopRequest(nsIRequest * aRequest,nsresult aStatus)513 HttpTransactionChild::OnStopRequest(nsIRequest* aRequest, nsresult aStatus) {
514 LOG(("HttpTransactionChild::OnStopRequest [this=%p]\n", this));
515
516 mTransactionPump = nullptr;
517
518 auto onStopGuard = MakeScopeExit([&] {
519 LOG((" calling mDataBridgeParent->OnStopRequest by ScopeExit [this=%p]\n",
520 this));
521 MOZ_ASSERT(NS_FAILED(mStatus), "This shoule be only called when failure");
522 if (mDataBridgeParent) {
523 mDataBridgeParent->OnStopRequest(mStatus, ResourceTimingStructArgs(),
524 TimeStamp(), nsHttpHeaderArray());
525 mDataBridgeParent = nullptr;
526 }
527 });
528
529 // Don't bother sending IPC to parent process if already canceled.
530 if (mCanceled) {
531 return mStatus;
532 }
533
534 if (!CanSend()) {
535 mStatus = NS_ERROR_UNEXPECTED;
536 return mStatus;
537 }
538
539 MOZ_ASSERT(mTransaction);
540
541 UniquePtr<nsHttpHeaderArray> headerArray(
542 mTransaction->TakeResponseTrailers());
543 Maybe<nsHttpHeaderArray> responseTrailers;
544 if (headerArray) {
545 responseTrailers.emplace(*headerArray);
546 }
547
548 onStopGuard.release();
549
550 TimeStamp lastActTabOpt = nsHttp::GetLastActiveTabLoadOptimizationHit();
551
552 if (mDataBridgeParent) {
553 mDataBridgeParent->OnStopRequest(
554 aStatus, GetTimingAttributes(), lastActTabOpt,
555 responseTrailers ? *responseTrailers : nsHttpHeaderArray());
556 mDataBridgeParent = nullptr;
557 }
558
559 RefPtr<nsHttpConnectionInfo> connInfo = mTransaction->GetConnInfo();
560 HttpConnectionInfoCloneArgs infoArgs;
561 nsHttpConnectionInfo::SerializeHttpConnectionInfo(connInfo, infoArgs);
562 Unused << SendOnStopRequest(aStatus, mTransaction->ResponseIsComplete(),
563 mTransaction->GetTransferSize(),
564 ToTimingStructArgs(mTransaction->Timings()),
565 responseTrailers, mTransactionObserverResult,
566 lastActTabOpt, mTransaction->Caps(), infoArgs);
567
568 return NS_OK;
569 }
570
571 //-----------------------------------------------------------------------------
572 // HttpTransactionChild <nsITransportEventSink>
573 //-----------------------------------------------------------------------------
574
575 NS_IMETHODIMP
OnTransportStatus(nsITransport * aTransport,nsresult aStatus,int64_t aProgress,int64_t aProgressMax)576 HttpTransactionChild::OnTransportStatus(nsITransport* aTransport,
577 nsresult aStatus, int64_t aProgress,
578 int64_t aProgressMax) {
579 LOG(("HttpTransactionChild::OnTransportStatus [this=%p status=%" PRIx32
580 " progress=%" PRId64 "]\n",
581 this, static_cast<uint32_t>(aStatus), aProgress));
582
583 if (!CanSend()) {
584 return NS_OK;
585 }
586
587 Maybe<NetworkAddressArg> arg;
588 if (aStatus == NS_NET_STATUS_CONNECTED_TO ||
589 aStatus == NS_NET_STATUS_WAITING_FOR) {
590 NetAddr selfAddr;
591 NetAddr peerAddr;
592 bool isTrr = false;
593 bool echConfigUsed = false;
594 if (mTransaction) {
595 mTransaction->GetNetworkAddresses(selfAddr, peerAddr, isTrr,
596 echConfigUsed);
597 } else {
598 nsCOMPtr<nsISocketTransport> socketTransport =
599 do_QueryInterface(aTransport);
600 if (socketTransport) {
601 socketTransport->GetSelfAddr(&selfAddr);
602 socketTransport->GetPeerAddr(&peerAddr);
603 socketTransport->ResolvedByTRR(&isTrr);
604 socketTransport->GetEchConfigUsed(&echConfigUsed);
605 }
606 }
607 arg.emplace(selfAddr, peerAddr, isTrr, echConfigUsed);
608 }
609
610 Unused << SendOnTransportStatus(aStatus, aProgress, aProgressMax, arg);
611 return NS_OK;
612 }
613
614 //-----------------------------------------------------------------------------
615 // HttpBaseChannel::nsIThrottledInputChannel
616 //-----------------------------------------------------------------------------
617
618 NS_IMETHODIMP
SetThrottleQueue(nsIInputChannelThrottleQueue * aQueue)619 HttpTransactionChild::SetThrottleQueue(nsIInputChannelThrottleQueue* aQueue) {
620 return NS_ERROR_NOT_IMPLEMENTED;
621 }
622
623 NS_IMETHODIMP
GetThrottleQueue(nsIInputChannelThrottleQueue ** aQueue)624 HttpTransactionChild::GetThrottleQueue(nsIInputChannelThrottleQueue** aQueue) {
625 nsCOMPtr<nsIInputChannelThrottleQueue> queue =
626 static_cast<nsIInputChannelThrottleQueue*>(mThrottleQueue.get());
627 queue.forget(aQueue);
628 return NS_OK;
629 }
630
631 //-----------------------------------------------------------------------------
632 // EventSourceImpl::nsIThreadRetargetableStreamListener
633 //-----------------------------------------------------------------------------
634 NS_IMETHODIMP
CheckListenerChain()635 HttpTransactionChild::CheckListenerChain() {
636 MOZ_ASSERT(NS_IsMainThread(), "Should be on the main thread!");
637 return NS_OK;
638 }
639
640 } // namespace net
641 } // namespace mozilla
642