HttpChannelChild.h (21210B)
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 #ifndef mozilla_net_HttpChannelChild_h 9 #define mozilla_net_HttpChannelChild_h 10 11 #include "mozilla/Mutex.h" 12 #include "mozilla/StaticPrefsBase.h" 13 #include "mozilla/extensions/StreamFilterParent.h" 14 #include "mozilla/net/HttpBaseChannel.h" 15 #include "mozilla/net/NeckoTargetHolder.h" 16 #include "mozilla/net/PHttpChannelChild.h" 17 #include "mozilla/net/ChannelEventQueue.h" 18 19 #include "nsIStreamListener.h" 20 #include "nsIInterfaceRequestor.h" 21 #include "nsIInterfaceRequestorUtils.h" 22 #include "nsIProgressEventSink.h" 23 #include "nsICacheEntry.h" 24 #include "nsICacheInfoChannel.h" 25 #include "nsIResumableChannel.h" 26 #include "nsIProxiedChannel.h" 27 #include "nsIAsyncVerifyRedirectCallback.h" 28 #include "nsIChildChannel.h" 29 #include "nsIHttpChannelChild.h" 30 #include "nsIMultiPartChannel.h" 31 #include "nsIThreadRetargetableRequest.h" 32 #include "mozilla/net/DNS.h" 33 34 class nsIEventTarget; 35 class nsIInterceptedBodyCallback; 36 class nsISerialEventTarget; 37 class nsITransportSecurityInfo; 38 class nsInputStreamPump; 39 40 #define HTTP_CHANNEL_CHILD_IID \ 41 {0x321bd99e, 0x2242, 0x4dc6, {0xbb, 0xec, 0xd5, 0x06, 0x29, 0x7c, 0x39, 0x83}} 42 43 namespace mozilla::net { 44 45 class HttpBackgroundChannelChild; 46 47 class HttpChannelChild final : public PHttpChannelChild, 48 public HttpBaseChannel, 49 public HttpAsyncAborter<HttpChannelChild>, 50 public nsICacheInfoChannel, 51 public nsIProxiedChannel, 52 public nsIAsyncVerifyRedirectCallback, 53 public nsIChildChannel, 54 public nsIHttpChannelChild, 55 public nsIMultiPartChannel, 56 public nsIThreadRetargetableRequest, 57 public NeckoTargetHolder { 58 virtual ~HttpChannelChild(); 59 60 public: 61 NS_DECL_ISUPPORTS_INHERITED 62 NS_DECL_NSICACHEINFOCHANNEL 63 NS_DECL_NSIPROXIEDCHANNEL 64 NS_DECL_NSIASYNCVERIFYREDIRECTCALLBACK 65 NS_DECL_NSICHILDCHANNEL 66 NS_DECL_NSIHTTPCHANNELCHILD 67 NS_DECL_NSIMULTIPARTCHANNEL 68 NS_DECL_NSITHREADRETARGETABLEREQUEST 69 NS_INLINE_DECL_STATIC_IID(HTTP_CHANNEL_CHILD_IID) 70 71 HttpChannelChild(); 72 73 // Methods HttpBaseChannel didn't implement for us or that we override. 74 // 75 // nsIRequest 76 NS_IMETHOD SetCanceledReason(const nsACString& aReason) override; 77 NS_IMETHOD GetCanceledReason(nsACString& aReason) override; 78 NS_IMETHOD CancelWithReason(nsresult status, 79 const nsACString& reason) override; 80 NS_IMETHOD Cancel(nsresult status) override; 81 NS_IMETHOD Suspend() override; 82 NS_IMETHOD Resume() override; 83 // nsIChannel 84 NS_IMETHOD GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) override; 85 NS_IMETHOD AsyncOpen(nsIStreamListener* aListener) override; 86 NS_IMETHOD GetDecompressDictionary( 87 DictionaryCacheEntry** aDictionary) override { 88 *aDictionary = nullptr; 89 return NS_OK; 90 } 91 NS_IMETHOD SetDecompressDictionary( 92 DictionaryCacheEntry* aDictionary) override { 93 return NS_OK; 94 } 95 96 // HttpBaseChannel::nsIHttpChannel 97 NS_IMETHOD SetRequestHeader(const nsACString& aHeader, 98 const nsACString& aValue, bool aMerge) override; 99 NS_IMETHOD SetEmptyRequestHeader(const nsACString& aHeader) override; 100 NS_IMETHOD RedirectTo(nsIURI* newURI) override; 101 NS_IMETHOD TransparentRedirectTo(nsIURI* newURI) override; 102 NS_IMETHOD UpgradeToSecure() override; 103 NS_IMETHOD GetProtocolVersion(nsACString& aProtocolVersion) override; 104 void DoDiagnosticAssertWhenOnStopNotCalledOnDestroy() override; 105 // nsIHttpChannelInternal 106 NS_IMETHOD GetIsAuthChannel(bool* aIsAuthChannel) override; 107 NS_IMETHOD SetEarlyHintObserver(nsIEarlyHintObserver* aObserver) override; 108 NS_IMETHOD SetWebTransportSessionEventListener( 109 WebTransportSessionEventListener* aListener) override; 110 111 NS_IMETHOD SetResponseOverride( 112 nsIReplacedHttpResponse* aReplacedHttpResponse) override { 113 return NS_OK; 114 } 115 116 NS_IMETHOD SetResponseStatus(uint32_t aStatus, 117 const nsACString& aStatusText) override { 118 return NS_OK; 119 } 120 // nsISupportsPriority 121 NS_IMETHOD SetPriority(int32_t value) override; 122 // nsIClassOfService 123 NS_IMETHOD SetClassFlags(uint32_t inFlags) override; 124 NS_IMETHOD AddClassFlags(uint32_t inFlags) override; 125 NS_IMETHOD ClearClassFlags(uint32_t inFlags) override; 126 NS_IMETHOD SetClassOfService(ClassOfService inCos) override; 127 NS_IMETHOD SetIncremental(bool inIncremental) override; 128 // nsIResumableChannel 129 NS_IMETHOD ResumeAt(uint64_t startPos, const nsACString& entityID) override; 130 131 nsresult SetReferrerHeader(const nsACString& aReferrer, 132 bool aRespectBeforeConnect) override; 133 134 [[nodiscard]] bool IsSuspended(); 135 136 // Callback while background channel is ready. 137 void OnBackgroundChildReady(HttpBackgroundChannelChild* aBgChild); 138 // Callback while background channel is destroyed. 139 void OnBackgroundChildDestroyed(HttpBackgroundChannelChild* aBgChild); 140 141 nsresult CrossProcessRedirectFinished(nsresult aStatus); 142 143 void RegisterStreamFilter( 144 RefPtr<extensions::StreamFilterParent>& aStreamFilter); 145 146 // Get the captured JavaScript call stack for LNA console logging 147 const char* GetCallStack() const { 148 return mCallStack ? mCallStack.get() : nullptr; 149 } 150 151 protected: 152 mozilla::ipc::IPCResult RecvOnStartRequestSent() override; 153 mozilla::ipc::IPCResult RecvFailedAsyncOpen(const nsresult& status) override; 154 mozilla::ipc::IPCResult RecvRedirect1Begin( 155 const uint32_t& registrarId, nsIURI* newOriginalURI, 156 const uint32_t& newLoadFlags, const uint32_t& redirectFlags, 157 const ParentLoadInfoForwarderArgs& loadInfoForwarder, 158 nsHttpResponseHead&& responseHead, nsITransportSecurityInfo* securityInfo, 159 const uint64_t& channelId, const NetAddr& oldPeerAddr, 160 const ResourceTimingStructArgs& aTiming) override; 161 mozilla::ipc::IPCResult RecvRedirect3Complete() override; 162 mozilla::ipc::IPCResult RecvRedirectFailed(const nsresult& status) override; 163 mozilla::ipc::IPCResult RecvDeleteSelf() override; 164 165 mozilla::ipc::IPCResult RecvReportSecurityMessage( 166 const nsAString& messageTag, const nsAString& messageCategory) override; 167 168 mozilla::ipc::IPCResult RecvReportLNAToConsole( 169 const NetAddr& aPeerAddr, const nsACString& aMessageType, 170 const nsACString& aPromptAction, 171 const nsACString& aTopLevelSite) override; 172 173 mozilla::ipc::IPCResult RecvSetPriority(const int16_t& aPriority) override; 174 175 mozilla::ipc::IPCResult RecvOriginalCacheInputStreamAvailable( 176 const Maybe<IPCStream>& aStream) override; 177 178 virtual void ActorDestroy(ActorDestroyReason aWhy) override; 179 180 virtual void DoNotifyListenerCleanup() override; 181 182 virtual void DoAsyncAbort(nsresult aStatus) override; 183 184 nsresult AsyncCall( 185 void (HttpChannelChild::*funcPtr)(), 186 nsRunnableMethod<HttpChannelChild>** retval = nullptr) override { 187 // Normally, this method would just be implemented directly, but clang 188 // miscompiles the corresponding non-virtual thunk on linux x86. 189 // It however doesn't when going though a non-virtual method. 190 // https://bugs.llvm.org/show_bug.cgi?id=38466 191 return AsyncCallImpl(funcPtr, retval); 192 }; 193 194 // Get event target for processing network events. 195 already_AddRefed<nsISerialEventTarget> GetNeckoTarget() override; 196 197 virtual mozilla::ipc::IPCResult RecvLogBlockedCORSRequest( 198 const nsAString& aMessage, const nsACString& aCategory, 199 const bool& aIsWarning) override; 200 NS_IMETHOD LogBlockedCORSRequest(const nsAString& aMessage, 201 const nsACString& aCategory, 202 bool aIsWarning = false) override; 203 204 virtual mozilla::ipc::IPCResult RecvLogMimeTypeMismatch( 205 const nsACString& aMessageName, const bool& aWarning, 206 const nsAString& aURL, const nsAString& aContentType) override; 207 NS_IMETHOD LogMimeTypeMismatch(const nsACString& aMessageName, bool aWarning, 208 const nsAString& aURL, 209 const nsAString& aContentType) override; 210 211 virtual void ExplicitSetUploadStreamLength( 212 uint64_t aContentLength, bool aSetContentLengthHeader) override; 213 214 private: 215 // We want to handle failure result of AsyncOpen, hence AsyncOpen calls the 216 // Internal method 217 nsresult AsyncOpenInternal(nsIStreamListener* aListener); 218 219 nsresult AsyncCallImpl(void (HttpChannelChild::*funcPtr)(), 220 nsRunnableMethod<HttpChannelChild>** retval); 221 222 // Sets the event target for future IPC messages. Messages will either be 223 // directed to the TabGroup or DocGroup, depending on the LoadInfo associated 224 // with the channel. Should be called when a new channel is being set up, 225 // before the constructor message is sent to the parent. 226 void SetEventTarget(); 227 228 // Get event target for ODA. 229 already_AddRefed<nsIEventTarget> GetODATarget(); 230 231 [[nodiscard]] nsresult ContinueAsyncOpen(); 232 void ProcessOnStartRequest(const nsHttpResponseHead& aResponseHead, 233 const bool& aUseResponseHead, 234 const nsHttpHeaderArray& aRequestHeaders, 235 const HttpChannelOnStartRequestArgs& aArgs, 236 const HttpChannelAltDataStream& aAltData, 237 const TimeStamp& aOnStartRequestStartTime); 238 239 // Callbacks while receiving OnTransportAndData/OnStopRequest/OnProgress/ 240 // OnStatus/FlushedForDiversion/DivertMessages on background IPC channel. 241 void ProcessOnTransportAndData(const nsresult& aChannelStatus, 242 const nsresult& aTransportStatus, 243 const uint64_t& aOffset, 244 const uint32_t& aCount, 245 const nsACString& aData, 246 const TimeStamp& aOnDataAvailableStartTime); 247 void ProcessOnStopRequest(const nsresult& aChannelStatus, 248 const ResourceTimingStructArgs& aTiming, 249 const nsHttpHeaderArray& aResponseTrailers, 250 nsTArray<ConsoleReportCollected>&& aConsoleReports, 251 bool aFromSocketProcess, 252 const TimeStamp& aOnStopRequestStartTime); 253 void ProcessOnConsoleReport( 254 nsTArray<ConsoleReportCollected>&& aConsoleReports); 255 256 void ProcessNotifyClassificationFlags(uint32_t aClassificationFlags, 257 bool aIsThirdParty); 258 void ProcessSetClassifierMatchedInfo(const nsACString& aList, 259 const nsACString& aProvider, 260 const nsACString& aFullHash); 261 void ProcessSetClassifierMatchedTrackingInfo(const nsACString& aLists, 262 const nsACString& aFullHashes); 263 void ProcessOnAfterLastPart(const nsresult& aStatus); 264 void ProcessOnProgress(const int64_t& aProgress, const int64_t& aProgressMax); 265 266 void ProcessOnStatus(const nsresult& aStatus); 267 268 void ProcessAttachStreamFilter( 269 Endpoint<extensions::PStreamFilterParent>&& aEndpoint); 270 void ProcessDetachStreamFilters(); 271 272 // Return true if we need to tell the parent the size of unreported received 273 // data 274 bool NeedToReportBytesRead(); 275 int32_t mUnreportBytesRead = 0; 276 277 void DoOnConsoleReport(nsTArray<ConsoleReportCollected>&& aConsoleReports); 278 void DoOnStartRequest(nsIRequest* aRequest); 279 void DoOnStatus(nsIRequest* aRequest, nsresult status); 280 void DoOnProgress(nsIRequest* aRequest, int64_t progress, 281 int64_t progressMax); 282 void DoOnDataAvailable(nsIRequest* aRequest, nsIInputStream* aStream, 283 uint64_t offset, uint32_t count); 284 void DoPreOnStopRequest(nsresult aStatus); 285 void DoOnStopRequest(nsIRequest* aRequest, nsresult aChannelStatus); 286 void ContinueOnStopRequest(); 287 288 // Try send DeletingChannel message to parent side. Dispatch an async task to 289 // main thread if invoking on non-main thread. 290 void TrySendDeletingChannel(); 291 292 // Try invoke Cancel if on main thread, or prepend a CancelEvent in mEventQ to 293 // ensure Cacnel is processed before any other channel events. 294 void CancelOnMainThread(nsresult aRv, const nsACString& aReason); 295 296 nsresult MaybeLogCOEPError(nsresult aStatus); 297 298 void RetargetDeliveryToImpl(nsISerialEventTarget* aNewTarget, 299 MutexAutoLock& aLockRef); 300 301 private: 302 // this section is for main-thread-only object 303 // all the references need to be proxy released on main thread. 304 nsCOMPtr<nsIChildChannel> mRedirectChannelChild; 305 306 // Proxy release all members above on main thread. 307 void ReleaseMainThreadOnlyReferences(); 308 309 private: 310 nsCString mProtocolVersion; 311 312 RequestHeaderTuples mClientSetRequestHeaders; 313 RefPtr<ChannelEventQueue> mEventQ; 314 315 nsCOMPtr<nsIInputStreamReceiver> mOriginalInputStreamReceiver; 316 nsCOMPtr<nsIInputStream> mAltDataInputStream; 317 318 // Used to ensure atomicity of mBgChild and mBgInitFailCallback 319 Mutex mBgChildMutex{"HttpChannelChild::BgChildMutex"}; 320 321 // Associated HTTP background channel 322 RefPtr<HttpBackgroundChannelChild> mBgChild MOZ_GUARDED_BY(mBgChildMutex); 323 324 // Error handling procedure if failed to establish PBackground IPC 325 nsCOMPtr<nsIRunnable> mBgInitFailCallback MOZ_GUARDED_BY(mBgChildMutex); 326 327 // Remove the association with background channel after OnStopRequest 328 // or AsyncAbort. 329 void CleanupBackgroundChannel(); 330 331 // Target thread for delivering ODA. 332 nsCOMPtr<nsISerialEventTarget> mODATarget MOZ_GUARDED_BY(mEventTargetMutex); 333 Atomic<bool, mozilla::Relaxed> mGotDataAvailable{false}; 334 // Used to ensure atomicity of mNeckoTarget / mODATarget; 335 Mutex mEventTargetMutex{"HttpChannelChild::EventTargetMutex"}; 336 337 TimeStamp mLastStatusReported; 338 339 uint64_t mCacheEntryId{0}; 340 nsICacheInfoChannel::CacheDisposition mCacheDisposition{ 341 nsICacheInfoChannel::kCacheUnknown}; 342 343 uint32_t mCacheKey{0}; 344 int32_t mCacheFetchCount{0}; 345 uint32_t mCacheExpirationTime{ 346 static_cast<uint32_t>(nsICacheEntry::NO_EXPIRATION_TIME)}; 347 348 // If we're handling a multi-part response, then this is set to the current 349 // part ID during OnStartRequest. 350 Maybe<uint32_t> mMultiPartID; 351 352 // To ensure only one SendDeletingChannel is triggered. 353 Atomic<bool> mDeletingChannelSent{false}; 354 355 Atomic<bool, SequentiallyConsistent> mIsFromCache{false}; 356 Atomic<bool, SequentiallyConsistent> mIsRacing{false}; 357 // Set if we get the result and cache |mNeedToReportBytesRead| 358 Atomic<bool, SequentiallyConsistent> mCacheNeedToReportBytesReadInitialized{ 359 false}; 360 // True if we need to tell the parent the size of unreported received data 361 Atomic<bool, SequentiallyConsistent> mNeedToReportBytesRead{true}; 362 Atomic<uint32_t, mozilla::Relaxed> mOnProgressEventSent{false}; 363 // Attached StreamFilterParents 364 // Using raw pointer here since StreamFilterParent owns the channel. 365 // Should be only accessed on the main thread. 366 using StreamFilters = nsTArray<extensions::StreamFilterParent*>; 367 StreamFilters mStreamFilters; 368 369 #ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 370 bool mDoDiagnosticAssertWhenOnStopNotCalledOnDestroy = false; 371 bool mAsyncOpenSucceeded = false; 372 bool mSuccesfullyRedirected = false; 373 bool mRemoteChannelExistedAtCancel = false; 374 bool mEverHadBgChildAtAsyncOpen = false; 375 bool mEverHadBgChildAtConnectParent = false; 376 bool mCreateBackgroundChannelFailed = false; 377 bool mBgInitFailCallbackTriggered = false; 378 bool mCanSendAtCancel = false; 379 // State of the HttpBackgroundChannelChild's event queue during destruction. 380 enum BckChildQueueStatus { 381 // BckChild never told us 382 BCKCHILD_UNKNOWN, 383 // BckChild was empty at the time of destruction 384 BCKCHILD_EMPTY, 385 // BckChild was keeping events in the queue at the destruction time! 386 BCKCHILD_NON_EMPTY 387 }; 388 Atomic<BckChildQueueStatus> mBackgroundChildQueueFinalState{BCKCHILD_UNKNOWN}; 389 Maybe<ActorDestroyReason> mActorDestroyReason; 390 #endif 391 392 uint8_t mCacheEntryAvailable : 1; 393 uint8_t mAltDataCacheEntryAvailable : 1; 394 395 // If ResumeAt is called before AsyncOpen, we need to send extra data upstream 396 uint8_t mSendResumeAt : 1; 397 398 uint8_t mKeptAlive : 1; // IPC kept open, but only for security info 399 400 // Set when ActorDestroy(ActorDestroyReason::Deletion) is called 401 // The channel must ignore any following OnStart/Stop/DataAvailable messages 402 uint8_t mIPCActorDeleted : 1; 403 404 // Set if SendSuspend is called. Determines if SendResume is needed when 405 // diverting callbacks to parent. 406 uint8_t mSuspendSent : 1; 407 408 // True if this channel is a multi-part channel, and the first part 409 // is currently being processed. 410 uint8_t mIsFirstPartOfMultiPart : 1; 411 412 // True if this channel is a multi-part channel, and the last part 413 // is currently being processed. 414 uint8_t mIsLastPartOfMultiPart : 1; 415 416 // True if this channel is suspended by ConnectParent and not resumed by 417 // CompleteRedirectSetup/RecvDeleteSelf. 418 uint8_t mSuspendForWaitCompleteRedirectSetup : 1; 419 420 // True if RecvOnStartRequestSent was received. 421 uint8_t mRecvOnStartRequestSentCalled : 1; 422 423 // True if this channel is for a document and suspended by waiting for 424 // permission or cookie. That is, RecvOnStartRequestSent is received. 425 uint8_t mSuspendedByWaitingForPermissionCookie : 1; 426 427 // HttpChannelChild::Release has some special logic that makes sure 428 // OnStart/OnStop are always called when releasing the channel. 429 // But we have to make sure we only do this once - otherwise we could 430 // get stuck in a loop. 431 uint8_t mAlreadyReleased : 1; 432 433 // JavaScript stack captured during AsyncOpen for LNA console logging 434 mozilla::UniquePtr<char[]> mCallStack; 435 436 void CleanupRedirectingChannel(nsresult rv); 437 438 // Calls OnStartRequest and/or OnStopRequest on our listener in case we didn't 439 // do that so far. If we already did, it will just release references to 440 // cleanup. 441 void NotifyOrReleaseListeners(nsresult rv); 442 443 // true after successful AsyncOpen until OnStopRequest completes. 444 bool RemoteChannelExists() { return CanSend() && !mKeptAlive; } 445 446 void OnStartRequest(const nsHttpResponseHead& aResponseHead, 447 const bool& aUseResponseHead, 448 const nsHttpHeaderArray& aRequestHeaders, 449 const HttpChannelOnStartRequestArgs& aArgs); 450 void OnTransportAndData(const nsresult& channelStatus, const nsresult& status, 451 const uint64_t& offset, const uint32_t& count, 452 const nsACString& data); 453 void OnStopRequest(const nsresult& channelStatus, 454 const ResourceTimingStructArgs& timing, 455 const nsHttpHeaderArray& aResponseTrailers); 456 void FailedAsyncOpen(const nsresult& status); 457 void HandleAsyncAbort(); 458 void Redirect1Begin(const uint32_t& registrarId, nsIURI* newOriginalURI, 459 const uint32_t& newLoadFlags, 460 const uint32_t& redirectFlags, 461 const ParentLoadInfoForwarderArgs& loadInfoForwarder, 462 const nsHttpResponseHead& responseHead, 463 nsITransportSecurityInfo* securityInfo, 464 const uint64_t& channelId, 465 const ResourceTimingStructArgs& timing); 466 void Redirect3Complete(); 467 void DeleteSelf(); 468 // aUseEventQueue should only be false when called from 469 // HttpChannelChild::Release to make sure OnStopRequest is called syncly. 470 void DoNotifyListener(bool aUseEventQueue = true); 471 void ContinueDoNotifyListener(); 472 void OnAfterLastPart(const nsresult& aStatus); 473 void MaybeConnectToSocketProcess(); 474 void OnDetachStreamFilters(); 475 void SendOnDataFinished(const nsresult& aChannelStatus); 476 477 // Create a a new channel to be used in a redirection, based on the provided 478 // response headers. 479 [[nodiscard]] nsresult SetupRedirect(nsIURI* uri, 480 const nsHttpResponseHead* responseHead, 481 const uint32_t& redirectFlags, 482 nsIChannel** outChannel); 483 484 // Collect telemetry for mixed content. 485 void CollectMixedContentTelemetry(); 486 487 friend class HttpAsyncAborter<HttpChannelChild>; 488 friend class InterceptStreamListener; 489 friend class InterceptedChannelContent; 490 friend class HttpBackgroundChannelChild; 491 friend class NeckoTargetChannelFunctionEvent; 492 }; 493 494 //----------------------------------------------------------------------------- 495 // inline functions 496 //----------------------------------------------------------------------------- 497 498 inline bool HttpChannelChild::IsSuspended() { return mSuspendCount != 0; } 499 500 } // namespace mozilla::net 501 502 #endif // mozilla_net_HttpChannelChild_h