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/. */
7 // HttpLog.h should generally be included first
10 #include "HttpTransactionParent.h"
12 #include "HttpTrafficAnalyzer.h"
13 #include "mozilla/ipc/IPCStreamUtils.h"
14 #include "mozilla/net/ChannelEventQueue.h"
15 #include "mozilla/net/InputChannelThrottleQueueParent.h"
16 #include "mozilla/net/SocketProcessParent.h"
17 #include "nsHttpHandler.h"
18 #include "nsIThreadRetargetableStreamListener.h"
19 #include "nsITransportSecurityInfo.h"
20 #include "nsNetUtil.h"
21 #include "nsQueryObject.h"
22 #include "nsSerializationHelper.h"
23 #include "nsStreamUtils.h"
24 #include "nsStringStream.h"
26 namespace mozilla::net
{
28 NS_IMPL_ADDREF(HttpTransactionParent
)
29 NS_INTERFACE_MAP_BEGIN(HttpTransactionParent
)
30 NS_INTERFACE_MAP_ENTRY(nsIRequest
)
31 NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest
)
32 NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpTransactionParent
)
33 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports
, nsIRequest
)
36 NS_IMETHODIMP_(MozExternalRefCountType
) HttpTransactionParent::Release(void) {
37 MOZ_ASSERT(int32_t(mRefCnt
) > 0, "dup release");
38 nsrefcnt count
= --mRefCnt
;
39 NS_LOG_RELEASE(this, count
, "HttpTransactionParent");
41 mRefCnt
= 1; /* stabilize */
46 // When ref count goes down to 1 (held internally by IPDL), it means that
47 // we are done with this transaction. We should send a delete message
48 // to delete the transaction child in socket process.
49 if (count
== 1 && CanSend()) {
50 if (!NS_IsMainThread()) {
51 RefPtr
<HttpTransactionParent
> self
= this;
52 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread(
53 NS_NewRunnableFunction("HttpTransactionParent::Release", [self
]() {
54 mozilla::Unused
<< self
->Send__delete__(self
);
55 // Make sure we can not send IPC after Send__delete__().
56 MOZ_ASSERT(!self
->CanSend());
59 mozilla::Unused
<< Send__delete__(this);
66 //-----------------------------------------------------------------------------
67 // HttpTransactionParent <public>
68 //-----------------------------------------------------------------------------
70 HttpTransactionParent::HttpTransactionParent(bool aIsDocumentLoad
)
71 : mIsDocumentLoad(aIsDocumentLoad
) {
72 LOG(("Creating HttpTransactionParent @%p\n", this));
73 mEventQ
= new ChannelEventQueue(static_cast<nsIRequest
*>(this));
76 HttpTransactionParent::~HttpTransactionParent() {
77 LOG(("Destroying HttpTransactionParent @%p\n", this));
78 mEventQ
->NotifyReleasingOwner();
81 //-----------------------------------------------------------------------------
82 // HttpTransactionParent <nsAHttpTransactionShell>
83 //-----------------------------------------------------------------------------
85 // Let socket process init the *real* nsHttpTransaction.
86 nsresult
HttpTransactionParent::Init(
87 uint32_t caps
, nsHttpConnectionInfo
* cinfo
, nsHttpRequestHead
* requestHead
,
88 nsIInputStream
* requestBody
, uint64_t requestContentLength
,
89 bool requestBodyHasHeaders
, nsIEventTarget
* target
,
90 nsIInterfaceRequestor
* callbacks
, nsITransportEventSink
* eventsink
,
91 uint64_t browserId
, HttpTrafficCategory trafficCategory
,
92 nsIRequestContext
* requestContext
, ClassOfService classOfService
,
93 uint32_t initialRwin
, bool responseTimeoutEnabled
, uint64_t channelId
,
94 TransactionObserverFunc
&& transactionObserver
,
95 OnPushCallback
&& aOnPushCallback
,
96 HttpTransactionShell
* aTransWithPushedStream
, uint32_t aPushedStreamId
) {
97 LOG(("HttpTransactionParent::Init [this=%p caps=%x]\n", this, caps
));
100 return NS_ERROR_FAILURE
;
103 mEventsink
= eventsink
;
104 mTargetThread
= GetCurrentSerialEventTarget();
105 mChannelId
= channelId
;
106 mTransactionObserver
= std::move(transactionObserver
);
107 mOnPushCallback
= std::move(aOnPushCallback
);
109 mConnInfo
= cinfo
->Clone();
110 mIsHttp3Used
= cinfo
->IsHttp3();
112 HttpConnectionInfoCloneArgs infoArgs
;
113 nsHttpConnectionInfo::SerializeHttpConnectionInfo(cinfo
, infoArgs
);
115 Maybe
<mozilla::ipc::IPCStream
> ipcStream
;
116 if (!mozilla::ipc::SerializeIPCStream(do_AddRef(requestBody
), ipcStream
,
117 /* aAllowLazy */ false)) {
118 return NS_ERROR_FAILURE
;
121 uint64_t requestContextID
= requestContext
? requestContext
->GetID() : 0;
123 Maybe
<H2PushedStreamArg
> pushedStreamArg
;
124 if (aTransWithPushedStream
&& aPushedStreamId
) {
125 MOZ_ASSERT(aTransWithPushedStream
->AsHttpTransactionParent());
126 pushedStreamArg
.emplace(
127 WrapNotNull(aTransWithPushedStream
->AsHttpTransactionParent()),
131 nsCOMPtr
<nsIThrottledInputChannel
> throttled
= do_QueryInterface(mEventsink
);
132 Maybe
<NotNull
<PInputChannelThrottleQueueParent
*>> throttleQueue
;
134 nsCOMPtr
<nsIInputChannelThrottleQueue
> queue
;
135 nsresult rv
= throttled
->GetThrottleQueue(getter_AddRefs(queue
));
136 // In case of failure, just carry on without throttling.
137 if (NS_SUCCEEDED(rv
) && queue
) {
138 LOG1(("HttpTransactionParent::Init %p using throttle queue %p\n", this,
140 RefPtr
<InputChannelThrottleQueueParent
> tqParent
= do_QueryObject(queue
);
141 MOZ_ASSERT(tqParent
);
142 throttleQueue
.emplace(WrapNotNull(tqParent
.get()));
146 // TODO: Figure out if we have to implement nsIThreadRetargetableRequest in
148 if (!SendInit(caps
, infoArgs
, *requestHead
, ipcStream
, requestContentLength
,
149 requestBodyHasHeaders
, browserId
,
150 static_cast<uint8_t>(trafficCategory
), requestContextID
,
151 classOfService
, initialRwin
, responseTimeoutEnabled
, mChannelId
,
152 !!mTransactionObserver
, pushedStreamArg
, throttleQueue
,
153 mIsDocumentLoad
, mRedirectStart
, mRedirectEnd
)) {
154 return NS_ERROR_FAILURE
;
157 nsCString reqHeaderBuf
= nsHttp::ConvertRequestHeadToString(
158 *requestHead
, !!requestBody
, requestBodyHasHeaders
,
159 cinfo
->UsingConnect());
160 requestContentLength
+= reqHeaderBuf
.Length();
162 mRequestSize
= InScriptableRange(requestContentLength
)
163 ? static_cast<int64_t>(requestContentLength
)
169 nsresult
HttpTransactionParent::AsyncRead(nsIStreamListener
* listener
,
173 *pump
= do_AddRef(this).take();
178 UniquePtr
<nsHttpResponseHead
> HttpTransactionParent::TakeResponseHead() {
179 MOZ_ASSERT(NS_IsMainThread());
180 MOZ_ASSERT(!mResponseHeadTaken
, "TakeResponseHead called 2x");
182 mResponseHeadTaken
= true;
183 return std::move(mResponseHead
);
186 UniquePtr
<nsHttpHeaderArray
> HttpTransactionParent::TakeResponseTrailers() {
187 MOZ_ASSERT(NS_IsMainThread());
188 MOZ_ASSERT(!mResponseTrailersTaken
, "TakeResponseTrailers called 2x");
190 mResponseTrailersTaken
= true;
191 return std::move(mResponseTrailers
);
194 void HttpTransactionParent::SetSniffedTypeToChannel(
195 nsInputStreamPump::PeekSegmentFun aCallTypeSniffers
, nsIChannel
* aChannel
) {
196 if (!mDataForSniffer
.IsEmpty()) {
197 aCallTypeSniffers(aChannel
, mDataForSniffer
.Elements(),
198 mDataForSniffer
.Length());
203 HttpTransactionParent::GetDeliveryTarget(nsISerialEventTarget
** aEventTarget
) {
204 MutexAutoLock
lock(mEventTargetMutex
);
206 nsCOMPtr
<nsISerialEventTarget
> target
= mODATarget
;
208 target
= mTargetThread
;
210 target
.forget(aEventTarget
);
214 already_AddRefed
<nsISerialEventTarget
> HttpTransactionParent::GetODATarget() {
215 nsCOMPtr
<nsISerialEventTarget
> target
;
217 MutexAutoLock
lock(mEventTargetMutex
);
218 target
= mODATarget
? mODATarget
: mTargetThread
;
222 target
= GetMainThreadSerialEventTarget();
224 return target
.forget();
227 NS_IMETHODIMP
HttpTransactionParent::RetargetDeliveryTo(
228 nsISerialEventTarget
* aEventTarget
) {
229 LOG(("HttpTransactionParent::RetargetDeliveryTo [this=%p, aTarget=%p]", this,
232 MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only");
233 MOZ_ASSERT(!mODATarget
);
234 NS_ENSURE_ARG(aEventTarget
);
236 if (aEventTarget
->IsOnCurrentThread()) {
237 NS_WARNING("Retargeting delivery to same thread");
242 nsCOMPtr
<nsIThreadRetargetableStreamListener
> retargetableListener
=
243 do_QueryInterface(mChannel
, &rv
);
244 if (!retargetableListener
|| NS_FAILED(rv
)) {
245 NS_WARNING("Listener is not retargetable");
246 return NS_ERROR_NO_INTERFACE
;
249 rv
= retargetableListener
->CheckListenerChain();
251 NS_WARNING("Subsequent listeners are not retargetable");
256 MutexAutoLock
lock(mEventTargetMutex
);
257 mODATarget
= aEventTarget
;
263 void HttpTransactionParent::SetDNSWasRefreshed() {
264 MOZ_ASSERT(NS_IsMainThread(), "SetDNSWasRefreshed on main thread only!");
265 Unused
<< SendSetDNSWasRefreshed();
268 void HttpTransactionParent::GetNetworkAddresses(
269 NetAddr
& self
, NetAddr
& peer
, bool& aResolvedByTRR
,
270 nsIRequest::TRRMode
& aEffectiveTRRMode
, TRRSkippedReason
& aSkipReason
,
271 bool& aEchConfigUsed
) {
274 aResolvedByTRR
= mResolvedByTRR
;
275 aEffectiveTRRMode
= mEffectiveTRRMode
;
276 aSkipReason
= mTRRSkipReason
;
277 aEchConfigUsed
= mEchConfigUsed
;
280 bool HttpTransactionParent::HasStickyConnection() const {
281 return mCaps
& NS_HTTP_STICKY_CONNECTION
;
284 mozilla::TimeStamp
HttpTransactionParent::GetDomainLookupStart() {
285 return mTimings
.domainLookupStart
;
288 mozilla::TimeStamp
HttpTransactionParent::GetDomainLookupEnd() {
289 return mTimings
.domainLookupEnd
;
292 mozilla::TimeStamp
HttpTransactionParent::GetConnectStart() {
293 return mTimings
.connectStart
;
296 mozilla::TimeStamp
HttpTransactionParent::GetTcpConnectEnd() {
297 return mTimings
.tcpConnectEnd
;
300 mozilla::TimeStamp
HttpTransactionParent::GetSecureConnectionStart() {
301 return mTimings
.secureConnectionStart
;
304 mozilla::TimeStamp
HttpTransactionParent::GetConnectEnd() {
305 return mTimings
.connectEnd
;
308 mozilla::TimeStamp
HttpTransactionParent::GetRequestStart() {
309 return mTimings
.requestStart
;
312 mozilla::TimeStamp
HttpTransactionParent::GetResponseStart() {
313 return mTimings
.responseStart
;
316 mozilla::TimeStamp
HttpTransactionParent::GetResponseEnd() {
317 return mTimings
.responseEnd
;
320 TimingStruct
HttpTransactionParent::Timings() { return mTimings
; }
322 bool HttpTransactionParent::ResponseIsComplete() { return mResponseIsComplete
; }
324 int64_t HttpTransactionParent::GetTransferSize() { return mTransferSize
; }
326 int64_t HttpTransactionParent::GetRequestSize() { return mRequestSize
; }
328 bool HttpTransactionParent::IsHttp3Used() { return mIsHttp3Used
; }
330 bool HttpTransactionParent::DataSentToChildProcess() {
331 return mDataSentToChildProcess
;
334 already_AddRefed
<nsITransportSecurityInfo
>
335 HttpTransactionParent::SecurityInfo() {
336 return do_AddRef(mSecurityInfo
);
339 bool HttpTransactionParent::ProxyConnectFailed() { return mProxyConnectFailed
; }
341 bool HttpTransactionParent::TakeRestartedState() {
342 bool result
= mRestarted
;
347 uint32_t HttpTransactionParent::HTTPSSVCReceivedStage() {
348 return mHTTPSSVCReceivedStage
;
351 void HttpTransactionParent::DontReuseConnection() {
352 MOZ_ASSERT(NS_IsMainThread());
353 Unused
<< SendDontReuseConnection();
356 void HttpTransactionParent::SetH2WSConnRefTaken() {
357 MOZ_ASSERT(NS_IsMainThread());
358 Unused
<< SendSetH2WSConnRefTaken();
361 void HttpTransactionParent::SetSecurityCallbacks(
362 nsIInterfaceRequestor
* aCallbacks
) {
363 // TODO: we might don't need to implement this.
364 // Will figure out in bug 1512479.
367 void HttpTransactionParent::SetDomainLookupStart(mozilla::TimeStamp timeStamp
,
369 mDomainLookupStart
= timeStamp
;
370 mTimings
.domainLookupStart
= mDomainLookupStart
;
372 void HttpTransactionParent::SetDomainLookupEnd(mozilla::TimeStamp timeStamp
,
374 mDomainLookupEnd
= timeStamp
;
375 mTimings
.domainLookupEnd
= mDomainLookupEnd
;
378 nsHttpTransaction
* HttpTransactionParent::AsHttpTransaction() {
382 HttpTransactionParent
* HttpTransactionParent::AsHttpTransactionParent() {
386 int32_t HttpTransactionParent::GetProxyConnectResponseCode() {
387 return mProxyConnectResponseCode
;
390 bool HttpTransactionParent::Http2Disabled() const {
391 return mCaps
& NS_HTTP_DISALLOW_SPDY
;
394 bool HttpTransactionParent::Http3Disabled() const {
395 return mCaps
& NS_HTTP_DISALLOW_HTTP3
;
398 already_AddRefed
<nsHttpConnectionInfo
> HttpTransactionParent::GetConnInfo()
400 RefPtr
<nsHttpConnectionInfo
> connInfo
= mConnInfo
->Clone();
401 return connInfo
.forget();
404 already_AddRefed
<nsIEventTarget
> HttpTransactionParent::GetNeckoTarget() {
405 nsCOMPtr
<nsIEventTarget
> target
= GetMainThreadSerialEventTarget();
406 return target
.forget();
409 mozilla::ipc::IPCResult
HttpTransactionParent::RecvOnStartRequest(
410 const nsresult
& aStatus
, const Maybe
<nsHttpResponseHead
>& aResponseHead
,
411 nsITransportSecurityInfo
* aSecurityInfo
, const bool& aProxyConnectFailed
,
412 const TimingStructArgs
& aTimings
, const int32_t& aProxyConnectResponseCode
,
413 nsTArray
<uint8_t>&& aDataForSniffer
, const Maybe
<nsCString
>& aAltSvcUsed
,
414 const bool& aDataToChildProcess
, const bool& aRestarted
,
415 const uint32_t& aHTTPSSVCReceivedStage
, const bool& aSupportsHttp3
,
416 const nsIRequest::TRRMode
& aMode
, const TRRSkippedReason
& aTrrSkipReason
,
417 const uint32_t& aCaps
) {
418 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
420 [self
= UnsafePtr
<HttpTransactionParent
>(this), aStatus
, aResponseHead
,
421 securityInfo
= nsCOMPtr
{aSecurityInfo
}, aProxyConnectFailed
, aTimings
,
422 aProxyConnectResponseCode
,
423 aDataForSniffer
= CopyableTArray
{std::move(aDataForSniffer
)},
424 aAltSvcUsed
, aDataToChildProcess
, aRestarted
, aHTTPSSVCReceivedStage
,
425 aSupportsHttp3
, aMode
, aTrrSkipReason
, aCaps
]() mutable {
426 self
->DoOnStartRequest(
427 aStatus
, aResponseHead
, securityInfo
, aProxyConnectFailed
, aTimings
,
428 aProxyConnectResponseCode
, std::move(aDataForSniffer
), aAltSvcUsed
,
429 aDataToChildProcess
, aRestarted
, aHTTPSSVCReceivedStage
,
430 aSupportsHttp3
, aMode
, aTrrSkipReason
, aCaps
);
435 static void TimingStructArgsToTimingsStruct(const TimingStructArgs
& aArgs
,
436 TimingStruct
& aTimings
) {
437 // If domainLookupStart/End was set by the channel before, we use these
438 // timestamps instead the ones from the transaction.
439 if (aTimings
.domainLookupStart
.IsNull() &&
440 aTimings
.domainLookupEnd
.IsNull()) {
441 aTimings
.domainLookupStart
= aArgs
.domainLookupStart();
442 aTimings
.domainLookupEnd
= aArgs
.domainLookupEnd();
444 aTimings
.connectStart
= aArgs
.connectStart();
445 aTimings
.tcpConnectEnd
= aArgs
.tcpConnectEnd();
446 aTimings
.secureConnectionStart
= aArgs
.secureConnectionStart();
447 aTimings
.connectEnd
= aArgs
.connectEnd();
448 aTimings
.requestStart
= aArgs
.requestStart();
449 aTimings
.responseStart
= aArgs
.responseStart();
450 aTimings
.responseEnd
= aArgs
.responseEnd();
451 aTimings
.transactionPending
= aArgs
.transactionPending();
454 void HttpTransactionParent::DoOnStartRequest(
455 const nsresult
& aStatus
, const Maybe
<nsHttpResponseHead
>& aResponseHead
,
456 nsITransportSecurityInfo
* aSecurityInfo
, const bool& aProxyConnectFailed
,
457 const TimingStructArgs
& aTimings
, const int32_t& aProxyConnectResponseCode
,
458 nsTArray
<uint8_t>&& aDataForSniffer
, const Maybe
<nsCString
>& aAltSvcUsed
,
459 const bool& aDataToChildProcess
, const bool& aRestarted
,
460 const uint32_t& aHTTPSSVCReceivedStage
, const bool& aSupportsHttp3
,
461 const nsIRequest::TRRMode
& aMode
, const TRRSkippedReason
& aSkipReason
,
462 const uint32_t& aCaps
) {
463 LOG(("HttpTransactionParent::DoOnStartRequest [this=%p aStatus=%" PRIx32
465 this, static_cast<uint32_t>(aStatus
)));
471 MOZ_ASSERT(!mOnStartRequestCalled
);
474 mDataSentToChildProcess
= aDataToChildProcess
;
475 mHTTPSSVCReceivedStage
= aHTTPSSVCReceivedStage
;
476 mSupportsHTTP3
= aSupportsHttp3
;
477 mEffectiveTRRMode
= aMode
;
478 mTRRSkipReason
= aSkipReason
;
480 mSecurityInfo
= aSecurityInfo
;
482 if (aResponseHead
.isSome()) {
483 mResponseHead
= MakeUnique
<nsHttpResponseHead
>(aResponseHead
.ref());
485 mProxyConnectFailed
= aProxyConnectFailed
;
486 TimingStructArgsToTimingsStruct(aTimings
, mTimings
);
488 mProxyConnectResponseCode
= aProxyConnectResponseCode
;
489 mDataForSniffer
= std::move(aDataForSniffer
);
490 mRestarted
= aRestarted
;
492 nsCOMPtr
<nsIHttpChannel
> httpChannel
= do_QueryInterface(mChannel
);
493 MOZ_ASSERT(httpChannel
, "mChannel is expected to implement nsIHttpChannel");
495 if (aAltSvcUsed
.isSome()) {
496 Unused
<< httpChannel
->SetRequestHeader(
497 nsHttp::Alternate_Service_Used
.val(), aAltSvcUsed
.ref(), false);
501 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
502 nsresult rv
= mChannel
->OnStartRequest(this);
503 mOnStartRequestCalled
= true;
509 mozilla::ipc::IPCResult
HttpTransactionParent::RecvOnTransportStatus(
510 const nsresult
& aStatus
, const int64_t& aProgress
,
511 const int64_t& aProgressMax
,
512 Maybe
<NetworkAddressArg
>&& aNetworkAddressArg
) {
513 if (aNetworkAddressArg
) {
514 mSelfAddr
= aNetworkAddressArg
->selfAddr();
515 mPeerAddr
= aNetworkAddressArg
->peerAddr();
516 mResolvedByTRR
= aNetworkAddressArg
->resolvedByTRR();
517 mEffectiveTRRMode
= aNetworkAddressArg
->mode();
518 mTRRSkipReason
= aNetworkAddressArg
->trrSkipReason();
519 mEchConfigUsed
= aNetworkAddressArg
->echConfigUsed();
521 mEventsink
->OnTransportStatus(nullptr, aStatus
, aProgress
, aProgressMax
);
525 mozilla::ipc::IPCResult
HttpTransactionParent::RecvOnDataAvailable(
526 const nsCString
& aData
, const uint64_t& aOffset
, const uint32_t& aCount
) {
527 LOG(("HttpTransactionParent::RecvOnDataAvailable [this=%p, aOffset= %" PRIu64
529 this, aOffset
, aCount
));
531 // The final transfer size is updated in OnStopRequest ipc message, but in the
532 // case that the socket process is crashed or something went wrong, we might
533 // not get the OnStopRequest. So, let's update the transfer size here.
534 mTransferSize
+= aCount
;
540 mEventQ
->RunOrEnqueue(new ChannelFunctionEvent(
541 [self
= UnsafePtr
<HttpTransactionParent
>(this)]() {
542 return self
->GetODATarget();
544 [self
= UnsafePtr
<HttpTransactionParent
>(this), aData
, aOffset
,
545 aCount
]() { self
->DoOnDataAvailable(aData
, aOffset
, aCount
); }));
549 void HttpTransactionParent::DoOnDataAvailable(const nsCString
& aData
,
550 const uint64_t& aOffset
,
551 const uint32_t& aCount
) {
552 LOG(("HttpTransactionParent::DoOnDataAvailable [this=%p]\n", this));
557 nsCOMPtr
<nsIInputStream
> stringStream
;
559 NS_NewByteInputStream(getter_AddRefs(stringStream
),
560 Span(aData
.get(), aCount
), NS_ASSIGNMENT_DEPEND
);
563 CancelOnMainThread(rv
);
567 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
568 rv
= mChannel
->OnDataAvailable(this, stringStream
, aOffset
, aCount
);
570 CancelOnMainThread(rv
);
574 // Note: Copied from HttpChannelChild.
575 void HttpTransactionParent::CancelOnMainThread(nsresult aRv
) {
576 LOG(("HttpTransactionParent::CancelOnMainThread [this=%p]", this));
578 if (NS_IsMainThread()) {
584 // Cancel is expected to preempt any other channel events, thus we put this
585 // event in the front of mEventQ to make sure nsIStreamListener not receiving
586 // any ODA/OnStopRequest callbacks.
587 mEventQ
->PrependEvent(MakeUnique
<NeckoTargetChannelFunctionEvent
>(
588 this, [self
= UnsafePtr
<HttpTransactionParent
>(this), aRv
]() {
594 mozilla::ipc::IPCResult
HttpTransactionParent::RecvOnStopRequest(
595 const nsresult
& aStatus
, const bool& aResponseIsComplete
,
596 const int64_t& aTransferSize
, const TimingStructArgs
& aTimings
,
597 const Maybe
<nsHttpHeaderArray
>& aResponseTrailers
,
598 Maybe
<TransactionObserverResult
>&& aTransactionObserverResult
,
599 const TimeStamp
& aLastActiveTabOptHit
,
600 const HttpConnectionInfoCloneArgs
& aArgs
) {
601 LOG(("HttpTransactionParent::RecvOnStopRequest [this=%p status=%" PRIx32
603 this, static_cast<uint32_t>(aStatus
)));
605 nsHttp::SetLastActiveTabLoadOptimizationHit(aLastActiveTabOptHit
);
610 RefPtr
<nsHttpConnectionInfo
> cinfo
=
611 nsHttpConnectionInfo::DeserializeHttpConnectionInfoCloneArgs(aArgs
);
612 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
613 this, [self
= UnsafePtr
<HttpTransactionParent
>(this), aStatus
,
614 aResponseIsComplete
, aTransferSize
, aTimings
, aResponseTrailers
,
615 aTransactionObserverResult
{std::move(aTransactionObserverResult
)},
616 cinfo
{std::move(cinfo
)}]() mutable {
617 self
->DoOnStopRequest(aStatus
, aResponseIsComplete
, aTransferSize
,
618 aTimings
, aResponseTrailers
,
619 std::move(aTransactionObserverResult
), cinfo
);
624 void HttpTransactionParent::DoOnStopRequest(
625 const nsresult
& aStatus
, const bool& aResponseIsComplete
,
626 const int64_t& aTransferSize
, const TimingStructArgs
& aTimings
,
627 const Maybe
<nsHttpHeaderArray
>& aResponseTrailers
,
628 Maybe
<TransactionObserverResult
>&& aTransactionObserverResult
,
629 nsHttpConnectionInfo
* aConnInfo
) {
630 LOG(("HttpTransactionParent::DoOnStopRequest [this=%p]\n", this));
635 MOZ_ASSERT(!mOnStopRequestCalled
, "We should not call OnStopRequest twice");
639 nsCOMPtr
<nsIRequest
> deathGrip
= this;
641 mResponseIsComplete
= aResponseIsComplete
;
642 mTransferSize
= aTransferSize
;
644 TimingStructArgsToTimingsStruct(aTimings
, mTimings
);
646 if (aResponseTrailers
.isSome()) {
647 mResponseTrailers
= MakeUnique
<nsHttpHeaderArray
>(aResponseTrailers
.ref());
649 mConnInfo
= aConnInfo
;
650 if (aTransactionObserverResult
.isSome()) {
651 TransactionObserverFunc obs
= nullptr;
652 std::swap(obs
, mTransactionObserver
);
653 obs(std::move(*aTransactionObserverResult
));
656 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
657 Unused
<< mChannel
->OnStopRequest(this, mStatus
);
658 mOnStopRequestCalled
= true;
661 mozilla::ipc::IPCResult
HttpTransactionParent::RecvOnInitFailed(
662 const nsresult
& aStatus
) {
663 nsCOMPtr
<nsIRequest
> request
= do_QueryInterface(mEventsink
);
665 request
->Cancel(aStatus
);
670 mozilla::ipc::IPCResult
HttpTransactionParent::RecvOnH2PushStream(
671 const uint32_t& aPushedStreamId
, const nsCString
& aResourceUrl
,
672 const nsCString
& aRequestString
) {
673 MOZ_ASSERT(mOnPushCallback
);
675 mOnPushCallback(aPushedStreamId
, aResourceUrl
, aRequestString
, this);
679 mozilla::ipc::IPCResult
HttpTransactionParent::RecvEarlyHint(
680 const nsCString
& aValue
, const nsACString
& aReferrerPolicy
,
681 const nsACString
& aCSPHeader
) {
683 ("HttpTransactionParent::RecvEarlyHint header=%s aReferrerPolicy=%s "
685 PromiseFlatCString(aValue
).get(),
686 PromiseFlatCString(aReferrerPolicy
).get(),
687 PromiseFlatCString(aCSPHeader
).get()));
688 nsCOMPtr
<nsIEarlyHintObserver
> obs
= do_QueryInterface(mChannel
);
690 Unused
<< obs
->EarlyHint(aValue
, aReferrerPolicy
, aCSPHeader
);
696 //-----------------------------------------------------------------------------
697 // HttpTransactionParent <nsIRequest>
698 //-----------------------------------------------------------------------------
701 HttpTransactionParent::GetName(nsACString
& aResult
) {
707 HttpTransactionParent::IsPending(bool* aRetval
) {
713 HttpTransactionParent::GetStatus(nsresult
* aStatus
) {
718 NS_IMETHODIMP
HttpTransactionParent::SetCanceledReason(
719 const nsACString
& aReason
) {
720 return SetCanceledReasonImpl(aReason
);
723 NS_IMETHODIMP
HttpTransactionParent::GetCanceledReason(nsACString
& aReason
) {
724 return GetCanceledReasonImpl(aReason
);
727 NS_IMETHODIMP
HttpTransactionParent::CancelWithReason(
728 nsresult aStatus
, const nsACString
& aReason
) {
729 return CancelWithReasonImpl(aStatus
, aReason
);
733 HttpTransactionParent::Cancel(nsresult aStatus
) {
734 MOZ_ASSERT(NS_IsMainThread());
736 LOG(("HttpTransactionParent::Cancel [this=%p status=%" PRIx32
"]\n", this,
737 static_cast<uint32_t>(aStatus
)));
740 LOG((" already canceled\n"));
744 MOZ_ASSERT(NS_FAILED(aStatus
), "cancel with non-failure status code");
749 Unused
<< SendCancelPump(mStatus
);
752 // Put DoNotifyListener() in front of the queue to avoid OnDataAvailable
753 // being called after cancellation. Note that
754 // HttpTransactionParent::OnStart/StopRequest are driven by IPC messages and
755 // HttpTransactionChild won't send IPC if already canceled. That's why we have
756 // to call DoNotifyListener().
758 mEventQ
->PrependEvent(MakeUnique
<NeckoTargetChannelFunctionEvent
>(
759 this, [self
= UnsafePtr
<HttpTransactionParent
>(this)]() {
760 self
->DoNotifyListener();
766 void HttpTransactionParent::DoNotifyListener() {
767 LOG(("HttpTransactionParent::DoNotifyListener this=%p", this));
768 MOZ_ASSERT(NS_IsMainThread());
770 if (mChannel
&& !mOnStartRequestCalled
) {
771 nsCOMPtr
<nsIStreamListener
> listener
= mChannel
;
772 mOnStartRequestCalled
= true;
773 listener
->OnStartRequest(this);
775 mOnStartRequestCalled
= true;
777 // This is to make sure that ODA in the event queue can be processed before
779 mEventQ
->RunOrEnqueue(new NeckoTargetChannelFunctionEvent(
780 this, [self
= UnsafePtr
<HttpTransactionParent
>(this)] {
781 self
->ContinueDoNotifyListener();
785 void HttpTransactionParent::ContinueDoNotifyListener() {
786 LOG(("HttpTransactionParent::ContinueDoNotifyListener this=%p", this));
787 MOZ_ASSERT(NS_IsMainThread());
789 if (mChannel
&& !mOnStopRequestCalled
) {
790 nsCOMPtr
<nsIStreamListener
> listener
= mChannel
;
791 mOnStopRequestCalled
= true; // avoid reentrancy bugs by setting this now
792 listener
->OnStopRequest(this, mStatus
);
794 mOnStopRequestCalled
= true;
800 HttpTransactionParent::Suspend() {
801 MOZ_ASSERT(NS_IsMainThread());
803 // SendSuspend only once, when suspend goes from 0 to 1.
804 if (!mSuspendCount
++ && CanSend()) {
805 Unused
<< SendSuspendPump();
812 HttpTransactionParent::Resume() {
813 MOZ_ASSERT(NS_IsMainThread());
814 MOZ_ASSERT(mSuspendCount
, "Resume called more than Suspend");
816 // SendResume only once, when suspend count drops to 0.
817 if (mSuspendCount
&& !--mSuspendCount
) {
819 Unused
<< SendResumePump();
823 nsCOMPtr
<nsIEventTarget
> neckoTarget
= GetNeckoTarget();
824 MOZ_ASSERT(neckoTarget
);
826 RefPtr
<HttpTransactionParent
> self
= this;
827 std::function
<void()> callOnResume
= nullptr;
828 std::swap(callOnResume
, mCallOnResume
);
829 neckoTarget
->Dispatch(
830 NS_NewRunnableFunction("net::HttpTransactionParent::mCallOnResume",
831 [callOnResume
]() { callOnResume(); }),
840 HttpTransactionParent::GetLoadGroup(nsILoadGroup
** aLoadGroup
) {
841 MOZ_ASSERT(false, "Should not be called.");
842 return NS_ERROR_NOT_IMPLEMENTED
;
846 HttpTransactionParent::SetLoadGroup(nsILoadGroup
* aLoadGroup
) {
847 MOZ_ASSERT(false, "Should not be called.");
848 return NS_ERROR_NOT_IMPLEMENTED
;
852 HttpTransactionParent::GetLoadFlags(nsLoadFlags
* aLoadFlags
) {
853 MOZ_ASSERT(false, "Should not be called.");
854 return NS_ERROR_NOT_IMPLEMENTED
;
858 HttpTransactionParent::SetLoadFlags(nsLoadFlags aLoadFlags
) {
859 MOZ_ASSERT(false, "Should not be called.");
860 return NS_ERROR_NOT_IMPLEMENTED
;
864 HttpTransactionParent::GetTRRMode(nsIRequest::TRRMode
* aTRRMode
) {
865 MOZ_ASSERT(false, "Should not be called.");
866 return NS_ERROR_NOT_IMPLEMENTED
;
870 HttpTransactionParent::SetTRRMode(nsIRequest::TRRMode aTRRMode
) {
871 MOZ_ASSERT(false, "Should not be called.");
872 return NS_ERROR_NOT_IMPLEMENTED
;
875 void HttpTransactionParent::ActorDestroy(ActorDestroyReason aWhy
) {
876 LOG(("HttpTransactionParent::ActorDestroy [this=%p]\n", this));
877 if (aWhy
!= Deletion
) {
878 // Make sure all the messages are processed.
879 AutoEventEnqueuer
ensureSerialDispatch(mEventQ
);
881 mStatus
= NS_ERROR_FAILURE
;
888 void HttpTransactionParent::HandleAsyncAbort() {
889 MOZ_ASSERT(!mCallOnResume
, "How did that happen?");
893 ("HttpTransactionParent Waiting until resume to do async notification "
896 RefPtr
<HttpTransactionParent
> self
= this;
897 mCallOnResume
= [self
]() { self
->HandleAsyncAbort(); };
904 bool HttpTransactionParent::GetSupportsHTTP3() { return mSupportsHTTP3
; }
906 void HttpTransactionParent::SetIsForWebTransport(bool SetIsForWebTransport
) {
910 mozilla::TimeStamp
HttpTransactionParent::GetPendingTime() {
911 return mTimings
.transactionPending
;
914 } // namespace mozilla::net