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