HttpTransactionParent.cpp (30924B)
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 "HttpTransactionParent.h" 11 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" 25 #include "nsIRequestContext.h" 26 27 namespace mozilla::net { 28 29 NS_IMPL_ADDREF(HttpTransactionParent) 30 NS_INTERFACE_MAP_BEGIN(HttpTransactionParent) 31 NS_INTERFACE_MAP_ENTRY(nsIRequest) 32 NS_INTERFACE_MAP_ENTRY(nsIThreadRetargetableRequest) 33 NS_INTERFACE_MAP_ENTRY_CONCRETE(HttpTransactionParent) 34 NS_INTERFACE_MAP_ENTRY_AMBIGUOUS(nsISupports, nsIRequest) 35 NS_INTERFACE_MAP_END 36 37 NS_IMETHODIMP_(MozExternalRefCountType) HttpTransactionParent::Release(void) { 38 MOZ_ASSERT(int32_t(mRefCnt) > 0, "dup release"); 39 nsrefcnt count = --mRefCnt; 40 NS_LOG_RELEASE(this, count, "HttpTransactionParent"); 41 if (count == 0) { 42 mRefCnt = 1; /* stabilize */ 43 delete (this); 44 return 0; 45 } 46 47 // When ref count goes down to 1 (held internally by IPDL), it means that 48 // we are done with this transaction. We should send a delete message 49 // to delete the transaction child in socket process. 50 if (count == 1 && CanSend()) { 51 if (!NS_IsMainThread()) { 52 RefPtr<HttpTransactionParent> self = this; 53 MOZ_ALWAYS_SUCCEEDS(NS_DispatchToMainThread( 54 NS_NewRunnableFunction("HttpTransactionParent::Release", [self]() { 55 (void)self->Send__delete__(self); 56 // Make sure we can not send IPC after Send__delete__(). 57 MOZ_ASSERT(!self->CanSend()); 58 }))); 59 } else { 60 (void)Send__delete__(this); 61 } 62 return 1; 63 } 64 return count; 65 } 66 67 //----------------------------------------------------------------------------- 68 // HttpTransactionParent <public> 69 //----------------------------------------------------------------------------- 70 71 HttpTransactionParent::HttpTransactionParent(bool aIsDocumentLoad) 72 : mIsDocumentLoad(aIsDocumentLoad) { 73 LOG(("Creating HttpTransactionParent @%p\n", this)); 74 mEventQ = new ChannelEventQueue(static_cast<nsIRequest*>(this)); 75 } 76 77 HttpTransactionParent::~HttpTransactionParent() { 78 LOG(("Destroying HttpTransactionParent @%p\n", this)); 79 mEventQ->NotifyReleasingOwner(); 80 } 81 82 //----------------------------------------------------------------------------- 83 // HttpTransactionParent <nsAHttpTransactionShell> 84 //----------------------------------------------------------------------------- 85 86 // Let socket process init the *real* nsHttpTransaction. 87 nsresult HttpTransactionParent::Init( 88 uint32_t caps, nsHttpConnectionInfo* cinfo, nsHttpRequestHead* requestHead, 89 nsIInputStream* requestBody, uint64_t requestContentLength, 90 bool requestBodyHasHeaders, nsIEventTarget* target, 91 nsIInterfaceRequestor* callbacks, nsITransportEventSink* eventsink, 92 uint64_t browserId, HttpTrafficCategory trafficCategory, 93 nsIRequestContext* requestContext, ClassOfService classOfService, 94 uint32_t initialRwin, bool responseTimeoutEnabled, uint64_t channelId, 95 TransactionObserverFunc&& transactionObserver, 96 nsILoadInfo::IPAddressSpace aParentIpAddressSpace, 97 const LNAPerms& aLnaPermissionStatus) { 98 LOG(("HttpTransactionParent::Init [this=%p caps=%x]\n", this, caps)); 99 100 if (!CanSend()) { 101 return NS_ERROR_FAILURE; 102 } 103 104 mEventsink = eventsink; 105 mTargetThread = GetCurrentSerialEventTarget(); 106 mChannelId = channelId; 107 mTransactionObserver = std::move(transactionObserver); 108 mCaps = caps; 109 mConnInfo = cinfo->Clone(); 110 mIsHttp3Used = cinfo->IsHttp3(); 111 112 HttpConnectionInfoCloneArgs infoArgs; 113 nsHttpConnectionInfo::SerializeHttpConnectionInfo(cinfo, infoArgs); 114 115 Maybe<mozilla::ipc::IPCStream> ipcStream; 116 if (!mozilla::ipc::SerializeIPCStream(do_AddRef(requestBody), ipcStream, 117 /* aAllowLazy */ false)) { 118 return NS_ERROR_FAILURE; 119 } 120 121 uint64_t requestContextID = requestContext ? requestContext->GetID() : 0; 122 123 nsCOMPtr<nsIThrottledInputChannel> throttled = do_QueryInterface(mEventsink); 124 Maybe<NotNull<PInputChannelThrottleQueueParent*>> throttleQueue; 125 if (throttled) { 126 nsCOMPtr<nsIInputChannelThrottleQueue> queue; 127 nsresult rv = throttled->GetThrottleQueue(getter_AddRefs(queue)); 128 // In case of failure, just carry on without throttling. 129 if (NS_SUCCEEDED(rv) && queue) { 130 LOG1(("HttpTransactionParent::Init %p using throttle queue %p\n", this, 131 queue.get())); 132 RefPtr<InputChannelThrottleQueueParent> tqParent = do_QueryObject(queue); 133 MOZ_ASSERT(tqParent); 134 throttleQueue.emplace(WrapNotNull(tqParent.get())); 135 } 136 } 137 138 // TODO: Figure out if we have to implement nsIThreadRetargetableRequest in 139 // bug 1544378. 140 if (!SendInit(caps, infoArgs, *requestHead, ipcStream, requestContentLength, 141 requestBodyHasHeaders, browserId, 142 static_cast<uint8_t>(trafficCategory), requestContextID, 143 classOfService, initialRwin, responseTimeoutEnabled, mChannelId, 144 !!mTransactionObserver, throttleQueue, mIsDocumentLoad, 145 aParentIpAddressSpace, aLnaPermissionStatus, mRedirectStart, 146 mRedirectEnd)) { 147 return NS_ERROR_FAILURE; 148 } 149 150 nsCString reqHeaderBuf = nsHttp::ConvertRequestHeadToString( 151 *requestHead, !!requestBody, requestBodyHasHeaders, 152 cinfo->UsingConnect()); 153 requestContentLength += reqHeaderBuf.Length(); 154 155 mRequestSize = InScriptableRange(requestContentLength) 156 ? static_cast<int64_t>(requestContentLength) 157 : -1; 158 159 return NS_OK; 160 } 161 162 nsresult HttpTransactionParent::AsyncRead(nsIStreamListener* listener, 163 nsIRequest** pump) { 164 MOZ_ASSERT(pump); 165 166 *pump = do_AddRef(this).take(); 167 mChannel = listener; 168 return NS_OK; 169 } 170 171 UniquePtr<nsHttpResponseHead> 172 HttpTransactionParent::TakeResponseHeadAndConnInfo( 173 nsHttpConnectionInfo** aOut) { 174 MOZ_ASSERT(NS_IsMainThread()); 175 MOZ_ASSERT(!mResponseHeadTaken, "TakeResponseHead called 2x"); 176 177 if (aOut) { 178 RefPtr<nsHttpConnectionInfo> connInfo = mConnInfo; 179 connInfo.forget(aOut); 180 } 181 182 mResponseHeadTaken = true; 183 return std::move(mResponseHead); 184 } 185 186 UniquePtr<nsHttpHeaderArray> HttpTransactionParent::TakeResponseTrailers() { 187 MOZ_ASSERT(NS_IsMainThread()); 188 MOZ_ASSERT(!mResponseTrailersTaken, "TakeResponseTrailers called 2x"); 189 190 mResponseTrailersTaken = true; 191 return std::move(mResponseTrailers); 192 } 193 194 void HttpTransactionParent::SetSniffedTypeToChannel( 195 nsInputStreamPump::PeekSegmentFun aCallTypeSniffers, nsIChannel* aChannel) { 196 if (!mDataForSniffer.IsEmpty()) { 197 aCallTypeSniffers(aChannel, mDataForSniffer.Elements(), 198 mDataForSniffer.Length()); 199 } 200 } 201 202 NS_IMETHODIMP 203 HttpTransactionParent::GetDeliveryTarget(nsISerialEventTarget** aEventTarget) { 204 MutexAutoLock lock(mEventTargetMutex); 205 206 nsCOMPtr<nsISerialEventTarget> target = mODATarget; 207 if (!mODATarget) { 208 target = mTargetThread; 209 } 210 target.forget(aEventTarget); 211 return NS_OK; 212 } 213 214 already_AddRefed<nsISerialEventTarget> HttpTransactionParent::GetODATarget() { 215 nsCOMPtr<nsISerialEventTarget> target; 216 { 217 MutexAutoLock lock(mEventTargetMutex); 218 target = mODATarget ? mODATarget : mTargetThread; 219 } 220 221 if (!target) { 222 target = GetMainThreadSerialEventTarget(); 223 } 224 return target.forget(); 225 } 226 227 NS_IMETHODIMP HttpTransactionParent::RetargetDeliveryTo( 228 nsISerialEventTarget* aEventTarget) { 229 LOG(("HttpTransactionParent::RetargetDeliveryTo [this=%p, aTarget=%p]", this, 230 aEventTarget)); 231 232 MOZ_ASSERT(NS_IsMainThread(), "Should be called on main thread only"); 233 MOZ_ASSERT(!mODATarget); 234 NS_ENSURE_ARG(aEventTarget); 235 236 if (aEventTarget->IsOnCurrentThread()) { 237 NS_WARNING("Retargeting delivery to same thread"); 238 return NS_OK; 239 } 240 241 nsresult rv = NS_OK; 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; 247 } 248 249 rv = retargetableListener->CheckListenerChain(); 250 if (NS_FAILED(rv)) { 251 NS_WARNING("Subsequent listeners are not retargetable"); 252 return rv; 253 } 254 255 { 256 MutexAutoLock lock(mEventTargetMutex); 257 mODATarget = aEventTarget; 258 } 259 260 return NS_OK; 261 } 262 263 void HttpTransactionParent::SetDNSWasRefreshed() { 264 MOZ_ASSERT(NS_IsMainThread(), "SetDNSWasRefreshed on main thread only!"); 265 (void)SendSetDNSWasRefreshed(); 266 } 267 268 void HttpTransactionParent::GetNetworkAddresses( 269 NetAddr& self, NetAddr& peer, bool& aResolvedByTRR, 270 nsIRequest::TRRMode& aEffectiveTRRMode, TRRSkippedReason& aSkipReason, 271 bool& aEchConfigUsed) { 272 self = mSelfAddr; 273 peer = mPeerAddr; 274 aResolvedByTRR = mResolvedByTRR; 275 aEffectiveTRRMode = mEffectiveTRRMode; 276 aSkipReason = mTRRSkipReason; 277 aEchConfigUsed = mEchConfigUsed; 278 } 279 280 nsILoadInfo::IPAddressSpace HttpTransactionParent::GetTargetIPAddressSpace() { 281 return mTargetIPAddressSpace; 282 } 283 284 bool HttpTransactionParent::HasStickyConnection() const { 285 return mCaps & NS_HTTP_STICKY_CONNECTION; 286 } 287 288 mozilla::TimeStamp HttpTransactionParent::GetDomainLookupStart() { 289 return mTimings.domainLookupStart; 290 } 291 292 mozilla::TimeStamp HttpTransactionParent::GetDomainLookupEnd() { 293 return mTimings.domainLookupEnd; 294 } 295 296 mozilla::TimeStamp HttpTransactionParent::GetConnectStart() { 297 return mTimings.connectStart; 298 } 299 300 mozilla::TimeStamp HttpTransactionParent::GetTcpConnectEnd() { 301 return mTimings.tcpConnectEnd; 302 } 303 304 mozilla::TimeStamp HttpTransactionParent::GetSecureConnectionStart() { 305 return mTimings.secureConnectionStart; 306 } 307 308 mozilla::TimeStamp HttpTransactionParent::GetConnectEnd() { 309 return mTimings.connectEnd; 310 } 311 312 mozilla::TimeStamp HttpTransactionParent::GetRequestStart() { 313 return mTimings.requestStart; 314 } 315 316 mozilla::TimeStamp HttpTransactionParent::GetResponseStart() { 317 return mTimings.responseStart; 318 } 319 320 mozilla::TimeStamp HttpTransactionParent::GetResponseEnd() { 321 return mTimings.responseEnd; 322 } 323 324 TimingStruct HttpTransactionParent::Timings() { return mTimings; } 325 326 bool HttpTransactionParent::ResponseIsComplete() { return mResponseIsComplete; } 327 328 int64_t HttpTransactionParent::GetTransferSize() { return mTransferSize; } 329 330 int64_t HttpTransactionParent::GetRequestSize() { return mRequestSize; } 331 332 bool HttpTransactionParent::IsHttp3Used() { return mIsHttp3Used; } 333 334 bool HttpTransactionParent::DataSentToChildProcess() { 335 return mDataSentToChildProcess; 336 } 337 338 already_AddRefed<nsITransportSecurityInfo> 339 HttpTransactionParent::SecurityInfo() { 340 return do_AddRef(mSecurityInfo); 341 } 342 343 bool HttpTransactionParent::ProxyConnectFailed() { return mProxyConnectFailed; } 344 345 bool HttpTransactionParent::TakeRestartedState() { 346 bool result = mRestarted; 347 mRestarted = false; 348 return result; 349 } 350 351 uint32_t HttpTransactionParent::HTTPSSVCReceivedStage() { 352 return mHTTPSSVCReceivedStage; 353 } 354 355 void HttpTransactionParent::DontReuseConnection() { 356 MOZ_ASSERT(NS_IsMainThread()); 357 (void)SendDontReuseConnection(); 358 } 359 360 void HttpTransactionParent::SetH2WSConnRefTaken() { 361 MOZ_ASSERT(NS_IsMainThread()); 362 (void)SendSetH2WSConnRefTaken(); 363 } 364 365 void HttpTransactionParent::SetSecurityCallbacks( 366 nsIInterfaceRequestor* aCallbacks) { 367 // TODO: we might don't need to implement this. 368 // Will figure out in bug 1512479. 369 } 370 371 void HttpTransactionParent::SetDomainLookupStart(mozilla::TimeStamp timeStamp, 372 bool onlyIfNull) { 373 mDomainLookupStart = timeStamp; 374 mTimings.domainLookupStart = mDomainLookupStart; 375 } 376 void HttpTransactionParent::SetDomainLookupEnd(mozilla::TimeStamp timeStamp, 377 bool onlyIfNull) { 378 mDomainLookupEnd = timeStamp; 379 mTimings.domainLookupEnd = mDomainLookupEnd; 380 } 381 382 nsHttpTransaction* HttpTransactionParent::AsHttpTransaction() { 383 return nullptr; 384 } 385 386 HttpTransactionParent* HttpTransactionParent::AsHttpTransactionParent() { 387 return this; 388 } 389 390 int32_t HttpTransactionParent::GetProxyConnectResponseCode() { 391 return mProxyConnectResponseCode; 392 } 393 394 bool HttpTransactionParent::Http2Disabled() const { 395 return mCaps & NS_HTTP_DISALLOW_SPDY; 396 } 397 398 bool HttpTransactionParent::Http3Disabled() const { 399 return mCaps & NS_HTTP_DISALLOW_HTTP3; 400 } 401 402 already_AddRefed<nsHttpConnectionInfo> HttpTransactionParent::GetConnInfo() 403 const { 404 RefPtr<nsHttpConnectionInfo> connInfo = mConnInfo->Clone(); 405 return connInfo.forget(); 406 } 407 408 already_AddRefed<nsIEventTarget> HttpTransactionParent::GetNeckoTarget() { 409 nsCOMPtr<nsIEventTarget> target = GetMainThreadSerialEventTarget(); 410 return target.forget(); 411 } 412 413 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnStartRequest( 414 const nsresult& aStatus, Maybe<nsHttpResponseHead>&& aResponseHead, 415 nsITransportSecurityInfo* aSecurityInfo, const bool& aProxyConnectFailed, 416 const TimingStructArgs& aTimings, const int32_t& aProxyConnectResponseCode, 417 nsTArray<uint8_t>&& aDataForSniffer, const Maybe<nsCString>& aAltSvcUsed, 418 const bool& aDataToChildProcess, const bool& aRestarted, 419 const uint32_t& aHTTPSSVCReceivedStage, const bool& aSupportsHttp3, 420 const nsIRequest::TRRMode& aMode, const TRRSkippedReason& aTrrSkipReason, 421 const uint32_t& aCaps, const TimeStamp& aOnStartRequestStartTime, 422 const HttpConnectionInfoCloneArgs& aArgs, 423 const nsILoadInfo::IPAddressSpace& aTargetIPAddressSpace) { 424 RefPtr<nsHttpConnectionInfo> cinfo = 425 nsHttpConnectionInfo::DeserializeHttpConnectionInfoCloneArgs(aArgs); 426 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 427 this, 428 [self = UnsafePtr<HttpTransactionParent>(this), aStatus, 429 aResponseHead = std::move(aResponseHead), 430 securityInfo = nsCOMPtr{aSecurityInfo}, aProxyConnectFailed, aTimings, 431 aProxyConnectResponseCode, 432 aDataForSniffer = CopyableTArray{std::move(aDataForSniffer)}, 433 aAltSvcUsed, aDataToChildProcess, aRestarted, aHTTPSSVCReceivedStage, 434 aSupportsHttp3, aMode, aTrrSkipReason, aCaps, aOnStartRequestStartTime, 435 aTargetIPAddressSpace, cinfo{std::move(cinfo)}]() mutable { 436 self->DoOnStartRequest( 437 aStatus, std::move(aResponseHead), securityInfo, 438 aProxyConnectFailed, aTimings, aProxyConnectResponseCode, 439 std::move(aDataForSniffer), aAltSvcUsed, aDataToChildProcess, 440 aRestarted, aHTTPSSVCReceivedStage, aSupportsHttp3, aMode, 441 aTrrSkipReason, aCaps, aOnStartRequestStartTime, cinfo, 442 aTargetIPAddressSpace); 443 })); 444 return IPC_OK(); 445 } 446 447 static void TimingStructArgsToTimingsStruct(const TimingStructArgs& aArgs, 448 TimingStruct& aTimings) { 449 // If domainLookupStart/End was set by the channel before, we use these 450 // timestamps instead the ones from the transaction. 451 if (aTimings.domainLookupStart.IsNull() && 452 aTimings.domainLookupEnd.IsNull()) { 453 aTimings.domainLookupStart = aArgs.domainLookupStart(); 454 aTimings.domainLookupEnd = aArgs.domainLookupEnd(); 455 } 456 aTimings.connectStart = aArgs.connectStart(); 457 aTimings.tcpConnectEnd = aArgs.tcpConnectEnd(); 458 aTimings.secureConnectionStart = aArgs.secureConnectionStart(); 459 aTimings.connectEnd = aArgs.connectEnd(); 460 aTimings.requestStart = aArgs.requestStart(); 461 aTimings.responseStart = aArgs.responseStart(); 462 aTimings.responseEnd = aArgs.responseEnd(); 463 aTimings.transactionPending = aArgs.transactionPending(); 464 } 465 466 void HttpTransactionParent::DoOnStartRequest( 467 const nsresult& aStatus, Maybe<nsHttpResponseHead>&& aResponseHead, 468 nsITransportSecurityInfo* aSecurityInfo, const bool& aProxyConnectFailed, 469 const TimingStructArgs& aTimings, const int32_t& aProxyConnectResponseCode, 470 nsTArray<uint8_t>&& aDataForSniffer, const Maybe<nsCString>& aAltSvcUsed, 471 const bool& aDataToChildProcess, const bool& aRestarted, 472 const uint32_t& aHTTPSSVCReceivedStage, const bool& aSupportsHttp3, 473 const nsIRequest::TRRMode& aMode, const TRRSkippedReason& aSkipReason, 474 const uint32_t& aCaps, const TimeStamp& aOnStartRequestStartTime, 475 nsHttpConnectionInfo* aConnInfo, 476 const nsILoadInfo::IPAddressSpace& aTargetIPAddressSpace) { 477 LOG(("HttpTransactionParent::DoOnStartRequest [this=%p aStatus=%" PRIx32 478 "]\n", 479 this, static_cast<uint32_t>(aStatus))); 480 481 if (mCanceled) { 482 return; 483 } 484 485 MOZ_ASSERT(!mOnStartRequestCalled); 486 487 mStatus = aStatus; 488 mDataSentToChildProcess = aDataToChildProcess; 489 mHTTPSSVCReceivedStage = aHTTPSSVCReceivedStage; 490 mSupportsHTTP3 = aSupportsHttp3; 491 mEffectiveTRRMode = aMode; 492 mTRRSkipReason = aSkipReason; 493 mCaps = aCaps; 494 mSecurityInfo = aSecurityInfo; 495 mOnStartRequestStartTime = aOnStartRequestStartTime; 496 mConnInfo = aConnInfo; 497 mTargetIPAddressSpace = aTargetIPAddressSpace; 498 499 if (aResponseHead.isSome()) { 500 mResponseHead = 501 MakeUnique<nsHttpResponseHead>(std::move(aResponseHead.ref())); 502 } 503 mProxyConnectFailed = aProxyConnectFailed; 504 TimingStructArgsToTimingsStruct(aTimings, mTimings); 505 506 mProxyConnectResponseCode = aProxyConnectResponseCode; 507 mDataForSniffer = std::move(aDataForSniffer); 508 mRestarted = aRestarted; 509 510 nsCOMPtr<nsIHttpChannel> httpChannel = do_QueryInterface(mChannel); 511 MOZ_ASSERT(httpChannel, "mChannel is expected to implement nsIHttpChannel"); 512 if (httpChannel) { 513 if (aAltSvcUsed.isSome()) { 514 (void)httpChannel->SetRequestHeader(nsHttp::Alternate_Service_Used.val(), 515 aAltSvcUsed.ref(), false); 516 } 517 } 518 519 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 520 nsresult rv = mChannel->OnStartRequest(this); 521 mOnStartRequestCalled = true; 522 if (NS_FAILED(rv)) { 523 Cancel(rv); 524 } 525 } 526 527 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnTransportStatus( 528 const nsresult& aStatus, const int64_t& aProgress, 529 const int64_t& aProgressMax, 530 Maybe<NetworkAddressArg>&& aNetworkAddressArg) { 531 if (aNetworkAddressArg) { 532 mSelfAddr = aNetworkAddressArg->selfAddr(); 533 mPeerAddr = aNetworkAddressArg->peerAddr(); 534 mResolvedByTRR = aNetworkAddressArg->resolvedByTRR(); 535 mEffectiveTRRMode = aNetworkAddressArg->mode(); 536 mTRRSkipReason = aNetworkAddressArg->trrSkipReason(); 537 mEchConfigUsed = aNetworkAddressArg->echConfigUsed(); 538 } 539 mEventsink->OnTransportStatus(nullptr, aStatus, aProgress, aProgressMax); 540 return IPC_OK(); 541 } 542 543 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnDataAvailable( 544 const nsCString& aData, const uint64_t& aOffset, const uint32_t& aCount, 545 const TimeStamp& aOnDataAvailableStartTime) { 546 LOG(("HttpTransactionParent::RecvOnDataAvailable [this=%p, aOffset= %" PRIu64 547 " aCount=%" PRIu32, 548 this, aOffset, aCount)); 549 550 // The final transfer size is updated in OnStopRequest ipc message, but in the 551 // case that the socket process is crashed or something went wrong, we might 552 // not get the OnStopRequest. So, let's update the transfer size here. 553 mTransferSize += aCount; 554 555 if (mCanceled) { 556 return IPC_OK(); 557 } 558 559 mEventQ->RunOrEnqueue(new ChannelFunctionEvent( 560 [self = UnsafePtr<HttpTransactionParent>(this)]() { 561 return self->GetODATarget(); 562 }, 563 [self = UnsafePtr<HttpTransactionParent>(this), aData, aOffset, aCount, 564 aOnDataAvailableStartTime]() { 565 self->DoOnDataAvailable(aData, aOffset, aCount, 566 aOnDataAvailableStartTime); 567 })); 568 return IPC_OK(); 569 } 570 571 void HttpTransactionParent::DoOnDataAvailable( 572 const nsCString& aData, const uint64_t& aOffset, const uint32_t& aCount, 573 const TimeStamp& aOnDataAvailableStartTime) { 574 LOG(("HttpTransactionParent::DoOnDataAvailable [this=%p]\n", this)); 575 if (mCanceled) { 576 return; 577 } 578 579 nsCOMPtr<nsIInputStream> stringStream; 580 nsresult rv = 581 NS_NewByteInputStream(getter_AddRefs(stringStream), 582 Span(aData.get(), aCount), NS_ASSIGNMENT_DEPEND); 583 584 if (NS_FAILED(rv)) { 585 CancelOnMainThread(rv); 586 return; 587 } 588 589 mOnDataAvailableStartTime = aOnDataAvailableStartTime; 590 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 591 rv = mChannel->OnDataAvailable(this, stringStream, aOffset, aCount); 592 if (NS_FAILED(rv)) { 593 CancelOnMainThread(rv); 594 } 595 } 596 597 // Note: Copied from HttpChannelChild. 598 void HttpTransactionParent::CancelOnMainThread(nsresult aRv) { 599 LOG(("HttpTransactionParent::CancelOnMainThread [this=%p]", this)); 600 601 if (NS_IsMainThread()) { 602 Cancel(aRv); 603 return; 604 } 605 606 mEventQ->Suspend(); 607 // Cancel is expected to preempt any other channel events, thus we put this 608 // event in the front of mEventQ to make sure nsIStreamListener not receiving 609 // any ODA/OnStopRequest callbacks. 610 mEventQ->PrependEvent(MakeUnique<NeckoTargetChannelFunctionEvent>( 611 this, [self = UnsafePtr<HttpTransactionParent>(this), aRv]() { 612 self->Cancel(aRv); 613 })); 614 mEventQ->Resume(); 615 } 616 617 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnStopRequest( 618 const nsresult& aStatus, const bool& aResponseIsComplete, 619 const int64_t& aTransferSize, const TimingStructArgs& aTimings, 620 const Maybe<nsHttpHeaderArray>& aResponseTrailers, 621 Maybe<TransactionObserverResult>&& aTransactionObserverResult, 622 const TimeStamp& aLastActiveTabOptHit, 623 const TimeStamp& aOnStopRequestStartTime) { 624 LOG(("HttpTransactionParent::RecvOnStopRequest [this=%p status=%" PRIx32 625 "]\n", 626 this, static_cast<uint32_t>(aStatus))); 627 628 nsHttp::SetLastActiveTabLoadOptimizationHit(aLastActiveTabOptHit); 629 630 if (mCanceled) { 631 return IPC_OK(); 632 } 633 634 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 635 this, [self = UnsafePtr<HttpTransactionParent>(this), aStatus, 636 aResponseIsComplete, aTransferSize, aTimings, aResponseTrailers, 637 aTransactionObserverResult{std::move(aTransactionObserverResult)}, 638 aOnStopRequestStartTime]() mutable { 639 self->DoOnStopRequest(aStatus, aResponseIsComplete, aTransferSize, 640 aTimings, aResponseTrailers, 641 std::move(aTransactionObserverResult), 642 aOnStopRequestStartTime); 643 })); 644 return IPC_OK(); 645 } 646 647 void HttpTransactionParent::DoOnStopRequest( 648 const nsresult& aStatus, const bool& aResponseIsComplete, 649 const int64_t& aTransferSize, const TimingStructArgs& aTimings, 650 const Maybe<nsHttpHeaderArray>& aResponseTrailers, 651 Maybe<TransactionObserverResult>&& aTransactionObserverResult, 652 const TimeStamp& aOnStopRequestStartTime) { 653 LOG(("HttpTransactionParent::DoOnStopRequest [this=%p]\n", this)); 654 if (mCanceled) { 655 return; 656 } 657 658 MOZ_ASSERT(!mOnStopRequestCalled, "We should not call OnStopRequest twice"); 659 660 mStatus = aStatus; 661 662 nsCOMPtr<nsIRequest> deathGrip = this; 663 664 mResponseIsComplete = aResponseIsComplete; 665 mTransferSize = aTransferSize; 666 mOnStopRequestStartTime = aOnStopRequestStartTime; 667 668 TimingStructArgsToTimingsStruct(aTimings, mTimings); 669 670 if (aResponseTrailers.isSome()) { 671 mResponseTrailers = MakeUnique<nsHttpHeaderArray>(aResponseTrailers.ref()); 672 } 673 674 if (aTransactionObserverResult.isSome()) { 675 TransactionObserverFunc obs = nullptr; 676 std::swap(obs, mTransactionObserver); 677 obs(std::move(*aTransactionObserverResult)); 678 } 679 680 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 681 (void)mChannel->OnStopRequest(this, mStatus); 682 mOnStopRequestCalled = true; 683 } 684 685 mozilla::ipc::IPCResult HttpTransactionParent::RecvOnInitFailed( 686 const nsresult& aStatus) { 687 nsCOMPtr<nsIRequest> request = do_QueryInterface(mEventsink); 688 if (request) { 689 request->Cancel(aStatus); 690 } 691 return IPC_OK(); 692 } 693 694 mozilla::ipc::IPCResult HttpTransactionParent::RecvEarlyHint( 695 const nsCString& aValue, const nsACString& aReferrerPolicy, 696 const nsACString& aCSPHeader) { 697 LOG( 698 ("HttpTransactionParent::RecvEarlyHint header=%s aReferrerPolicy=%s " 699 "aCSPHeader=%s", 700 PromiseFlatCString(aValue).get(), 701 PromiseFlatCString(aReferrerPolicy).get(), 702 PromiseFlatCString(aCSPHeader).get())); 703 nsCOMPtr<nsIEarlyHintObserver> obs = do_QueryInterface(mChannel); 704 if (obs) { 705 (void)obs->EarlyHint(aValue, aReferrerPolicy, aCSPHeader); 706 } 707 708 return IPC_OK(); 709 } 710 711 //----------------------------------------------------------------------------- 712 // HttpTransactionParent <nsIRequest> 713 //----------------------------------------------------------------------------- 714 715 NS_IMETHODIMP 716 HttpTransactionParent::GetName(nsACString& aResult) { 717 aResult.Truncate(); 718 return NS_OK; 719 } 720 721 NS_IMETHODIMP 722 HttpTransactionParent::IsPending(bool* aRetval) { 723 *aRetval = false; 724 return NS_OK; 725 } 726 727 NS_IMETHODIMP 728 HttpTransactionParent::GetStatus(nsresult* aStatus) { 729 *aStatus = mStatus; 730 return NS_OK; 731 } 732 733 NS_IMETHODIMP HttpTransactionParent::SetCanceledReason( 734 const nsACString& aReason) { 735 return SetCanceledReasonImpl(aReason); 736 } 737 738 NS_IMETHODIMP HttpTransactionParent::GetCanceledReason(nsACString& aReason) { 739 return GetCanceledReasonImpl(aReason); 740 } 741 742 NS_IMETHODIMP HttpTransactionParent::CancelWithReason( 743 nsresult aStatus, const nsACString& aReason) { 744 return CancelWithReasonImpl(aStatus, aReason); 745 } 746 747 NS_IMETHODIMP 748 HttpTransactionParent::Cancel(nsresult aStatus) { 749 MOZ_ASSERT(NS_IsMainThread()); 750 751 LOG(("HttpTransactionParent::Cancel [this=%p status=%" PRIx32 "]\n", this, 752 static_cast<uint32_t>(aStatus))); 753 754 if (mCanceled) { 755 LOG((" already canceled\n")); 756 return NS_OK; 757 } 758 759 MOZ_ASSERT(NS_FAILED(aStatus), "cancel with non-failure status code"); 760 761 mCanceled = true; 762 mStatus = aStatus; 763 if (CanSend()) { 764 (void)SendCancelPump(mStatus); 765 } 766 767 // Put DoNotifyListener() in front of the queue to avoid OnDataAvailable 768 // being called after cancellation. Note that 769 // HttpTransactionParent::OnStart/StopRequest are driven by IPC messages and 770 // HttpTransactionChild won't send IPC if already canceled. That's why we have 771 // to call DoNotifyListener(). 772 mEventQ->Suspend(); 773 mEventQ->PrependEvent(MakeUnique<NeckoTargetChannelFunctionEvent>( 774 this, [self = UnsafePtr<HttpTransactionParent>(this)]() { 775 self->DoNotifyListener(); 776 })); 777 mEventQ->Resume(); 778 return NS_OK; 779 } 780 781 void HttpTransactionParent::DoNotifyListener() { 782 LOG(("HttpTransactionParent::DoNotifyListener this=%p", this)); 783 MOZ_ASSERT(NS_IsMainThread()); 784 785 if (mChannel && !mOnStartRequestCalled) { 786 nsCOMPtr<nsIStreamListener> listener = mChannel; 787 mOnStartRequestCalled = true; 788 listener->OnStartRequest(this); 789 } 790 mOnStartRequestCalled = true; 791 792 // This is to make sure that ODA in the event queue can be processed before 793 // OnStopRequest. 794 mEventQ->RunOrEnqueue(new NeckoTargetChannelFunctionEvent( 795 this, [self = UnsafePtr<HttpTransactionParent>(this)] { 796 self->ContinueDoNotifyListener(); 797 })); 798 } 799 800 void HttpTransactionParent::ContinueDoNotifyListener() { 801 LOG(("HttpTransactionParent::ContinueDoNotifyListener this=%p", this)); 802 MOZ_ASSERT(NS_IsMainThread()); 803 804 if (mChannel && !mOnStopRequestCalled) { 805 nsCOMPtr<nsIStreamListener> listener = mChannel; 806 mOnStopRequestCalled = true; // avoid reentrancy bugs by setting this now 807 listener->OnStopRequest(this, mStatus); 808 } 809 mOnStopRequestCalled = true; 810 811 mChannel = nullptr; 812 } 813 814 NS_IMETHODIMP 815 HttpTransactionParent::Suspend() { 816 MOZ_ASSERT(NS_IsMainThread()); 817 818 // SendSuspend only once, when suspend goes from 0 to 1. 819 if (!mSuspendCount++ && CanSend()) { 820 (void)SendSuspendPump(); 821 } 822 mEventQ->Suspend(); 823 return NS_OK; 824 } 825 826 NS_IMETHODIMP 827 HttpTransactionParent::Resume() { 828 MOZ_ASSERT(NS_IsMainThread()); 829 MOZ_ASSERT(mSuspendCount, "Resume called more than Suspend"); 830 831 // SendResume only once, when suspend count drops to 0. 832 if (mSuspendCount && !--mSuspendCount) { 833 if (CanSend()) { 834 (void)SendResumePump(); 835 } 836 837 if (mCallOnResume) { 838 nsCOMPtr<nsIEventTarget> neckoTarget = GetNeckoTarget(); 839 MOZ_ASSERT(neckoTarget); 840 841 RefPtr<HttpTransactionParent> self = this; 842 std::function<void()> callOnResume = nullptr; 843 std::swap(callOnResume, mCallOnResume); 844 neckoTarget->Dispatch( 845 NS_NewRunnableFunction("net::HttpTransactionParent::mCallOnResume", 846 [callOnResume]() { callOnResume(); }), 847 NS_DISPATCH_NORMAL); 848 } 849 } 850 mEventQ->Resume(); 851 return NS_OK; 852 } 853 854 NS_IMETHODIMP 855 HttpTransactionParent::GetLoadGroup(nsILoadGroup** aLoadGroup) { 856 MOZ_ASSERT(false, "Should not be called."); 857 return NS_ERROR_NOT_IMPLEMENTED; 858 } 859 860 NS_IMETHODIMP 861 HttpTransactionParent::SetLoadGroup(nsILoadGroup* aLoadGroup) { 862 MOZ_ASSERT(false, "Should not be called."); 863 return NS_ERROR_NOT_IMPLEMENTED; 864 } 865 866 NS_IMETHODIMP 867 HttpTransactionParent::GetLoadFlags(nsLoadFlags* aLoadFlags) { 868 MOZ_ASSERT(false, "Should not be called."); 869 return NS_ERROR_NOT_IMPLEMENTED; 870 } 871 872 NS_IMETHODIMP 873 HttpTransactionParent::SetLoadFlags(nsLoadFlags aLoadFlags) { 874 MOZ_ASSERT(false, "Should not be called."); 875 return NS_ERROR_NOT_IMPLEMENTED; 876 } 877 878 NS_IMETHODIMP 879 HttpTransactionParent::GetTRRMode(nsIRequest::TRRMode* aTRRMode) { 880 MOZ_ASSERT(false, "Should not be called."); 881 return NS_ERROR_NOT_IMPLEMENTED; 882 } 883 884 NS_IMETHODIMP 885 HttpTransactionParent::SetTRRMode(nsIRequest::TRRMode aTRRMode) { 886 MOZ_ASSERT(false, "Should not be called."); 887 return NS_ERROR_NOT_IMPLEMENTED; 888 } 889 890 void HttpTransactionParent::ActorDestroy(ActorDestroyReason aWhy) { 891 LOG(("HttpTransactionParent::ActorDestroy [this=%p]\n", this)); 892 if (aWhy != Deletion) { 893 // Make sure all the messages are processed. 894 AutoEventEnqueuer ensureSerialDispatch(mEventQ); 895 896 mStatus = NS_ERROR_FAILURE; 897 HandleAsyncAbort(); 898 899 mCanceled = true; 900 } 901 } 902 903 void HttpTransactionParent::HandleAsyncAbort() { 904 MOZ_ASSERT(!mCallOnResume, "How did that happen?"); 905 906 if (mSuspendCount) { 907 LOG( 908 ("HttpTransactionParent Waiting until resume to do async notification " 909 "[this=%p]\n", 910 this)); 911 RefPtr<HttpTransactionParent> self = this; 912 mCallOnResume = [self]() { self->HandleAsyncAbort(); }; 913 return; 914 } 915 916 DoNotifyListener(); 917 } 918 919 bool HttpTransactionParent::GetSupportsHTTP3() { return mSupportsHTTP3; } 920 921 void HttpTransactionParent::SetIsForWebTransport(bool SetIsForWebTransport) { 922 // TODO: bug 1791727 923 } 924 925 mozilla::TimeStamp HttpTransactionParent::GetPendingTime() { 926 return mTimings.transactionPending; 927 } 928 929 } // namespace mozilla::net