Backed out changeset a47a1ff34d2a (bug 1853444) for causing failures on /webtransport...
[gecko.git] / netwerk / protocol / http / Http3Session.h
blobee7f29fea0f728115a5454a451a89433f2742a93
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"
15 #include "nsDeque.h"
16 #include "nsISupportsImpl.h"
17 #include "nsITimer.h"
18 #include "nsIUDPSocket.h"
19 #include "nsRefPtrHashtable.h"
20 #include "nsTHashMap.h"
21 #include "nsWeakReference.h"
24 * WebTransport
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.
66 * The headers may be:
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 {
123 public:
124 NS_DECLARE_STATIC_IID_ACCESSOR(NS_HTTP3SESSION_IID)
126 NS_DECL_THREADSAFE_ISUPPORTS
127 NS_DECL_NSAHTTPTRANSACTION
128 NS_DECL_NSAHTTPCONNECTION(mConnection)
130 Http3Session();
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);
145 bool CanReuse();
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,
207 nsresult aResult);
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();
222 private:
223 ~Http3Session();
225 void CloseInternal(bool aCallNeqoClose);
226 void Shutdown();
228 bool RealJoinConnection(const nsACString& hostname, int32_t port,
229 bool justKidding);
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);
241 enum ResetType {
242 RESET,
243 STOP_SENDING,
245 void ResetOrStopSendingRecvd(uint64_t aStreamId, uint64_t aError,
246 ResetType aType);
248 void QueueStream(Http3StreamBase* stream);
249 void RemoveStreamFromQueues(Http3StreamBase*);
250 void ProcessPending();
252 void CallCertVerification(Maybe<nsCString> aEchPublicName);
253 void SetSecInfo();
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 {
264 NOT_USED,
265 USED_SUCCEEDED,
266 USED_REJECTED,
267 USED_CONN_ERROR,
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;
287 enum State {
288 INITIALIZING,
289 ZERORTT,
290 CONNECTED,
291 CLOSING,
292 CLOSED
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
305 // socket.
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
357 // a connection.
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
369 // are exchanged.
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__