/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ /* 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_net_Http2WebTransportSession_h #define mozilla_net_Http2WebTransportSession_h #include "CapsuleParser.h" #include "Http2StreamTunnel.h" #include "mozilla/UniquePtr.h" #include "mozilla/Queue.h" #include "nsRefPtrHashtable.h" #include "nsTHashMap.h" #include "nsHashKeys.h" #include "WebTransportFlowControl.h" #include "WebTransportSessionBase.h" #include "WebTransportStreamBase.h" namespace mozilla::net { class CapsuleEncoder; class Http2WebTransportStream; // A handler used exclusively by Http2WebTransportSessionImpl for capsule I/O, // primarily responsible for sending capsules. class CapsuleIOHandler { public: NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING virtual void HasCapsuleToSend() = 0; virtual void SetSentFin() = 0; virtual void StartReading() = 0; virtual void OnCapsuleParseFailure(nsresult aError) = 0; protected: virtual ~CapsuleIOHandler() = default; }; struct Http2WebTransportInitialSettings { // Initial session-level data limit. uint32_t mInitialMaxData = 0; // Initial stream-level data limit for outgoing unidirectional streams. uint32_t mInitialMaxStreamDataUni = 0; // Initial stream-level data limit for outgoing bidirectional streams. uint32_t mInitialMaxStreamDataBidi = 0; // Initial max unidirectional streams per session. uint32_t mInitialMaxStreamsUni = 0; // Initial max bidirectional streams per session. uint32_t mInitialMaxStreamsBidi = 0; // Initial limit on unidirectional streams that the peer creates. uint32_t mInitialLocalMaxStreamsUnidi = 16; // Initial limit on bidirectional streams that the peer creates. uint32_t mInitialLocalMaxStreamsBidi = 16; // Initial flow control limit for receiving data on unidirectional streams // that the peer creates. uint32_t mInitialLocalMaxStreamDataUnidi = 0x100000; // Initial flow control limit for receiving data on bidirectional streams // that the peer creates. uint32_t mInitialLocalMaxStreamDataBidi = 0x100000; // Initial session-level flow control limit. uint64_t mInitialLocalMaxData = 0x3FFFFFFFFFFFFFFF; }; enum class CapsuleTransmissionPriority : uint8_t { Critical = 0, Important = 1, High = 2, Normal = 3, Low = 4, }; // Core implementation of the logic behind Http2WebTransportSession. // It's designed to be independently instantiated, which makes it easier to // test. class Http2WebTransportSessionImpl final : public WebTransportSessionBase, public CapsuleParser::Listener { public: NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http2WebTransportSessionImpl, override) explicit Http2WebTransportSessionImpl( CapsuleIOHandler* aHandler, Http2WebTransportInitialSettings aSettings); void CloseSession(uint32_t aStatus, const nsACString& aReason) override; uint64_t GetStreamId() const override; void GetMaxDatagramSize() override; void SendDatagram(nsTArray&& aData, uint64_t aTrackingId) override; void CreateOutgoingBidirectionalStream( std::function, nsresult>&&)>&& aCallback) override; void CreateOutgoingUnidirectionalStream( std::function, nsresult>&&)>&& aCallback) override; bool OnCapsule(Capsule&& aCapsule) override; void OnCapsuleParseFailure(nsresult aError) override; void StartReading() override; void Close(nsresult aReason); void OnStreamClosed(Http2WebTransportStream* aStream); void PrepareCapsulesToSend( mozilla::Queue>& aOutput); SenderFlowControlSession& SessionDataFc() { return mSessionDataFc; } ReceiverFlowControlSession& ReceiverFc() { return mReceiverFc; } void StreamHasCapsuleToSend(); void OnStreamDataSent(StreamId aId, size_t aCount); void OnError(uint64_t aError); private: virtual ~Http2WebTransportSessionImpl(); void CreateOutgoingStreamInternal( StreamId aStreamId, std::function, nsresult>&&)>&& aCallback); class PendingStreamCallback { public: explicit PendingStreamCallback( std::function, nsresult>&&)>&& aCallback) : mCallback(std::move(aCallback)) {} std::function, nsresult>&&)> TakeCallback() { return std::move(mCallback); } private: std::function, nsresult>&&)> mCallback; }; void ProcessPendingStreamCallbacks( mozilla::Queue>& aCallbacks, WebTransportStreamType aStreamType); bool ProcessIncomingStreamCapsule(Capsule&& aCapsule, StreamId aID, WebTransportStreamType aStreamType); void SendMaintenanceCapsules(CapsuleTransmissionPriority aPriority); already_AddRefed GetStream(StreamId aId); bool HandleMaxStreamDataCapsule(StreamId aId, Capsule&& aCapsule); bool HandleStreamStopSendingCapsule(StreamId aId, Capsule&& aCapsule); bool HandleStreamResetCapsule(StreamId aId, Capsule&& aCapsule); class CapsuleQueue final { public: CapsuleQueue(); mozilla::Queue>& operator[]( CapsuleTransmissionPriority aPriority); private: mozilla::Queue> mCritical; mozilla::Queue> mImportant; mozilla::Queue> mHigh; mozilla::Queue> mNormal; mozilla::Queue> mLow; }; void EnqueueOutCapsule(CapsuleTransmissionPriority aPriority, UniquePtr&& aData); uint64_t mStreamId = 0; nsRefPtrHashtable mOutgoingStreams; nsRefPtrHashtable mIncomingStreams; mozilla::Queue> mBidiPendingStreamCallbacks; mozilla::Queue> mUnidiPendingStreamCallbacks; Http2WebTransportInitialSettings mSettings; LocalStreamLimits mLocalStreamsFlowControl; RemoteStreamLimits mRemoteStreamsFlowControl; RefPtr mHandler; CapsuleQueue mCapsuleQueue; SenderFlowControlSession mSessionDataFc; ReceiverFlowControlSession mReceiverFc; }; class Http2WebTransportSession final : public Http2StreamTunnel, public nsIOutputStreamCallback, public nsIInputStreamCallback, public CapsuleIOHandler { public: NS_DECL_ISUPPORTS_INHERITED NS_DECL_NSIOUTPUTSTREAMCALLBACK NS_DECL_NSIINPUTSTREAMCALLBACK Http2WebTransportSession(Http2Session* aSession, int32_t aPriority, uint64_t aBcId, nsHttpConnectionInfo* aConnectionInfo, Http2WebTransportInitialSettings aSettings); Http2WebTransportSession* GetHttp2WebTransportSession() override { return this; } Http2WebTransportSessionImpl* GetHttp2WebTransportSessionImpl() { return mImpl; } void CloseStream(nsresult aReason) override; void HasCapsuleToSend() override; void SetSentFin() override; void StartReading() override; void OnCapsuleParseFailure(nsresult aError) override; private: virtual ~Http2WebTransportSession(); nsresult GenerateHeaders(nsCString& aCompressedData, uint8_t& aFirstFrameFlags) override; size_t mWriteOffset{0}; mozilla::Queue> mOutgoingQueue; RefPtr mImpl; UniquePtr mCapsuleParser; UniquePtr mCurrentOutCapsule; }; } // namespace mozilla::net #endif // mozilla_net_Http2WebTransportSession_h