Refactor WebTransport API to make it independent of QUIC.
This moves web_transport_interface.h types into their own namespace and directory, removes dependencies on QUIC types, and cleans the API in a bunch of other ways (notably, adds more documentation).
A notable functional outcome of this refactor is that we accept datagrams as string_views instead of memslices. For HTTP/3 use cases, this will typically reduce one copy, since we always copy the contents of the datagram while appending the stream ID.
PiperOrigin-RevId: 499584983
diff --git a/quiche/quic/core/http/end_to_end_test.cc b/quiche/quic/core/http/end_to_end_test.cc
index f3b7f03..80161dd 100644
--- a/quiche/quic/core/http/end_to_end_test.cc
+++ b/quiche/quic/core/http/end_to_end_test.cc
@@ -6759,7 +6759,7 @@
quiche::SimpleBufferAllocator allocator;
for (int i = 0; i < 10; i++) {
- session->SendOrQueueDatagram(MemSliceFromString("test"));
+ session->SendOrQueueDatagram("test");
}
int received = 0;
diff --git a/quiche/quic/core/http/web_transport_http3.cc b/quiche/quic/core/http/web_transport_http3.cc
index 84f1d33..d74071d 100644
--- a/quiche/quic/core/http/web_transport_http3.cc
+++ b/quiche/quic/core/http/web_transport_http3.cc
@@ -21,6 +21,7 @@
#include "quiche/quic/core/quic_versions.h"
#include "quiche/quic/platform/api/quic_bug_tracker.h"
#include "quiche/common/platform/api/quiche_logging.h"
+#include "quiche/web_transport/web_transport.h"
#define ENDPOINT \
(session_->perspective() == Perspective::IS_SERVER ? "Server: " : "Client: ")
@@ -266,10 +267,10 @@
return stream->interface();
}
-MessageStatus WebTransportHttp3::SendOrQueueDatagram(
- quiche::QuicheMemSlice datagram) {
- return connect_stream_->SendHttp3Datagram(
- absl::string_view(datagram.data(), datagram.length()));
+webtransport::DatagramStatus WebTransportHttp3::SendOrQueueDatagram(
+ absl::string_view datagram) {
+ return MessageStatusToWebTransportStatus(
+ connect_stream_->SendHttp3Datagram(datagram));
}
QuicByteCount WebTransportHttp3::GetMaxDatagramSize() const {
@@ -277,8 +278,9 @@
}
void WebTransportHttp3::SetDatagramMaxTimeInQueue(
- QuicTime::Delta max_time_in_queue) {
- connect_stream_->SetMaxDatagramTimeInQueue(max_time_in_queue);
+ absl::Duration max_time_in_queue) {
+ connect_stream_->SetMaxDatagramTimeInQueue(
+ QuicTime::Delta::FromAbsl(max_time_in_queue));
}
void WebTransportHttp3::OnHttp3Datagram(QuicStreamId stream_id,
diff --git a/quiche/quic/core/http/web_transport_http3.h b/quiche/quic/core/http/web_transport_http3.h
index 67c2fc8..8744449 100644
--- a/quiche/quic/core/http/web_transport_http3.h
+++ b/quiche/quic/core/http/web_transport_http3.h
@@ -9,6 +9,7 @@
#include "absl/base/attributes.h"
#include "absl/container/flat_hash_set.h"
+#include "absl/time/time.h"
#include "absl/types/optional.h"
#include "quiche/quic/core/http/quic_spdy_session.h"
#include "quiche/quic/core/http/web_transport_stream_adapter.h"
@@ -17,6 +18,7 @@
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/web_transport_interface.h"
#include "quiche/common/platform/api/quiche_mem_slice.h"
+#include "quiche/web_transport/web_transport.h"
#include "quiche/spdy/core/http2_header_block.h"
namespace quic {
@@ -80,9 +82,10 @@
WebTransportStream* OpenOutgoingBidirectionalStream() override;
WebTransportStream* OpenOutgoingUnidirectionalStream() override;
- MessageStatus SendOrQueueDatagram(quiche::QuicheMemSlice datagram) override;
+ webtransport::DatagramStatus SendOrQueueDatagram(
+ absl::string_view datagram) override;
QuicByteCount GetMaxDatagramSize() const override;
- void SetDatagramMaxTimeInQueue(QuicTime::Delta max_time_in_queue) override;
+ void SetDatagramMaxTimeInQueue(absl::Duration max_time_in_queue) override;
// From QuicSpdyStream::Http3DatagramVisitor.
void OnHttp3Datagram(QuicStreamId stream_id,
diff --git a/quiche/quic/core/http/web_transport_stream_adapter.cc b/quiche/quic/core/http/web_transport_stream_adapter.cc
index b6eca7b..24d7bf5 100644
--- a/quiche/quic/core/http/web_transport_stream_adapter.cc
+++ b/quiche/quic/core/http/web_transport_stream_adapter.cc
@@ -6,7 +6,9 @@
#include "quiche/quic/core/http/web_transport_http3.h"
#include "quiche/quic/core/quic_error_codes.h"
+#include "quiche/quic/core/quic_types.h"
#include "quiche/common/platform/api/quiche_mem_slice.h"
+#include "quiche/web_transport/web_transport.h"
namespace quic {
@@ -15,10 +17,10 @@
: session_(session), stream_(stream), sequencer_(sequencer) {}
WebTransportStream::ReadResult WebTransportStreamAdapter::Read(
- char* buffer, size_t buffer_size) {
+ absl::Span<char> buffer) {
iovec iov;
- iov.iov_base = buffer;
- iov.iov_len = buffer_size;
+ iov.iov_base = buffer.data();
+ iov.iov_len = buffer.size();
const size_t result = sequencer_->Readv(&iov, 1);
if (!fin_read_ && sequencer_->IsClosed()) {
fin_read_ = true;
@@ -32,7 +34,8 @@
const size_t old_size = output->size();
const size_t bytes_to_read = ReadableBytes();
output->resize(old_size + bytes_to_read);
- ReadResult result = Read(&(*output)[old_size], bytes_to_read);
+ ReadResult result =
+ Read(absl::Span<char>(&(*output)[old_size], bytes_to_read));
QUICHE_DCHECK_EQ(bytes_to_read, result.bytes_read);
output->resize(old_size + result.bytes_read);
return result;
diff --git a/quiche/quic/core/http/web_transport_stream_adapter.h b/quiche/quic/core/http/web_transport_stream_adapter.h
index 7e8eeea..621120b 100644
--- a/quiche/quic/core/http/web_transport_stream_adapter.h
+++ b/quiche/quic/core/http/web_transport_stream_adapter.h
@@ -10,6 +10,7 @@
#include "quiche/quic/core/quic_stream_sequencer.h"
#include "quiche/quic/core/quic_types.h"
#include "quiche/quic/core/web_transport_interface.h"
+#include "quiche/web_transport/web_transport.h"
namespace quic {
@@ -22,8 +23,7 @@
QuicStreamSequencer* sequencer);
// WebTransportStream implementation.
- ABSL_MUST_USE_RESULT ReadResult Read(char* buffer,
- size_t buffer_size) override;
+ ABSL_MUST_USE_RESULT ReadResult Read(absl::Span<char> output) override;
ABSL_MUST_USE_RESULT ReadResult Read(std::string* output) override;
ABSL_MUST_USE_RESULT bool Write(absl::string_view data) override;
ABSL_MUST_USE_RESULT bool SendFin() override;
diff --git a/quiche/quic/core/quic_time.h b/quiche/quic/core/quic_time.h
index 21bad68..a148888 100644
--- a/quiche/quic/core/quic_time.h
+++ b/quiche/quic/core/quic_time.h
@@ -19,6 +19,7 @@
#include <ostream>
#include <string>
+#include "absl/time/time.h"
#include "quiche/quic/platform/api/quic_export.h"
// TODO(vasilvv): replace with ABSL_MUST_USE_RESULT once we're using absl.
@@ -60,6 +61,14 @@
// Converts a number of microseconds to a time offset.
static constexpr Delta FromMicroseconds(int64_t us) { return Delta(us); }
+ // Converts from Abseil duration type.
+ static constexpr Delta FromAbsl(absl::Duration duration) {
+ if (ABSL_PREDICT_FALSE(duration == absl::InfiniteDuration())) {
+ return Infinite();
+ }
+ return Delta(absl::ToInt64Microseconds(duration));
+ }
+
// Converts the time offset to a rounded number of seconds.
constexpr int64_t ToSeconds() const { return time_offset_ / 1000 / 1000; }
@@ -69,6 +78,14 @@
// Converts the time offset to a rounded number of microseconds.
constexpr int64_t ToMicroseconds() const { return time_offset_; }
+ // Converts the time offset to an Abseil duration.
+ constexpr absl::Duration ToAbsl() {
+ if (ABSL_PREDICT_FALSE(IsInfinite())) {
+ return absl::InfiniteDuration();
+ }
+ return absl::Microseconds(time_offset_);
+ }
+
constexpr bool IsZero() const { return time_offset_ == 0; }
constexpr bool IsInfinite() const {
diff --git a/quiche/quic/core/web_transport_interface.h b/quiche/quic/core/web_transport_interface.h
index bfccf7d..f87768c 100644
--- a/quiche/quic/core/web_transport_interface.h
+++ b/quiche/quic/core/web_transport_interface.h
@@ -8,145 +8,41 @@
#ifndef QUICHE_QUIC_CORE_WEB_TRANSPORT_INTERFACE_H_
#define QUICHE_QUIC_CORE_WEB_TRANSPORT_INTERFACE_H_
-#include <cstddef>
-#include <memory>
-
-#include "absl/base/attributes.h"
-#include "absl/strings/string_view.h"
-#include "quiche/quic/core/quic_datagram_queue.h"
#include "quiche/quic/core/quic_types.h"
-#include "quiche/quic/platform/api/quic_export.h"
-#include "quiche/common/platform/api/quiche_mem_slice.h"
-#include "quiche/spdy/core/http2_header_block.h"
+#include "quiche/web_transport/web_transport.h"
namespace quic {
-// Visitor that gets notified about events related to a WebTransport stream.
-class QUIC_EXPORT_PRIVATE WebTransportStreamVisitor {
- public:
- virtual ~WebTransportStreamVisitor() {}
+using WebTransportSessionError = webtransport::SessionErrorCode;
+using WebTransportStreamError = webtransport::StreamErrorCode;
- // Called whenever the stream has readable data available.
- virtual void OnCanRead() = 0;
- // Called whenever the stream is not write-blocked and can accept new data.
- virtual void OnCanWrite() = 0;
+using WebTransportStreamVisitor = webtransport::StreamVisitor;
+using WebTransportStream = webtransport::Stream;
+using WebTransportVisitor = webtransport::SessionVisitor;
+using WebTransportSession = webtransport::Session;
- // Called when RESET_STREAM is received for the stream.
- virtual void OnResetStreamReceived(WebTransportStreamError error) = 0;
- // Called when STOP_SENDING is received for the stream.
- virtual void OnStopSendingReceived(WebTransportStreamError error) = 0;
- // Called when the write side of the stream is closed and all of the data sent
- // has been acknowledged ("Data Recvd" state of RFC 9000).
- virtual void OnWriteSideInDataRecvdState() = 0;
-};
-
-// A stream (either bidirectional or unidirectional) that is contained within a
-// WebTransport session.
-class QUIC_EXPORT_PRIVATE WebTransportStream {
- public:
- struct QUIC_EXPORT_PRIVATE ReadResult {
- // Number of bytes actually read.
- size_t bytes_read;
- // Whether the FIN has been received; if true, no further data will arrive
- // on the stream, and the stream object can be soon potentially garbage
- // collected.
- bool fin;
- };
-
- virtual ~WebTransportStream() {}
-
- // Reads at most |buffer_size| bytes into |buffer|.
- ABSL_MUST_USE_RESULT virtual ReadResult Read(char* buffer,
- size_t buffer_size) = 0;
- // Reads all available data and appends it to the end of |output|.
- ABSL_MUST_USE_RESULT virtual ReadResult Read(std::string* output) = 0;
- // Writes |data| into the stream. Returns true on success.
- ABSL_MUST_USE_RESULT virtual bool Write(absl::string_view data) = 0;
- // Sends the FIN on the stream. Returns true on success.
- ABSL_MUST_USE_RESULT virtual bool SendFin() = 0;
-
- // Indicates whether it is possible to write into stream right now.
- virtual bool CanWrite() const = 0;
- // Indicates the number of bytes that can be read from the stream.
- virtual size_t ReadableBytes() const = 0;
-
- // An ID that is unique within the session. Those are not exposed to the user
- // via the web API, but can be used internally for bookkeeping and
- // diagnostics.
- virtual QuicStreamId GetStreamId() const = 0;
-
- // Resets the stream with the specified error code.
- virtual void ResetWithUserCode(WebTransportStreamError error) = 0;
- virtual void ResetDueToInternalError() = 0;
- virtual void SendStopSending(WebTransportStreamError error) = 0;
- // Called when the owning object has been garbage-collected.
- virtual void MaybeResetDueToStreamObjectGone() = 0;
-
- virtual WebTransportStreamVisitor* visitor() = 0;
- virtual void SetVisitor(
- std::unique_ptr<WebTransportStreamVisitor> visitor) = 0;
-};
-
-// Visitor that gets notified about events related to a WebTransport session.
-class QUIC_EXPORT_PRIVATE WebTransportVisitor {
- public:
- virtual ~WebTransportVisitor() {}
-
- // Notifies the visitor when the session is ready to exchange application
- // data.
- virtual void OnSessionReady(const spdy::Http2HeaderBlock& headers) = 0;
-
- // Notifies the visitor when the session has been closed.
- virtual void OnSessionClosed(WebTransportSessionError error_code,
- const std::string& error_message) = 0;
-
- // Notifies the visitor when a new stream has been received. The stream in
- // question can be retrieved using AcceptIncomingBidirectionalStream() or
- // AcceptIncomingUnidirectionalStream().
- virtual void OnIncomingBidirectionalStreamAvailable() = 0;
- virtual void OnIncomingUnidirectionalStreamAvailable() = 0;
-
- // Notifies the visitor when a new datagram has been received.
- virtual void OnDatagramReceived(absl::string_view datagram) = 0;
-
- // Notifies the visitor that a new outgoing stream can now be created.
- virtual void OnCanCreateNewOutgoingBidirectionalStream() = 0;
- virtual void OnCanCreateNewOutgoingUnidirectionalStream() = 0;
-};
-
-// An abstract interface for a WebTransport session.
-class QUIC_EXPORT_PRIVATE WebTransportSession {
- public:
- virtual ~WebTransportSession() {}
-
- // Closes the WebTransport session in question with the specified |error_code|
- // and |error_message|.
- virtual void CloseSession(WebTransportSessionError error_code,
- absl::string_view error_message) = 0;
-
- // Return the earliest incoming stream that has been received by the session
- // but has not been accepted. Returns nullptr if there are no incoming
- // streams.
- virtual WebTransportStream* AcceptIncomingBidirectionalStream() = 0;
- virtual WebTransportStream* AcceptIncomingUnidirectionalStream() = 0;
-
- // Returns true if flow control allows opening a new stream.
- virtual bool CanOpenNextOutgoingBidirectionalStream() = 0;
- virtual bool CanOpenNextOutgoingUnidirectionalStream() = 0;
- // Opens a new WebTransport stream, or returns nullptr if that is not possible
- // due to flow control.
- virtual WebTransportStream* OpenOutgoingBidirectionalStream() = 0;
- virtual WebTransportStream* OpenOutgoingUnidirectionalStream() = 0;
-
- virtual MessageStatus SendOrQueueDatagram(
- quiche::QuicheMemSlice datagram) = 0;
- // Returns a conservative estimate of the largest datagram size that the
- // session would be able to send.
- virtual QuicByteCount GetMaxDatagramSize() const = 0;
- // Sets the largest duration that a datagram can spend in the queue before
- // being silently dropped.
- virtual void SetDatagramMaxTimeInQueue(QuicTime::Delta max_time_in_queue) = 0;
-};
+inline webtransport::DatagramStatus MessageStatusToWebTransportStatus(
+ MessageStatus status) {
+ switch (status) {
+ case MESSAGE_STATUS_SUCCESS:
+ return webtransport::DatagramStatus(
+ webtransport::DatagramStatusCode::kSuccess, "");
+ case MESSAGE_STATUS_BLOCKED:
+ return webtransport::DatagramStatus(
+ webtransport::DatagramStatusCode::kBlocked,
+ "QUIC connection write-blocked");
+ case MESSAGE_STATUS_TOO_LARGE:
+ return webtransport::DatagramStatus(
+ webtransport::DatagramStatusCode::kTooBig,
+ "Datagram payload exceeded maximum allowed size");
+ case MESSAGE_STATUS_ENCRYPTION_NOT_ESTABLISHED:
+ case MESSAGE_STATUS_INTERNAL_ERROR:
+ case MESSAGE_STATUS_UNSUPPORTED:
+ return webtransport::DatagramStatus(
+ webtransport::DatagramStatusCode::kInternalError,
+ absl::StrCat("Internal error: ", MessageStatusToString(status)));
+ }
+}
} // namespace quic
diff --git a/quiche/quic/tools/web_transport_test_visitors.h b/quiche/quic/tools/web_transport_test_visitors.h
index 368e53a..c311ff4 100644
--- a/quiche/quic/tools/web_transport_test_visitors.h
+++ b/quiche/quic/tools/web_transport_test_visitors.h
@@ -224,9 +224,7 @@
}
void OnDatagramReceived(absl::string_view datagram) override {
- quiche::QuicheMemSlice slice(
- quiche::QuicheBuffer::Copy(&allocator_, datagram));
- session_->SendOrQueueDatagram(std::move(slice));
+ session_->SendOrQueueDatagram(datagram);
}
void OnCanCreateNewOutgoingBidirectionalStream() override {