1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim:set ts=4 sw=2 et cindent: */
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/. */
7 #ifndef Http3Session_H__
8 #define Http3Session_H__
10 #include "HttpTrafficAnalyzer.h"
11 #include "mozilla/UniquePtr.h"
12 #include "mozilla/WeakPtr.h"
13 #include "mozilla/net/NeqoHttp3Conn.h"
14 #include "nsAHttpConnection.h"
16 #include "nsISupportsImpl.h"
18 #include "nsIUDPSocket.h"
19 #include "nsRefPtrHashtable.h"
20 #include "nsTHashMap.h"
21 #include "nsWeakReference.h"
26 * Http3Session and the underlying neqo code support multiplexing of multiple
27 * WebTransport and multiplexing WebTransport sessions with regular HTTP
28 * traffic. Whether WebTransport sessions are polled, will be controlled by the
29 * nsHttpConnectionMgr.
31 * WebTransport support is negotiated using HTTP/3 setting. Before the settings
32 * are available all WebTransport transactions are queued in
33 * mWaitingForWebTransportNegotiation. The information on whether WebTransport
34 * is supported is received via an HTTP/3 event. The event is
35 * Http3Event::Tag::WebTransport with the value
36 * WebTransportEventExternal::Tag::Negotiated that can be true or false. If
37 * the WebTransport feature has been negotiated, queued transactions will be
38 * activated otherwise they will be canceled(i.e. WebTransportNegotiationDone).
40 * The lifetime of a WebTransport session
42 * A WebTransport lifetime consists of 2 parts:
43 * - WebTransport session setup
44 * - WebTransport session active time
46 * WebTransport session setup:
47 * A WebTransport session uses a regular HTTP request for negotiation.
48 * Therefore when a new WebTransport is started a nsHttpChannel and the
49 * corresponding nsHttpTransaction are created. The nsHttpTransaction is
50 * dispatched to a Http3Session and after the
51 * WebTransportEventExternal::Tag::Negotiated event it behaves almost the same
52 * as a regular transaction, e.g. it is added to mStreamTransactionHash and
53 * mStreamIdHash. For activating the session NeqoHttp3Conn::CreateWebTransport
54 * is called instead of NeqoHttp3Conn::Fetch(this is called for the regular
55 * HTTP requests). In this phase, the WebTransport session is canceled in the
56 * same way a regular request is canceled, by canceling the corresponding
57 * nsHttpChannel. If HTTP/3 connection is closed in this phase the
58 * corresponding nsHttpTransaction is canceled and this may cause the
59 * transaction to be restarted (this is the existing restart logic) or the
60 * error is propagated to the nsHttpChannel and its listener(via OnStartRequest
61 * and OnStopRequest as the regular HTTP request).
62 * The phase ends when a connection breaks or when the event
63 * Http3Event::Tag::WebTransport with the value
64 * WebTransportEventExternal::Tag::Session is received. The parameter
65 * aData(from NeqoHttp3Conn::GetEvent) contain the HTTP head of the response.
67 * - failed code, i.e. anything except 200. In this case, the nsHttpTransaction
68 * behaves the same as a normal HTTP request and the nsHttpChannel listener
69 * will be informed via OnStartRequest and OnStopRequest calls.
70 * - success code, i.e. 200. The code will be propagated to the
71 * nsHttpTransaction. The transaction will parse the header and call
72 * Http3Session::GetWebTransportSession. The function transfers WebTransport
73 * session into the next phase:
74 * - Removes nsHttpTransaction from mStreamTransactionHash.
75 * - Adds the stream to mWebTransportSessions
76 * - The nsHttpTransaction supplies Http3WebTransportSession to the
77 * WebTransportSessionProxy and vice versa.
78 * TODO remove this circular referencing.
80 * WebTransport session active time:
81 * During this phase the following actions are possible:
82 * - Cancelling a WebTransport session by the application:
83 * The application calls Http3WebTransportSession::CloseSession. This
84 * transfers Http3WebTransportSession into the CLOSE_PENDING state and calls
85 * Http3Session::ConnectSlowConsumer to add itself to the “ready for reading
86 * queue”. Consequently, the Http3Session will call
87 * Http3WebTransportSession::WriteSegments and
88 * Http3Session::CloseWebTransport will be called to send the closing signal
89 * to the peer. After this, the Http3WebTransportSession is in the state DONE
90 * and it will be removed from the Http3Session(the CloseStream function
91 * takes care of this).
92 * - The peer sending a session closing signal:
93 * Http3Session will receive a Http3Event::Tag::WebTransport event with value
94 * WebTransportEventExternal::Tag::SessionClosed. The
95 * Http3WebTransportSession::OnSessionClosed function for the corresponding
96 * stream wil be called. The function will inform the corresponding
97 * WebTransportSessionProxy by calling OnSessionClosed function. The
98 * Http3WebTransportSession is in the state DONE and will be removed from the
99 * Http3Session(the CloseStream function takes care of this).
102 namespace mozilla::net
{
104 class HttpConnectionUDP
;
105 class Http3StreamBase
;
106 class QuicSocketControl
;
108 // IID for the Http3Session interface
109 #define NS_HTTP3SESSION_IID \
111 0x8fc82aaf, 0xc4ef, 0x46ed, { \
112 0x89, 0x41, 0x93, 0x95, 0x8f, 0xac, 0x4f, 0x21 \
116 enum class EchExtensionStatus
{
117 kNotPresent
, // No ECH Extension was sent
118 kGREASE
, // A GREASE ECH Extension was sent
119 kReal
// A 'real' ECH Extension was sent
122 class Http3Session final
: public nsAHttpTransaction
, public nsAHttpConnection
{
124 NS_DECLARE_STATIC_IID_ACCESSOR(NS_HTTP3SESSION_IID
)
126 NS_DECL_THREADSAFE_ISUPPORTS
127 NS_DECL_NSAHTTPTRANSACTION
128 NS_DECL_NSAHTTPCONNECTION(mConnection
)
131 nsresult
Init(const nsHttpConnectionInfo
* aConnInfo
, nsINetAddr
* selfAddr
,
132 nsINetAddr
* peerAddr
, HttpConnectionUDP
* udpConn
,
133 uint32_t controlFlags
, nsIInterfaceRequestor
* callbacks
);
135 bool IsConnected() const { return mState
== CONNECTED
; }
136 bool CanSendData() const {
137 return (mState
== CONNECTED
) || (mState
== ZERORTT
);
139 bool IsClosing() const { return (mState
== CLOSING
|| mState
== CLOSED
); }
140 bool IsClosed() const { return mState
== CLOSED
; }
142 bool AddStream(nsAHttpTransaction
* aHttpTransaction
, int32_t aPriority
,
143 nsIInterfaceRequestor
* aCallbacks
);
147 // The following functions are used by Http3Stream and
148 // Http3WebTransportSession:
149 nsresult
TryActivating(const nsACString
& aMethod
, const nsACString
& aScheme
,
150 const nsACString
& aAuthorityHeader
,
151 const nsACString
& aPath
, const nsACString
& aHeaders
,
152 uint64_t* aStreamId
, Http3StreamBase
* aStream
);
153 // The folowing functions are used by Http3Stream:
154 void CloseSendingSide(uint64_t aStreamId
);
155 nsresult
SendRequestBody(uint64_t aStreamId
, const char* buf
, uint32_t count
,
156 uint32_t* countRead
);
157 nsresult
ReadResponseHeaders(uint64_t aStreamId
,
158 nsTArray
<uint8_t>& aResponseHeaders
, bool* aFin
);
159 nsresult
ReadResponseData(uint64_t aStreamId
, char* aBuf
, uint32_t aCount
,
160 uint32_t* aCountWritten
, bool* aFin
);
162 // The folowing functions are used by Http3WebTransportSession:
163 nsresult
CloseWebTransport(uint64_t aSessionId
, uint32_t aError
,
164 const nsACString
& aMessage
);
165 nsresult
CreateWebTransportStream(uint64_t aSessionId
,
166 WebTransportStreamType aStreamType
,
167 uint64_t* aStreamId
);
168 void CloseStream(Http3StreamBase
* aStream
, nsresult aResult
);
169 void CloseStreamInternal(Http3StreamBase
* aStream
, nsresult aResult
);
171 void SetCleanShutdown(bool aCleanShutdown
) {
172 mCleanShutdown
= aCleanShutdown
;
175 bool TestJoinConnection(const nsACString
& hostname
, int32_t port
);
176 bool JoinConnection(const nsACString
& hostname
, int32_t port
);
178 void TransactionHasDataToWrite(nsAHttpTransaction
* caller
) override
;
179 void TransactionHasDataToRecv(nsAHttpTransaction
* caller
) override
;
180 [[nodiscard
]] nsresult
GetTransactionTLSSocketControl(
181 nsITLSSocketControl
**) override
;
183 // This function will be called by QuicSocketControl when the certificate
184 // verification is done.
185 void Authenticated(int32_t aError
);
187 nsresult
ProcessOutputAndEvents(nsIUDPSocket
* socket
);
189 void ReportHttp3Connection();
191 int64_t GetBytesWritten() { return mTotalBytesWritten
; }
192 int64_t BytesRead() { return mTotalBytesRead
; }
194 nsresult
SendData(nsIUDPSocket
* socket
);
195 nsresult
RecvData(nsIUDPSocket
* socket
);
197 void DoSetEchConfig(const nsACString
& aEchConfig
);
199 nsresult
SendPriorityUpdateFrame(uint64_t aStreamId
, uint8_t aPriorityUrgency
,
200 bool aPriorityIncremental
);
202 void ConnectSlowConsumer(Http3StreamBase
* stream
);
204 nsresult
TryActivatingWebTransportStream(uint64_t* aStreamId
,
205 Http3StreamBase
* aStream
);
206 void CloseWebTransportStream(Http3WebTransportStream
* aStream
,
208 void StreamHasDataToWrite(Http3StreamBase
* aStream
);
209 void ResetWebTransportStream(Http3WebTransportStream
* aStream
,
210 uint64_t aErrorCode
);
211 void StreamStopSending(Http3WebTransportStream
* aStream
, uint8_t aErrorCode
);
213 void SendDatagram(Http3WebTransportSession
* aSession
,
214 nsTArray
<uint8_t>& aData
, uint64_t aTrackingId
);
216 uint64_t MaxDatagramSize(uint64_t aSessionId
);
218 void SetSendOrder(Http3StreamBase
* aStream
, int64_t aSendOrder
);
220 void CloseWebTransportConn();
225 void CloseInternal(bool aCallNeqoClose
);
228 bool RealJoinConnection(const nsACString
& hostname
, int32_t port
,
231 nsresult
ProcessOutput(nsIUDPSocket
* socket
);
232 void ProcessInput(nsIUDPSocket
* socket
);
233 nsresult
ProcessEvents();
235 nsresult
ProcessTransactionRead(uint64_t stream_id
);
236 nsresult
ProcessTransactionRead(Http3StreamBase
* stream
);
237 nsresult
ProcessSlowConsumers();
239 void SetupTimer(uint64_t aTimeout
);
245 void ResetOrStopSendingRecvd(uint64_t aStreamId
, uint64_t aError
,
248 void QueueStream(Http3StreamBase
* stream
);
249 void RemoveStreamFromQueues(Http3StreamBase
*);
250 void ProcessPending();
252 void CallCertVerification(Maybe
<nsCString
> aEchPublicName
);
255 void EchOutcomeTelemetry();
257 void StreamReadyToWrite(Http3StreamBase
* aStream
);
258 void MaybeResumeSend();
260 void CloseConnectionTelemetry(CloseError
& aError
, bool aClosing
);
261 void Finish0Rtt(bool aRestart
);
263 enum ZeroRttOutcome
{
268 USED_CONN_CLOSED_BY_NECKO
270 void ZeroRttTelemetry(ZeroRttOutcome aOutcome
);
272 RefPtr
<NeqoHttp3Conn
> mHttp3Connection
;
273 RefPtr
<nsAHttpConnection
> mConnection
;
274 // We need an extra map to store the mapping of WebTransportSession and
275 // WebTransportStreams to handle the case that a stream is already removed
276 // from mStreamIdHash and we still need the WebTransportSession.
277 nsTHashMap
<nsUint64HashKey
, uint64_t> mWebTransportStreamToSessionMap
;
278 nsRefPtrHashtable
<nsUint64HashKey
, Http3StreamBase
> mStreamIdHash
;
279 nsRefPtrHashtable
<nsPtrHashKey
<nsAHttpTransaction
>, Http3StreamBase
>
280 mStreamTransactionHash
;
282 nsRefPtrDeque
<Http3StreamBase
> mReadyForWrite
;
284 nsTArray
<RefPtr
<Http3StreamBase
>> mSlowConsumersReadyForRead
;
285 nsRefPtrDeque
<Http3StreamBase
> mQueuedStreams
;
293 } mState
{INITIALIZING
};
295 bool mAuthenticationStarted
{false};
296 bool mCleanShutdown
{false};
297 bool mGoawayReceived
{false};
298 bool mShouldClose
{false};
299 bool mIsClosedByNeqo
{false};
300 bool mHttp3ConnectionReported
= false;
301 // mError is neqo error (a protocol error) and that may mean that we will
302 // send some packets after that.
303 nsresult mError
{NS_OK
};
304 // This is a socket error, there is no poioint in sending anything on that
306 nsresult mSocketError
{NS_OK
};
307 bool mBeforeConnectedError
{false};
308 uint64_t mCurrentBrowserId
;
310 // True if the mTimer is inited and waiting for firing.
311 bool mTimerActive
{false};
313 RefPtr
<HttpConnectionUDP
> mUdpConn
;
315 // The underlying socket transport object is needed to propogate some events
316 RefPtr
<nsISocketTransport
> mSocketTransport
;
318 nsCOMPtr
<nsITimer
> mTimer
;
320 nsTHashMap
<nsCStringHashKey
, bool> mJoinConnectionCache
;
322 RefPtr
<QuicSocketControl
> mSocketControl
;
324 uint64_t mTransactionCount
= 0;
326 // The stream(s) that we are getting 0RTT data from.
327 nsTArray
<WeakPtr
<Http3StreamBase
>> m0RTTStreams
;
328 // The stream(s) that are not able to send 0RTT data. We need to
329 // remember them put them into mReadyForWrite queue when 0RTT finishes.
330 nsTArray
<WeakPtr
<Http3StreamBase
>> mCannotDo0RTTStreams
;
332 // The following variables are needed for telemetry.
333 TimeStamp mConnectionIdleStart
;
334 TimeStamp mConnectionIdleEnd
;
335 Maybe
<uint64_t> mFirstStreamIdReuseIdleConnection
;
336 TimeStamp mTimerShouldTrigger
;
337 TimeStamp mZeroRttStarted
;
338 uint64_t mBlockedByStreamLimitCount
= 0;
339 uint64_t mTransactionsBlockedByStreamLimitCount
= 0;
340 uint64_t mTransactionsSenderBlockedByFlowControlCount
= 0;
342 // NS_NET_STATUS_CONNECTED_TO event will be created by the Http3Session.
343 // We want to propagate it to the first transaction.
344 RefPtr
<nsHttpTransaction
> mFirstHttpTransaction
;
346 RefPtr
<nsHttpConnectionInfo
> mConnInfo
;
348 bool mThroughCaptivePortal
= false;
349 int64_t mTotalBytesRead
= 0; // total data read
350 int64_t mTotalBytesWritten
= 0; // total data read
351 PRIntervalTime mLastWriteTime
= 0;
353 // Records whether we sent an ECH Extension and whether it was a GREASE Xtn
354 EchExtensionStatus mEchExtensionStatus
= EchExtensionStatus::kNotPresent
;
356 // Records whether the handshake finished successfully and we established a
358 bool mHandshakeSucceeded
= false;
360 nsCOMPtr
<nsINetAddr
> mNetAddr
;
362 enum WebTransportNegotiation
{ DISABLED
, NEGOTIATING
, FAILED
, SUCCEEDED
};
363 WebTransportNegotiation mWebTransportNegotiationStatus
{
364 WebTransportNegotiation::DISABLED
};
366 nsTArray
<WeakPtr
<Http3StreamBase
>> mWaitingForWebTransportNegotiation
;
367 // 1795854 implement the case when WebTransport is not supported.
368 // Also, implement the case when the HTTP/3 session fails before settings
370 void WebTransportNegotiationDone();
372 nsTArray
<RefPtr
<Http3StreamBase
>> mWebTransportSessions
;
373 nsTArray
<RefPtr
<Http3StreamBase
>> mWebTransportStreams
;
375 bool mHasWebTransportSession
= false;
376 // When true, we don't add this connection info into the Http/3 excluded list.
377 bool mDontExclude
= false;
380 NS_DEFINE_STATIC_IID_ACCESSOR(Http3Session
, NS_HTTP3SESSION_IID
);
382 } // namespace mozilla::net
384 #endif // Http3Session_H__