Http2WebTransportSession.h (8185B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* This Source Code Form is subject to the terms of the Mozilla Public 3 * License, v. 2.0. If a copy of the MPL was not distributed with this 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 5 6 #ifndef mozilla_net_Http2WebTransportSession_h 7 #define mozilla_net_Http2WebTransportSession_h 8 9 #include "CapsuleParser.h" 10 #include "Http2StreamTunnel.h" 11 #include "mozilla/UniquePtr.h" 12 #include "mozilla/Queue.h" 13 #include "nsRefPtrHashtable.h" 14 #include "nsTHashMap.h" 15 #include "nsHashKeys.h" 16 #include "WebTransportFlowControl.h" 17 #include "WebTransportSessionBase.h" 18 #include "WebTransportStreamBase.h" 19 20 namespace mozilla::net { 21 22 class CapsuleEncoder; 23 class Http2WebTransportStream; 24 25 // A handler used exclusively by Http2WebTransportSessionImpl for capsule I/O, 26 // primarily responsible for sending capsules. 27 class CapsuleIOHandler { 28 public: 29 NS_INLINE_DECL_PURE_VIRTUAL_REFCOUNTING 30 31 virtual void HasCapsuleToSend() = 0; 32 virtual void SetSentFin() = 0; 33 virtual void StartReading() = 0; 34 virtual void OnCapsuleParseFailure(nsresult aError) = 0; 35 36 protected: 37 virtual ~CapsuleIOHandler() = default; 38 }; 39 40 struct Http2WebTransportInitialSettings { 41 // Initial session-level data limit. 42 uint32_t mInitialMaxData = 0; 43 // Initial stream-level data limit for outgoing unidirectional streams. 44 uint32_t mInitialMaxStreamDataUni = 0; 45 // Initial stream-level data limit for outgoing bidirectional streams. 46 uint32_t mInitialMaxStreamDataBidi = 0; 47 // Initial max unidirectional streams per session. 48 uint32_t mInitialMaxStreamsUni = 0; 49 // Initial max bidirectional streams per session. 50 uint32_t mInitialMaxStreamsBidi = 0; 51 // Initial limit on unidirectional streams that the peer creates. 52 uint32_t mInitialLocalMaxStreamsUnidi = 16; 53 // Initial limit on bidirectional streams that the peer creates. 54 uint32_t mInitialLocalMaxStreamsBidi = 16; 55 // Initial flow control limit for receiving data on unidirectional streams 56 // that the peer creates. 57 uint32_t mInitialLocalMaxStreamDataUnidi = 0x100000; 58 // Initial flow control limit for receiving data on bidirectional streams 59 // that the peer creates. 60 uint32_t mInitialLocalMaxStreamDataBidi = 0x100000; 61 // Initial session-level flow control limit. 62 uint64_t mInitialLocalMaxData = 0x3FFFFFFFFFFFFFFF; 63 }; 64 65 enum class CapsuleTransmissionPriority : uint8_t { 66 Critical = 0, 67 Important = 1, 68 High = 2, 69 Normal = 3, 70 Low = 4, 71 }; 72 73 // Core implementation of the logic behind Http2WebTransportSession. 74 // It's designed to be independently instantiated, which makes it easier to 75 // test. 76 class Http2WebTransportSessionImpl final : public WebTransportSessionBase, 77 public CapsuleParser::Listener { 78 public: 79 NS_INLINE_DECL_THREADSAFE_REFCOUNTING(Http2WebTransportSessionImpl, override) 80 81 explicit Http2WebTransportSessionImpl( 82 CapsuleIOHandler* aHandler, Http2WebTransportInitialSettings aSettings); 83 84 void CloseSession(uint32_t aStatus, const nsACString& aReason) override; 85 uint64_t GetStreamId() const override; 86 void GetMaxDatagramSize() override; 87 void SendDatagram(nsTArray<uint8_t>&& aData, uint64_t aTrackingId) override; 88 void CreateOutgoingBidirectionalStream( 89 std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&& 90 aCallback) override; 91 void CreateOutgoingUnidirectionalStream( 92 std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&& 93 aCallback) override; 94 bool OnCapsule(Capsule&& aCapsule) override; 95 void OnCapsuleParseFailure(nsresult aError) override; 96 void StartReading() override; 97 void Close(nsresult aReason); 98 99 void OnStreamClosed(Http2WebTransportStream* aStream); 100 void PrepareCapsulesToSend( 101 mozilla::Queue<UniquePtr<CapsuleEncoder>>& aOutput); 102 SenderFlowControlSession& SessionDataFc() { return mSessionDataFc; } 103 ReceiverFlowControlSession& ReceiverFc() { return mReceiverFc; } 104 105 void StreamHasCapsuleToSend(); 106 void OnStreamDataSent(StreamId aId, size_t aCount); 107 void OnError(uint64_t aError); 108 109 private: 110 virtual ~Http2WebTransportSessionImpl(); 111 112 void CreateOutgoingStreamInternal( 113 StreamId aStreamId, 114 std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&& 115 aCallback); 116 117 class PendingStreamCallback { 118 public: 119 explicit PendingStreamCallback( 120 std::function<void( 121 Result<RefPtr<WebTransportStreamBase>, nsresult>&&)>&& aCallback) 122 : mCallback(std::move(aCallback)) {} 123 std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)> 124 TakeCallback() { 125 return std::move(mCallback); 126 } 127 128 private: 129 std::function<void(Result<RefPtr<WebTransportStreamBase>, nsresult>&&)> 130 mCallback; 131 }; 132 void ProcessPendingStreamCallbacks( 133 mozilla::Queue<UniquePtr<PendingStreamCallback>>& aCallbacks, 134 WebTransportStreamType aStreamType); 135 bool ProcessIncomingStreamCapsule(Capsule&& aCapsule, StreamId aID, 136 WebTransportStreamType aStreamType); 137 void SendMaintenanceCapsules(CapsuleTransmissionPriority aPriority); 138 already_AddRefed<Http2WebTransportStream> GetStream(StreamId aId); 139 bool HandleMaxStreamDataCapsule(StreamId aId, Capsule&& aCapsule); 140 bool HandleStreamStopSendingCapsule(StreamId aId, Capsule&& aCapsule); 141 bool HandleStreamResetCapsule(StreamId aId, Capsule&& aCapsule); 142 143 class CapsuleQueue final { 144 public: 145 CapsuleQueue(); 146 mozilla::Queue<UniquePtr<CapsuleEncoder>>& operator[]( 147 CapsuleTransmissionPriority aPriority); 148 149 private: 150 mozilla::Queue<UniquePtr<CapsuleEncoder>> mCritical; 151 mozilla::Queue<UniquePtr<CapsuleEncoder>> mImportant; 152 mozilla::Queue<UniquePtr<CapsuleEncoder>> mHigh; 153 mozilla::Queue<UniquePtr<CapsuleEncoder>> mNormal; 154 mozilla::Queue<UniquePtr<CapsuleEncoder>> mLow; 155 }; 156 void EnqueueOutCapsule(CapsuleTransmissionPriority aPriority, 157 UniquePtr<CapsuleEncoder>&& aData); 158 159 uint64_t mStreamId = 0; 160 nsRefPtrHashtable<nsUint64HashKey, Http2WebTransportStream> mOutgoingStreams; 161 nsRefPtrHashtable<nsUint64HashKey, Http2WebTransportStream> mIncomingStreams; 162 163 mozilla::Queue<UniquePtr<PendingStreamCallback>> mBidiPendingStreamCallbacks; 164 mozilla::Queue<UniquePtr<PendingStreamCallback>> mUnidiPendingStreamCallbacks; 165 Http2WebTransportInitialSettings mSettings; 166 LocalStreamLimits mLocalStreamsFlowControl; 167 RemoteStreamLimits mRemoteStreamsFlowControl; 168 169 RefPtr<CapsuleIOHandler> mHandler; 170 CapsuleQueue mCapsuleQueue; 171 SenderFlowControlSession mSessionDataFc; 172 ReceiverFlowControlSession mReceiverFc; 173 }; 174 175 class Http2WebTransportSession final : public Http2StreamTunnel, 176 public nsIOutputStreamCallback, 177 public nsIInputStreamCallback, 178 public CapsuleIOHandler { 179 public: 180 NS_DECL_ISUPPORTS_INHERITED 181 NS_DECL_NSIOUTPUTSTREAMCALLBACK 182 NS_DECL_NSIINPUTSTREAMCALLBACK 183 184 Http2WebTransportSession(Http2Session* aSession, int32_t aPriority, 185 uint64_t aBcId, 186 nsHttpConnectionInfo* aConnectionInfo, 187 Http2WebTransportInitialSettings aSettings); 188 Http2WebTransportSession* GetHttp2WebTransportSession() override { 189 return this; 190 } 191 Http2WebTransportSessionImpl* GetHttp2WebTransportSessionImpl() { 192 return mImpl; 193 } 194 195 void CloseStream(nsresult aReason) override; 196 void HasCapsuleToSend() override; 197 void SetSentFin() override; 198 void StartReading() override; 199 void OnCapsuleParseFailure(nsresult aError) override; 200 201 private: 202 virtual ~Http2WebTransportSession(); 203 nsresult GenerateHeaders(nsCString& aCompressedData, 204 uint8_t& aFirstFrameFlags) override; 205 206 size_t mWriteOffset{0}; 207 mozilla::Queue<UniquePtr<CapsuleEncoder>> mOutgoingQueue; 208 RefPtr<Http2WebTransportSessionImpl> mImpl; 209 UniquePtr<CapsuleParser> mCapsuleParser; 210 UniquePtr<CapsuleEncoder> mCurrentOutCapsule; 211 }; 212 213 } // namespace mozilla::net 214 215 #endif // mozilla_net_Http2WebTransportSession_h