xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/quic/core/http/web_transport_http3.h (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
1 // Copyright 2021 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4 
5 #ifndef QUICHE_QUIC_CORE_HTTP_WEB_TRANSPORT_HTTP3_H_
6 #define QUICHE_QUIC_CORE_HTTP_WEB_TRANSPORT_HTTP3_H_
7 
8 #include <memory>
9 #include <optional>
10 
11 #include "absl/base/attributes.h"
12 #include "absl/container/flat_hash_set.h"
13 #include "absl/time/time.h"
14 #include "quiche/quic/core/http/quic_spdy_session.h"
15 #include "quiche/quic/core/http/web_transport_stream_adapter.h"
16 #include "quiche/quic/core/quic_error_codes.h"
17 #include "quiche/quic/core/quic_stream.h"
18 #include "quiche/quic/core/quic_types.h"
19 #include "quiche/quic/core/web_transport_interface.h"
20 #include "quiche/quic/core/web_transport_stats.h"
21 #include "quiche/common/platform/api/quiche_mem_slice.h"
22 #include "quiche/common/quiche_callbacks.h"
23 #include "quiche/web_transport/web_transport.h"
24 #include "quiche/spdy/core/http2_header_block.h"
25 
26 namespace quic {
27 
28 class QuicSpdySession;
29 class QuicSpdyStream;
30 
31 enum class WebTransportHttp3RejectionReason {
32   kNone,
33   kNoStatusCode,
34   kWrongStatusCode,
35   kMissingDraftVersion,
36   kUnsupportedDraftVersion,
37 };
38 
39 // A session of WebTransport over HTTP/3.  The session is owned by
40 // QuicSpdyStream object for the CONNECT stream that established it.
41 //
42 // WebTransport over HTTP/3 specification:
43 // <https://datatracker.ietf.org/doc/html/draft-ietf-webtrans-http3>
44 class QUICHE_EXPORT WebTransportHttp3
45     : public WebTransportSession,
46       public QuicSpdyStream::Http3DatagramVisitor {
47  public:
48   WebTransportHttp3(QuicSpdySession* session, QuicSpdyStream* connect_stream,
49                     WebTransportSessionId id);
50 
51   void HeadersReceived(const spdy::Http2HeaderBlock& headers);
SetVisitor(std::unique_ptr<WebTransportVisitor> visitor)52   void SetVisitor(std::unique_ptr<WebTransportVisitor> visitor) {
53     visitor_ = std::move(visitor);
54   }
55 
id()56   WebTransportSessionId id() { return id_; }
ready()57   bool ready() { return ready_; }
58 
59   void AssociateStream(QuicStreamId stream_id);
OnStreamClosed(QuicStreamId stream_id)60   void OnStreamClosed(QuicStreamId stream_id) { streams_.erase(stream_id); }
61   void OnConnectStreamClosing();
62 
NumberOfAssociatedStreams()63   size_t NumberOfAssociatedStreams() { return streams_.size(); }
64 
65   void CloseSession(WebTransportSessionError error_code,
66                     absl::string_view error_message) override;
67   void OnCloseReceived(WebTransportSessionError error_code,
68                        absl::string_view error_message);
69   void OnConnectStreamFinReceived();
70 
71   // It is legal for WebTransport to be closed without a
72   // CLOSE_WEBTRANSPORT_SESSION capsule.  We always send a capsule, but we still
73   // need to ensure we handle this case correctly.
74   void CloseSessionWithFinOnlyForTests();
75 
76   // Return the earliest incoming stream that has been received by the session
77   // but has not been accepted.  Returns nullptr if there are no incoming
78   // streams.
79   WebTransportStream* AcceptIncomingBidirectionalStream() override;
80   WebTransportStream* AcceptIncomingUnidirectionalStream() override;
81 
82   bool CanOpenNextOutgoingBidirectionalStream() override;
83   bool CanOpenNextOutgoingUnidirectionalStream() override;
84   WebTransportStream* OpenOutgoingBidirectionalStream() override;
85   WebTransportStream* OpenOutgoingUnidirectionalStream() override;
86 
87   webtransport::Stream* GetStreamById(webtransport::StreamId id) override;
88 
89   webtransport::DatagramStatus SendOrQueueDatagram(
90       absl::string_view datagram) override;
91   QuicByteCount GetMaxDatagramSize() const override;
92   void SetDatagramMaxTimeInQueue(absl::Duration max_time_in_queue) override;
93 
GetDatagramStats()94   webtransport::DatagramStats GetDatagramStats() override {
95     return WebTransportDatagramStatsForQuicSession(*session_);
96   }
GetSessionStats()97   webtransport::SessionStats GetSessionStats() override {
98     return WebTransportStatsForQuicSession(*session_);
99   }
100 
101   void NotifySessionDraining() override;
SetOnDraining(quiche::SingleUseCallback<void ()> callback)102   void SetOnDraining(quiche::SingleUseCallback<void()> callback) override {
103     drain_callback_ = std::move(callback);
104   }
105 
106   // From QuicSpdyStream::Http3DatagramVisitor.
107   void OnHttp3Datagram(QuicStreamId stream_id,
108                        absl::string_view payload) override;
OnUnknownCapsule(QuicStreamId,const quiche::UnknownCapsule &)109   void OnUnknownCapsule(QuicStreamId /*stream_id*/,
110                         const quiche::UnknownCapsule& /*capsule*/) override {}
111 
close_received()112   bool close_received() const { return close_received_; }
rejection_reason()113   WebTransportHttp3RejectionReason rejection_reason() const {
114     return rejection_reason_;
115   }
116 
117   void OnGoAwayReceived();
118   void OnDrainSessionReceived();
119 
120  private:
121   // Notifies the visitor that the connection has been closed.  Ensures that the
122   // visitor is only ever called once.
123   void MaybeNotifyClose();
124 
125   QuicSpdySession* const session_;        // Unowned.
126   QuicSpdyStream* const connect_stream_;  // Unowned.
127   const WebTransportSessionId id_;
128   // |ready_| is set to true when the peer has seen both sets of headers.
129   bool ready_ = false;
130   std::unique_ptr<WebTransportVisitor> visitor_;
131   absl::flat_hash_set<QuicStreamId> streams_;
132   quiche::QuicheCircularDeque<QuicStreamId> incoming_bidirectional_streams_;
133   quiche::QuicheCircularDeque<QuicStreamId> incoming_unidirectional_streams_;
134 
135   bool close_sent_ = false;
136   bool close_received_ = false;
137   bool close_notified_ = false;
138 
139   quiche::SingleUseCallback<void()> drain_callback_ = nullptr;
140 
141   WebTransportHttp3RejectionReason rejection_reason_ =
142       WebTransportHttp3RejectionReason::kNone;
143   bool drain_sent_ = false;
144   // Those are set to default values, which are used if the session is not
145   // closed cleanly using an appropriate capsule.
146   WebTransportSessionError error_code_ = 0;
147   std::string error_message_ = "";
148 };
149 
150 class QUICHE_EXPORT WebTransportHttp3UnidirectionalStream : public QuicStream {
151  public:
152   // Incoming stream.
153   WebTransportHttp3UnidirectionalStream(PendingStream* pending,
154                                         QuicSpdySession* session);
155   // Outgoing stream.
156   WebTransportHttp3UnidirectionalStream(QuicStreamId id,
157                                         QuicSpdySession* session,
158                                         WebTransportSessionId session_id);
159 
160   // Sends the stream type and the session ID on the stream.
161   void WritePreamble();
162 
163   // Implementation of QuicStream.
164   void OnDataAvailable() override;
165   void OnCanWriteNewData() override;
166   void OnClose() override;
167   void OnStreamReset(const QuicRstStreamFrame& frame) override;
168   bool OnStopSending(QuicResetStreamError error) override;
169   void OnWriteSideInDataRecvdState() override;
170 
interface()171   WebTransportStream* interface() { return &adapter_; }
SetUnblocked()172   void SetUnblocked() { sequencer()->SetUnblocked(); }
173 
174  private:
175   QuicSpdySession* session_;
176   WebTransportStreamAdapter adapter_;
177   std::optional<WebTransportSessionId> session_id_;
178   bool needs_to_send_preamble_;
179 
180   bool ReadSessionId();
181   // Closes the stream if all of the data has been received.
182   void MaybeCloseIncompleteStream();
183 };
184 
185 // Remaps HTTP/3 error code into a WebTransport error code.  Returns nullopt if
186 // the provided code is outside of valid range.
187 QUICHE_EXPORT std::optional<WebTransportStreamError> Http3ErrorToWebTransport(
188     uint64_t http3_error_code);
189 
190 // Same as above, but returns default error value (zero) when none could be
191 // mapped.
192 QUICHE_EXPORT WebTransportStreamError
193 Http3ErrorToWebTransportOrDefault(uint64_t http3_error_code);
194 
195 // Remaps WebTransport error code into an HTTP/3 error code.
196 QUICHE_EXPORT uint64_t
197 WebTransportErrorToHttp3(WebTransportStreamError webtransport_error_code);
198 
199 }  // namespace quic
200 
201 #endif  // QUICHE_QUIC_CORE_HTTP_WEB_TRANSPORT_HTTP3_H_
202