/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* vim: set ts=8 sts=2 et sw=2 tw=80: */ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef mozilla_extensions_StreamFilterParent_h #define mozilla_extensions_StreamFilterParent_h #include "StreamFilterBase.h" #include "mozilla/extensions/PStreamFilterParent.h" #include "mozilla/LinkedList.h" #include "mozilla/Mutex.h" #include "mozilla/WebRequestService.h" #include "nsIStreamListener.h" #include "nsIThread.h" #include "nsIThreadRetargetableStreamListener.h" #include "nsThreadUtils.h" #if defined(_MSC_VER) # define FUNC __FUNCSIG__ #else # define FUNC __PRETTY_FUNCTION__ #endif namespace mozilla { namespace dom { class ContentParent; } namespace net { class ChannelEventQueue; class nsHttpChannel; } // namespace net namespace extensions { using namespace mozilla::dom; using mozilla::ipc::IPCResult; class StreamFilterParent final : public PStreamFilterParent, public nsIStreamListener, public nsIThreadRetargetableStreamListener, public nsIRequest, public StreamFilterBase { friend class PStreamFilterParent; public: NS_DECL_THREADSAFE_ISUPPORTS NS_DECL_NSISTREAMLISTENER NS_DECL_NSIREQUEST NS_DECL_NSIREQUESTOBSERVER NS_DECL_NSITHREADRETARGETABLESTREAMLISTENER StreamFilterParent(); using ParentEndpoint = mozilla::ipc::Endpoint; using ChildEndpoint = mozilla::ipc::Endpoint; using ChildEndpointPromise = MozPromise; [[nodiscard]] static RefPtr Create( ContentParent* aContentParent, uint64_t aChannelId, const nsAString& aAddonId); static void Attach(nsIChannel* aChannel, ParentEndpoint&& aEndpoint); enum class State { // The parent has been created, but not yet constructed by the child. Uninitialized, // The parent has been successfully constructed. Initialized, // The OnRequestStarted event has been received, and data is being // transferred to the child. TransferringData, // The channel is suspended. Suspended, // The channel has been closed by the child, and will send or receive data. Closed, // The channel is being disconnected from the child, so that all further // data and events pass unfiltered to the output listener. Any data // currnetly in transit to, or buffered by, the child will be written to the // output listener before we enter the Disconnected atate. Disconnecting, // The channel has been disconnected from the child, and all further data // and events will be passed directly to the output listener. Disconnected, }; // This method makes StreamFilterParent to disconnect from channel. // Notice that this method can only be called before OnStartRequest(). void Disconnect(const nsACString& aReason); protected: virtual ~StreamFilterParent(); IPCResult RecvWrite(Data&& aData); IPCResult RecvFlushedData(); IPCResult RecvSuspend(); IPCResult RecvResume(); IPCResult RecvClose(); IPCResult RecvDisconnect(); IPCResult RecvDestroy(); private: bool IPCActive() { return (mState != State::Closed && mState != State::Disconnecting && mState != State::Disconnected); } void Init(nsIChannel* aChannel); void Bind(ParentEndpoint&& aEndpoint); void Destroy(); nsresult FlushBufferedData(); nsresult Write(Data& aData); void WriteMove(Data&& aData); void DoSendData(Data&& aData); nsresult EmitStopRequest(nsresult aStatusCode); virtual void ActorDestroy(ActorDestroyReason aWhy) override; void Broken(); void FinishDisconnect(); void CheckResult(bool aResult) { if (NS_WARN_IF(!aResult)) { Broken(); } } inline nsIEventTarget* ActorThread(); inline nsISerialEventTarget* IOThread(); inline bool IsIOThread(); inline bool IsActorThread(); inline void AssertIsActorThread(); inline void AssertIsIOThread(); static void AssertIsMainThread() { MOZ_ASSERT(NS_IsMainThread()); } template void RunOnMainThread(const char* aName, Function&& aFunc); void RunOnMainThread(already_AddRefed aRunnable); template void RunOnActorThread(const char* aName, Function&& aFunc); template void RunOnIOThread(const char* aName, Function&& aFunc); void RunOnIOThread(already_AddRefed); nsCOMPtr mChannel; nsCOMPtr mLoadGroup; nsCOMPtr mOrigListener; nsCOMPtr mMainThread; nsCOMPtr mIOThread; RefPtr mQueue; Mutex mBufferMutex MOZ_UNANNOTATED; bool mReceivedStop; bool mSentStop; bool mDisconnected = false; // If redirection happens or alterate cached data is being sent, the stream // filter is disconnected in OnStartRequest and the following ODA would not // be filtered. Using mDisconnected causes race condition. mState is possible // to late to be set, which leads out of sync. bool mDisconnectedByOnStartRequest = false; bool mBeforeOnStartRequest = true; nsCOMPtr mContext; uint64_t mOffset; // Use Release-Acquire ordering to ensure the OMT ODA is not sent while // the channel is disconnecting or closed. Atomic mState; }; } // namespace extensions } // namespace mozilla #endif // mozilla_extensions_StreamFilterParent_h