summaryrefslogtreecommitdiff
path: root/chromium/net/third_party/quiche/src/quic/tools
diff options
context:
space:
mode:
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/tools')
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client.cc9
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc11
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc44
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc51
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc16
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc8
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc25
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h17
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc31
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h10
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc40
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc67
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc97
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc23
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h11
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc2
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc3
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h3
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc129
-rw-r--r--chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h137
27 files changed, 527 insertions, 248 deletions
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h
index a7edd78e6f8..1c5cad87112 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_backend_response.h
@@ -50,11 +50,20 @@ class QuicBackendResponse {
~QuicBackendResponse();
+ const std::vector<spdy::Http2HeaderBlock>& early_hints() const {
+ return early_hints_;
+ }
SpecialResponseType response_type() const { return response_type_; }
const spdy::Http2HeaderBlock& headers() const { return headers_; }
const spdy::Http2HeaderBlock& trailers() const { return trailers_; }
const absl::string_view body() const { return absl::string_view(body_); }
+ void AddEarlyHints(const spdy::Http2HeaderBlock& headers) {
+ spdy::Http2HeaderBlock hints = headers.Clone();
+ hints[":status"] = "103";
+ early_hints_.push_back(std::move(hints));
+ }
+
void set_response_type(SpecialResponseType response_type) {
response_type_ = response_type;
}
@@ -70,6 +79,7 @@ class QuicBackendResponse {
}
private:
+ std::vector<spdy::Http2HeaderBlock> early_hints_;
SpecialResponseType response_type_;
spdy::Http2HeaderBlock headers_;
spdy::Http2HeaderBlock trailers_;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
index f8375ab3b13..e659b4a7b84 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client.cc
@@ -24,7 +24,6 @@
#include "quic/core/quic_server_id.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_logging.h"
-#include "quic/platform/api/quic_ptr_util.h"
#include "quic/platform/api/quic_socket_address.h"
#include "quic/tools/quic_simple_client_session.h"
@@ -67,7 +66,7 @@ QuicClient::QuicClient(QuicSocketAddress server_address,
supported_versions,
QuicConfig(),
epoll_server,
- QuicWrapUnique(new QuicClientEpollNetworkHelper(epoll_server, this)),
+ std::make_unique<QuicClientEpollNetworkHelper>(epoll_server, this),
std::move(proof_verifier),
nullptr) {}
@@ -83,7 +82,7 @@ QuicClient::QuicClient(QuicSocketAddress server_address,
supported_versions,
QuicConfig(),
epoll_server,
- QuicWrapUnique(new QuicClientEpollNetworkHelper(epoll_server, this)),
+ std::make_unique<QuicClientEpollNetworkHelper>(epoll_server, this),
std::move(proof_verifier),
std::move(session_cache)) {}
@@ -100,7 +99,7 @@ QuicClient::QuicClient(QuicSocketAddress server_address,
supported_versions,
config,
epoll_server,
- QuicWrapUnique(new QuicClientEpollNetworkHelper(epoll_server, this)),
+ std::make_unique<QuicClientEpollNetworkHelper>(epoll_server, this),
std::move(proof_verifier),
std::move(session_cache)) {}
@@ -165,7 +164,7 @@ std::unique_ptr<QuicSession> QuicClient::CreateQuicClientSession(
QuicConnection* connection) {
return std::make_unique<QuicSimpleClientSession>(
*config(), supported_versions, connection, server_id(), crypto_config(),
- push_promise_index(), drop_response_body());
+ push_promise_index(), drop_response_body(), enable_web_transport());
}
QuicClientEpollNetworkHelper* QuicClient::epoll_network_helper() {
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
index 1737f8cb549..7077f16506e 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_base.cc
@@ -147,7 +147,7 @@ bool QuicClientBase::Connect() {
num_attempts++;
}
if (session() == nullptr) {
- QUIC_BUG << "Missing session after Connect";
+ QUIC_BUG(quic_bug_10906_1) << "Missing session after Connect";
return false;
}
return session()->connection()->connected();
@@ -230,7 +230,8 @@ bool QuicClientBase::EncryptionBeingEstablished() {
bool QuicClientBase::WaitForEvents() {
if (!connected()) {
- QUIC_BUG << "Cannot call WaitForEvents on non-connected client";
+ QUIC_BUG(quic_bug_10906_2)
+ << "Cannot call WaitForEvents on non-connected client";
return false;
}
@@ -335,7 +336,8 @@ const QuicClientBase::NetworkHelper* QuicClientBase::network_helper() const {
void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
if (!connected()) {
- QUIC_BUG << "Cannot WaitForStreamToClose on non-connected client";
+ QUIC_BUG(quic_bug_10906_3)
+ << "Cannot WaitForStreamToClose on non-connected client";
return;
}
@@ -346,7 +348,8 @@ void QuicClientBase::WaitForStreamToClose(QuicStreamId id) {
bool QuicClientBase::WaitForOneRttKeysAvailable() {
if (!connected()) {
- QUIC_BUG << "Cannot WaitForOneRttKeysAvailable on non-connected client";
+ QUIC_BUG(quic_bug_10906_4)
+ << "Cannot WaitForOneRttKeysAvailable on non-connected client";
return false;
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
index f67a338b09c..eee0ae7f891 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_client_interop_test_bin.cc
@@ -25,6 +25,12 @@ DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
"",
"The IP or hostname to connect to.");
+DEFINE_QUIC_COMMAND_LINE_FLAG(
+ std::string,
+ quic_version,
+ "",
+ "The QUIC version to use. Defaults to most recent IETF QUIC version.");
+
DEFINE_QUIC_COMMAND_LINE_FLAG(int32_t, port, 0, "The port to connect to.");
namespace quic {
@@ -366,21 +372,8 @@ void QuicClientInteropRunner::SendRequest(
std::set<Feature> ServerSupport(std::string dns_host,
std::string url_host,
- int port) {
- // Enable IETF version support.
- QuicVersionInitializeSupportForIetfDraft();
- ParsedQuicVersion version = UnsupportedQuicVersion();
- for (const ParsedQuicVersion& vers : AllSupportedVersions()) {
- // Find the first version that supports IETF QUIC.
- if (vers.HasIetfQuicFrames() &&
- vers.handshake_protocol == quic::PROTOCOL_TLS1_3) {
- version = vers;
- break;
- }
- }
- QUICHE_CHECK(version.IsKnown());
- QuicEnableVersion(version);
-
+ int port,
+ ParsedQuicVersion version) {
std::cout << "Attempting interop with version " << version << std::endl;
// Build the client, and try to connect.
@@ -440,7 +433,26 @@ int main(int argc, char* argv[]) {
url_host = dns_host;
}
- auto supported_features = quic::ServerSupport(dns_host, url_host, port);
+ // Pick QUIC version to use.
+ quic::QuicVersionInitializeSupportForIetfDraft();
+ quic::ParsedQuicVersion version = quic::UnsupportedQuicVersion();
+ std::string quic_version_string = GetQuicFlag(FLAGS_quic_version);
+ if (!quic_version_string.empty()) {
+ version = quic::ParseQuicVersionString(quic_version_string);
+ } else {
+ for (const quic::ParsedQuicVersion& vers : quic::AllSupportedVersions()) {
+ // Use the most recent IETF QUIC version.
+ if (vers.HasIetfQuicFrames() && vers.UsesHttp3() && vers.UsesTls()) {
+ version = vers;
+ break;
+ }
+ }
+ }
+ QUICHE_CHECK(version.IsKnown());
+ QuicEnableVersion(version);
+
+ auto supported_features =
+ quic::ServerSupport(dns_host, url_host, port, version);
std::cout << "Results for " << url_host << ":" << port << std::endl;
int current_row = 1;
for (auto feature : supported_features) {
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc
index c67e5b35be8..e76a6cffb3c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.cc
@@ -8,6 +8,7 @@
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quic/core/http/spdy_utils.h"
#include "quic/platform/api/quic_bug_tracker.h"
@@ -171,10 +172,8 @@ void QuicMemoryCacheBackend::AddSimpleResponse(absl::string_view host,
int response_code,
absl::string_view body) {
Http2HeaderBlock response_headers;
- response_headers[":status"] =
- quiche::QuicheTextUtils::Uint64ToString(response_code);
- response_headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(body.length());
+ response_headers[":status"] = absl::StrCat(response_code);
+ response_headers["content-length"] = absl::StrCat(body.length());
AddResponse(host, path, std::move(response_headers), body);
}
@@ -199,7 +198,7 @@ void QuicMemoryCacheBackend::AddResponse(absl::string_view host,
absl::string_view response_body) {
AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
std::move(response_headers), response_body,
- Http2HeaderBlock());
+ Http2HeaderBlock(), std::vector<spdy::Http2HeaderBlock>());
}
void QuicMemoryCacheBackend::AddResponse(absl::string_view host,
@@ -209,7 +208,19 @@ void QuicMemoryCacheBackend::AddResponse(absl::string_view host,
Http2HeaderBlock response_trailers) {
AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
std::move(response_headers), response_body,
- std::move(response_trailers));
+ std::move(response_trailers),
+ std::vector<spdy::Http2HeaderBlock>());
+}
+
+void QuicMemoryCacheBackend::AddResponseWithEarlyHints(
+ absl::string_view host,
+ absl::string_view path,
+ spdy::Http2HeaderBlock response_headers,
+ absl::string_view response_body,
+ const std::vector<spdy::Http2HeaderBlock>& early_hints) {
+ AddResponseImpl(host, path, QuicBackendResponse::REGULAR_RESPONSE,
+ std::move(response_headers), response_body,
+ Http2HeaderBlock(), early_hints);
}
void QuicMemoryCacheBackend::AddSpecialResponse(
@@ -217,7 +228,7 @@ void QuicMemoryCacheBackend::AddSpecialResponse(
absl::string_view path,
SpecialResponseType response_type) {
AddResponseImpl(host, path, response_type, Http2HeaderBlock(), "",
- Http2HeaderBlock());
+ Http2HeaderBlock(), std::vector<spdy::Http2HeaderBlock>());
}
void QuicMemoryCacheBackend::AddSpecialResponse(
@@ -227,7 +238,8 @@ void QuicMemoryCacheBackend::AddSpecialResponse(
absl::string_view response_body,
SpecialResponseType response_type) {
AddResponseImpl(host, path, response_type, std::move(response_headers),
- response_body, Http2HeaderBlock());
+ response_body, Http2HeaderBlock(),
+ std::vector<spdy::Http2HeaderBlock>());
}
QuicMemoryCacheBackend::QuicMemoryCacheBackend() : cache_initialized_(false) {}
@@ -235,7 +247,7 @@ QuicMemoryCacheBackend::QuicMemoryCacheBackend() : cache_initialized_(false) {}
bool QuicMemoryCacheBackend::InitializeBackend(
const std::string& cache_directory) {
if (cache_directory.empty()) {
- QUIC_BUG << "cache_directory must not be empty.";
+ QUIC_BUG(quic_bug_10932_1) << "cache_directory must not be empty.";
return false;
}
QUIC_LOG(INFO)
@@ -274,7 +286,8 @@ bool QuicMemoryCacheBackend::InitializeBackend(
QuicUrl url(push_url);
const QuicBackendResponse* response = GetResponse(url.host(), url.path());
if (!response) {
- QUIC_BUG << "Push URL '" << push_url << "' not found.";
+ QUIC_BUG(quic_bug_10932_2)
+ << "Push URL '" << push_url << "' not found.";
return false;
}
push_resources.push_back(ServerPushInfo(url, response->headers().Clone(),
@@ -316,8 +329,13 @@ void QuicMemoryCacheBackend::FetchResponseFromBackend(
quic_response = GetResponse(authority->second, path->second);
}
- std::string request_url =
- std::string(authority->second) + std::string(path->second);
+ std::string request_url;
+ if (authority != request_headers.end()) {
+ request_url = std::string(authority->second);
+ }
+ if (path != request_headers.end()) {
+ request_url += std::string(path->second);
+ }
std::list<ServerPushInfo> resources = GetServerPushResources(request_url);
QUIC_DVLOG(1)
<< "Fetching QUIC response from backend in-memory cache for url "
@@ -356,14 +374,16 @@ void QuicMemoryCacheBackend::AddResponseImpl(
SpecialResponseType response_type,
Http2HeaderBlock response_headers,
absl::string_view response_body,
- Http2HeaderBlock response_trailers) {
+ Http2HeaderBlock response_trailers,
+ const std::vector<spdy::Http2HeaderBlock>& early_hints) {
QuicWriterMutexLock lock(&response_mutex_);
QUICHE_DCHECK(!host.empty())
<< "Host must be populated, e.g. \"www.google.com\"";
std::string key = GetKey(host, path);
if (QuicContainsKey(responses_, key)) {
- QUIC_BUG << "Response for '" << key << "' already exists!";
+ QUIC_BUG(quic_bug_10932_3)
+ << "Response for '" << key << "' already exists!";
return;
}
auto new_response = std::make_unique<QuicBackendResponse>();
@@ -371,6 +391,9 @@ void QuicMemoryCacheBackend::AddResponseImpl(
new_response->set_headers(std::move(response_headers));
new_response->set_body(response_body);
new_response->set_trailers(std::move(response_trailers));
+ for (auto& headers : early_hints) {
+ new_response->AddEarlyHints(headers);
+ }
QUIC_DVLOG(1) << "Add response with key " << key;
responses_[key] = std::move(new_response);
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
index 5e4b2674dd9..8ba6d605218 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend.h
@@ -110,6 +110,14 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend {
absl::string_view response_body,
spdy::Http2HeaderBlock response_trailers);
+ // Add a response, with 103 Early Hints, to the cache.
+ void AddResponseWithEarlyHints(
+ absl::string_view host,
+ absl::string_view path,
+ spdy::Http2HeaderBlock response_headers,
+ absl::string_view response_body,
+ const std::vector<spdy::Http2HeaderBlock>& early_hints);
+
// Simulate a special behavior at a particular path.
void AddSpecialResponse(
absl::string_view host,
@@ -152,7 +160,8 @@ class QuicMemoryCacheBackend : public QuicSimpleServerBackend {
QuicBackendResponse::SpecialResponseType response_type,
spdy::Http2HeaderBlock response_headers,
absl::string_view response_body,
- spdy::Http2HeaderBlock response_trailers);
+ spdy::Http2HeaderBlock response_trailers,
+ const std::vector<spdy::Http2HeaderBlock>& early_hints);
std::string GetKey(absl::string_view host, absl::string_view path) const;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc
index e86bb872b47..d0383e19b6e 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_memory_cache_backend_test.cc
@@ -10,7 +10,6 @@
#include "quic/platform/api/quic_map_util.h"
#include "quic/platform/api/quic_test.h"
#include "quic/tools/quic_backend_response.h"
-#include "common/platform/api/quiche_text_utils.h"
namespace quic {
namespace test {
@@ -62,8 +61,7 @@ TEST_F(QuicMemoryCacheBackendTest, AddResponse) {
spdy::Http2HeaderBlock response_headers;
response_headers[":status"] = "200";
- response_headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(kResponseBody.size());
+ response_headers["content-length"] = absl::StrCat(kResponseBody.size());
spdy::Http2HeaderBlock response_trailers;
response_trailers["key-1"] = "value-1";
@@ -184,16 +182,14 @@ TEST_F(QuicMemoryCacheBackendTest, AddSimpleResponseWithServerPushResources) {
std::list<ServerPushInfo> push_resources;
std::string scheme = "http";
for (int i = 0; i < NumResources; ++i) {
- std::string path =
- "/server_push_src" + quiche::QuicheTextUtils::Uint64ToString(i);
+ std::string path = absl::StrCat("/server_push_src", i);
std::string url = scheme + "://" + request_host + path;
QuicUrl resource_url(url);
std::string body =
absl::StrCat("This is server push response body for ", path);
spdy::Http2HeaderBlock response_headers;
response_headers[":status"] = "200";
- response_headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(body.size());
+ response_headers["content-length"] = absl::StrCat(body.size());
push_resources.push_back(
ServerPushInfo(resource_url, response_headers.Clone(), i, body));
}
@@ -224,15 +220,13 @@ TEST_F(QuicMemoryCacheBackendTest, GetServerPushResourcesAndPushResponses) {
"404"};
std::list<ServerPushInfo> push_resources;
for (int i = 0; i < NumResources; ++i) {
- std::string path =
- "/server_push_src" + quiche::QuicheTextUtils::Uint64ToString(i);
+ std::string path = absl::StrCat("/server_push_src", i);
std::string url = scheme + "://" + request_host + path;
QuicUrl resource_url(url);
std::string body = "This is server push response body for " + path;
spdy::Http2HeaderBlock response_headers;
response_headers[":status"] = push_response_status[i];
- response_headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(body.size());
+ response_headers["content-length"] = absl::StrCat(body.size());
push_resources.push_back(
ServerPushInfo(resource_url, response_headers.Clone(), i, body));
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
index 9d67b09e5e8..97ca71e9c6f 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_packet_printer_bin.cc
@@ -28,12 +28,13 @@
#include <iostream>
+#include "absl/strings/escaping.h"
+#include "absl/strings/string_view.h"
#include "quic/core/quic_framer.h"
+#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "common/platform/api/quiche_text_utils.h"
-#include "absl/strings/string_view.h"
-#include "absl/strings/escaping.h"
DEFINE_QUIC_COMMAND_LINE_FLAG(std::string,
quic_version,
@@ -213,7 +214,8 @@ class QuicPacketPrinter : public QuicFramerVisitorInterface {
return true;
}
void OnPacketComplete() override { std::cerr << "OnPacketComplete\n"; }
- bool IsValidStatelessResetToken(QuicUint128 /*token*/) const override {
+ bool IsValidStatelessResetToken(
+ const StatelessResetToken& /*token*/) const override {
std::cerr << "IsValidStatelessResetToken\n";
return false;
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc
index 6ed8e994bea..c9713670a9c 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_server_bin.cc
@@ -9,10 +9,12 @@
#include "quic/core/quic_versions.h"
#include "quic/platform/api/quic_flags.h"
+#include "quic/platform/api/quic_system_event_loop.h"
#include "quic/tools/quic_epoll_server_factory.h"
#include "quic/tools/quic_toy_server.h"
int main(int argc, char* argv[]) {
+ QuicSystemEventLoop event_loop("quic_server");
const char* usage = "Usage: quic_server [options]";
std::vector<std::string> non_option_args =
quic::QuicParseCommandLineFlags(usage, argc, argv);
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc
index 7f64495f0fd..d1efcba4fe0 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.cc
@@ -16,13 +16,32 @@ QuicSimpleClientSession::QuicSimpleClientSession(
QuicCryptoClientConfig* crypto_config,
QuicClientPushPromiseIndex* push_promise_index,
bool drop_response_body)
+ : QuicSimpleClientSession(config,
+ supported_versions,
+ connection,
+ server_id,
+ crypto_config,
+ push_promise_index,
+ drop_response_body,
+ /*enable_web_transport=*/false) {}
+
+QuicSimpleClientSession::QuicSimpleClientSession(
+ const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection,
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* crypto_config,
+ QuicClientPushPromiseIndex* push_promise_index,
+ bool drop_response_body,
+ bool enable_web_transport)
: QuicSpdyClientSession(config,
supported_versions,
connection,
server_id,
crypto_config,
push_promise_index),
- drop_response_body_(drop_response_body) {}
+ drop_response_body_(drop_response_body),
+ enable_web_transport_(enable_web_transport) {}
std::unique_ptr<QuicSpdyClientStream>
QuicSimpleClientSession::CreateClientStream() {
@@ -31,4 +50,8 @@ QuicSimpleClientSession::CreateClientStream() {
drop_response_body_);
}
+bool QuicSimpleClientSession::ShouldNegotiateWebTransport() {
+ return enable_web_transport_;
+}
+
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h
index 5b5314183f8..aa86d9a83c9 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_client_session.h
@@ -19,11 +19,21 @@ class QuicSimpleClientSession : public QuicSpdyClientSession {
QuicCryptoClientConfig* crypto_config,
QuicClientPushPromiseIndex* push_promise_index,
bool drop_response_body);
+ QuicSimpleClientSession(const QuicConfig& config,
+ const ParsedQuicVersionVector& supported_versions,
+ QuicConnection* connection,
+ const QuicServerId& server_id,
+ QuicCryptoClientConfig* crypto_config,
+ QuicClientPushPromiseIndex* push_promise_index,
+ bool drop_response_body,
+ bool enable_web_transport);
std::unique_ptr<QuicSpdyClientStream> CreateClientStream() override;
+ bool ShouldNegotiateWebTransport() override;
private:
const bool drop_response_body_;
+ const bool enable_web_transport_;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc
index 736c061a2db..aa9a9c1e616 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.cc
@@ -53,7 +53,8 @@ std::unique_ptr<QuicSession> QuicSimpleDispatcher::CreateQuicSession(
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
absl::string_view /*alpn*/,
- const ParsedQuicVersion& version) {
+ const ParsedQuicVersion& version,
+ absl::string_view /*sni*/) {
// The QuicServerSessionBase takes ownership of |connection| below.
QuicConnection* connection =
new QuicConnection(connection_id, self_address, peer_address, helper(),
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h
index a629d3cd299..c790f21a140 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_dispatcher.h
@@ -36,7 +36,8 @@ class QuicSimpleDispatcher : public QuicDispatcher {
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
absl::string_view alpn,
- const ParsedQuicVersion& version) override;
+ const ParsedQuicVersion& version,
+ absl::string_view sni) override;
QuicSimpleServerBackend* server_backend() {
return quic_simple_server_backend_;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h
index 9e16d4e9a88..43ced4bcefb 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_backend.h
@@ -5,7 +5,10 @@
#ifndef QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_BACKEND_H_
#define QUICHE_QUIC_TOOLS_QUIC_SIMPLE_SERVER_BACKEND_H_
+#include <memory>
+
#include "quic/core/quic_types.h"
+#include "quic/core/web_transport_interface.h"
#include "quic/tools/quic_backend_response.h"
#include "spdy/core/spdy_header_block.h"
@@ -33,6 +36,11 @@ class QuicSimpleServerBackend {
std::list<QuicBackendResponse::ServerPushInfo> resources) = 0;
};
+ struct WebTransportResponse {
+ spdy::Http2HeaderBlock response_headers;
+ std::unique_ptr<WebTransportVisitor> visitor;
+ };
+
virtual ~QuicSimpleServerBackend() = default;
// This method initializes the backend instance to fetch responses
// from a backend server, in-memory cache etc.
@@ -51,6 +59,15 @@ class QuicSimpleServerBackend {
RequestHandler* request_handler) = 0;
// Clears the state of the backend instance
virtual void CloseBackendResponseStream(RequestHandler* request_handler) = 0;
+
+ virtual WebTransportResponse ProcessWebTransportRequest(
+ const spdy::Http2HeaderBlock& /*request_headers*/,
+ WebTransportSession* /*session*/) {
+ WebTransportResponse response;
+ response.response_headers[":status"] = "400";
+ return response;
+ }
+ virtual bool SupportsWebTransport() { return false; }
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
index 044998c9e16..4075d3ff417 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.cc
@@ -6,12 +6,13 @@
#include <utility>
+#include "absl/memory/memory.h"
+#include "quic/core/http/quic_server_initiated_spdy_stream.h"
#include "quic/core/http/quic_spdy_session.h"
#include "quic/core/quic_connection.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
-#include "quic/platform/api/quic_ptr_util.h"
#include "quic/tools/quic_simple_server_stream.h"
namespace quic {
@@ -51,7 +52,7 @@ QuicSimpleServerSession::CreateQuicCryptoServerStream(
}
void QuicSimpleServerSession::OnStreamFrame(const QuicStreamFrame& frame) {
- if (!IsIncomingStream(frame.stream_id)) {
+ if (!IsIncomingStream(frame.stream_id) && !WillNegotiateWebTransport()) {
QUIC_LOG(WARNING) << "Client shouldn't send data on server push stream";
connection()->CloseConnection(
QUIC_INVALID_STREAM_ID, "Client sent data on server push stream",
@@ -101,7 +102,7 @@ QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(QuicStreamId id) {
QuicSpdyStream* stream = new QuicSimpleServerStream(
id, this, BIDIRECTIONAL, quic_simple_server_backend_);
- ActivateStream(QuicWrapUnique(stream));
+ ActivateStream(absl::WrapUnique(stream));
return stream;
}
@@ -109,14 +110,26 @@ QuicSpdyStream* QuicSimpleServerSession::CreateIncomingStream(
PendingStream* pending) {
QuicSpdyStream* stream = new QuicSimpleServerStream(
pending, this, BIDIRECTIONAL, quic_simple_server_backend_);
- ActivateStream(QuicWrapUnique(stream));
+ ActivateStream(absl::WrapUnique(stream));
return stream;
}
-QuicSimpleServerStream*
-QuicSimpleServerSession::CreateOutgoingBidirectionalStream() {
- QUICHE_DCHECK(false);
- return nullptr;
+QuicSpdyStream* QuicSimpleServerSession::CreateOutgoingBidirectionalStream() {
+ if (!WillNegotiateWebTransport()) {
+ QUIC_BUG(QuicSimpleServerSession CreateOutgoingBidirectionalStream without
+ WebTransport support)
+ << "QuicSimpleServerSession::CreateOutgoingBidirectionalStream called "
+ "in a session without WebTransport support.";
+ return nullptr;
+ }
+ if (!ShouldCreateOutgoingBidirectionalStream()) {
+ return nullptr;
+ }
+
+ QuicServerInitiatedSpdyStream* stream = new QuicServerInitiatedSpdyStream(
+ GetNextOutgoingBidirectionalStreamId(), this, BIDIRECTIONAL);
+ ActivateStream(absl::WrapUnique(stream));
+ return stream;
}
QuicSimpleServerStream*
@@ -128,7 +141,7 @@ QuicSimpleServerSession::CreateOutgoingUnidirectionalStream() {
QuicSimpleServerStream* stream = new QuicSimpleServerStream(
GetNextOutgoingUnidirectionalStreamId(), this, WRITE_UNIDIRECTIONAL,
quic_simple_server_backend_);
- ActivateStream(QuicWrapUnique(stream));
+ ActivateStream(absl::WrapUnique(stream));
return stream;
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h
index 49aaae56b37..b91966da722 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session.h
@@ -85,7 +85,7 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
// QuicSession methods:
QuicSpdyStream* CreateIncomingStream(QuicStreamId id) override;
QuicSpdyStream* CreateIncomingStream(PendingStream* pending) override;
- QuicSimpleServerStream* CreateOutgoingBidirectionalStream() override;
+ QuicSpdyStream* CreateOutgoingBidirectionalStream() override;
QuicSimpleServerStream* CreateOutgoingUnidirectionalStream() override;
// Override to return true for locally preserved server push stream.
void HandleFrameOnNonexistentOutgoingStream(QuicStreamId stream_id) override;
@@ -104,6 +104,14 @@ class QuicSimpleServerSession : public QuicServerSessionBase {
void MaybeInitializeHttp3UnidirectionalStreams() override;
+ bool ShouldNegotiateWebTransport() override {
+ return quic_simple_server_backend_->SupportsWebTransport();
+ }
+ bool ShouldNegotiateHttp3Datagram() override {
+ return QuicServerSessionBase::ShouldNegotiateHttp3Datagram() ||
+ ShouldNegotiateWebTransport();
+ }
+
private:
friend class test::QuicSimpleServerSessionPeer;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
index 80d3a930349..62bbae949d5 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_session_test.cc
@@ -8,6 +8,7 @@
#include <memory>
#include <utility>
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quic/core/crypto/null_encrypter.h"
#include "quic/core/crypto/quic_crypto_server_config.h"
@@ -37,7 +38,6 @@
#include "quic/tools/quic_backend_response.h"
#include "quic/tools/quic_memory_cache_backend.h"
#include "quic/tools/quic_simple_server_stream.h"
-#include "common/platform/api/quiche_text_utils.h"
using testing::_;
using testing::AnyNumber;
@@ -135,9 +135,9 @@ QuicCryptoServerStreamBase* CreateMockCryptoServerStream(
case PROTOCOL_UNSUPPORTED:
break;
}
- QUIC_BUG << "Unknown handshake protocol: "
- << static_cast<int>(
- session->connection()->version().handshake_protocol);
+ QUIC_BUG(quic_bug_10933_1)
+ << "Unknown handshake protocol: "
+ << static_cast<int>(session->connection()->version().handshake_protocol);
return nullptr;
}
@@ -699,8 +699,7 @@ class QuicSimpleServerSessionServerPushTest
} else {
stream_id = GetNthServerInitiatedUnidirectionalId(i - 1);
}
- std::string path = partial_push_resource_path +
- quiche::QuicheTextUtils::Uint64ToString(i);
+ std::string path = absl::StrCat(partial_push_resource_path, i);
std::string url = scheme + "://" + resource_host + path;
QuicUrl resource_url = QuicUrl(url);
std::string body(body_size, 'a');
@@ -774,19 +773,26 @@ class QuicSimpleServerSessionServerPushTest
}
};
+ParsedQuicVersionVector SupportedVersionsWithPush() {
+ ParsedQuicVersionVector versions;
+ for (const ParsedQuicVersion& version : AllSupportedVersions()) {
+ if (!version.UsesHttp3()) {
+ // Push over HTTP/3 is not supported.
+ versions.push_back(version);
+ }
+ }
+ return versions;
+}
+
INSTANTIATE_TEST_SUITE_P(Tests,
QuicSimpleServerSessionServerPushTest,
- ::testing::ValuesIn(AllSupportedVersions()));
+ ::testing::ValuesIn(SupportedVersionsWithPush()));
// Tests that given more than kMaxStreamsForTest resources, all their
// PUSH_PROMISE's will be sent out and only kMaxStreamsForTest streams will be
// opened and send push response.
TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
MaybeConsumeHeadersStreamData();
- if (VersionUsesHttp3(transport_version())) {
- session_->EnableServerPush();
- session_->OnMaxPushIdFrame(kMaxQuicStreamId);
- }
size_t num_resources = kMaxStreamsForTest + 5;
PromisePushResources(num_resources);
EXPECT_EQ(kMaxStreamsForTest,
@@ -798,10 +804,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest, TestPromisePushResources) {
TEST_P(QuicSimpleServerSessionServerPushTest,
HandlePromisedPushRequestsAfterStreamDraining) {
MaybeConsumeHeadersStreamData();
- if (VersionUsesHttp3(transport_version())) {
- session_->EnableServerPush();
- session_->OnMaxPushIdFrame(kMaxQuicStreamId);
- }
size_t num_resources = kMaxStreamsForTest + 1;
QuicByteCount data_frame_header_length = PromisePushResources(num_resources);
QuicStreamId next_out_going_stream_id;
@@ -879,10 +881,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
return;
}
MaybeConsumeHeadersStreamData();
- if (VersionUsesHttp3(transport_version())) {
- session_->EnableServerPush();
- session_->OnMaxPushIdFrame(kMaxQuicStreamId);
- }
// Having two extra resources to be send later. One of them will be reset, so
// when opened stream become close, only one will become open.
@@ -969,10 +967,6 @@ TEST_P(QuicSimpleServerSessionServerPushTest,
TEST_P(QuicSimpleServerSessionServerPushTest,
CloseStreamToHandleMorePromisedStream) {
MaybeConsumeHeadersStreamData();
- if (VersionUsesHttp3(transport_version())) {
- session_->EnableServerPush();
- session_->OnMaxPushIdFrame(kMaxQuicStreamId);
- }
size_t num_resources = kMaxStreamsForTest + 1;
if (VersionHasIetfQuicFrames(transport_version())) {
// V99 will send out a stream-id-blocked frame when the we desired to exceed
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
index 800608bf0ba..f4afeb241c0 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.cc
@@ -9,16 +9,17 @@
#include "absl/strings/match.h"
#include "absl/strings/numbers.h"
+#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "quic/core/http/quic_spdy_stream.h"
#include "quic/core/http/spdy_utils.h"
+#include "quic/core/http/web_transport_http3.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_bug_tracker.h"
#include "quic/platform/api/quic_flags.h"
#include "quic/platform/api/quic_logging.h"
#include "quic/platform/api/quic_map_util.h"
#include "quic/tools/quic_simple_server_session.h"
-#include "common/platform/api/quiche_text_utils.h"
#include "spdy/core/spdy_protocol.h"
using spdy::Http2HeaderBlock;
@@ -64,7 +65,7 @@ void QuicSimpleServerStream::OnInitialHeadersComplete(
SendErrorResponse();
}
ConsumeHeaderList();
- if (!fin) {
+ if (!fin && !response_sent_) {
// CONNECT and other CONNECT-like methods (such as CONNECT-UDP) require
// sending the response right after parsing the headers even though the FIN
// bit has not been received on the request stream.
@@ -80,7 +81,7 @@ void QuicSimpleServerStream::OnTrailingHeadersComplete(
bool /*fin*/,
size_t /*frame_len*/,
const QuicHeaderList& /*header_list*/) {
- QUIC_BUG << "Server does not support receiving Trailers.";
+ QUIC_BUG(quic_bug_10962_1) << "Server does not support receiving Trailers.";
SendErrorResponse();
}
@@ -124,7 +125,8 @@ void QuicSimpleServerStream::PushResponse(
Http2HeaderBlock push_request_headers) {
if (QuicUtils::IsClientInitiatedStreamId(session()->transport_version(),
id())) {
- QUIC_BUG << "Client initiated stream shouldn't be used as promised stream.";
+ QUIC_BUG(quic_bug_10962_2)
+ << "Client initiated stream shouldn't be used as promised stream.";
return;
}
// Change the stream state to emulate a client request.
@@ -153,19 +155,46 @@ void QuicSimpleServerStream::SendResponse() {
return;
}
- if (!QuicContainsKey(request_headers_, ":authority") ||
- !QuicContainsKey(request_headers_, ":path")) {
- QUIC_DVLOG(1) << "Request headers do not contain :authority or :path.";
+ if (!QuicContainsKey(request_headers_, ":authority")) {
+ QUIC_DVLOG(1) << "Request headers do not contain :authority.";
SendErrorResponse();
return;
}
+ if (!QuicContainsKey(request_headers_, ":path")) {
+ // CONNECT and other CONNECT-like methods (such as CONNECT-UDP) do not all
+ // require :path to be present.
+ auto it = request_headers_.find(":method");
+ if (it == request_headers_.end() ||
+ !absl::StartsWith(it->second, "CONNECT")) {
+ QUIC_DVLOG(1) << "Request headers do not contain :path.";
+ SendErrorResponse();
+ return;
+ }
+ }
+
if (quic_simple_server_backend_ == nullptr) {
QUIC_DVLOG(1) << "Backend is missing.";
SendErrorResponse();
return;
}
+ if (web_transport() != nullptr) {
+ QuicSimpleServerBackend::WebTransportResponse response =
+ quic_simple_server_backend_->ProcessWebTransportRequest(
+ request_headers_, web_transport());
+ if (response.response_headers[":status"] == "200") {
+ WriteHeaders(std::move(response.response_headers), false, nullptr);
+ if (response.visitor != nullptr) {
+ web_transport()->SetVisitor(std::move(response.visitor));
+ }
+ web_transport()->HeadersReceived(request_headers_);
+ } else {
+ WriteHeaders(std::move(response.response_headers), true, nullptr);
+ }
+ return;
+ }
+
// Fetch the response from the backend interface and wait for callback once
// response is ready
quic_simple_server_backend_->FetchResponseFromBackend(request_headers_, body_,
@@ -193,6 +222,13 @@ void QuicSimpleServerStream::OnResponseBackendComplete(
return;
}
+ // Send Early Hints first.
+ for (const auto& headers : response->early_hints()) {
+ QUIC_DVLOG(1) << "Stream " << id() << " sending an Early Hints response: "
+ << headers.DebugString();
+ WriteHeaders(headers.Clone(), false, nullptr);
+ }
+
if (response->response_type() == QuicBackendResponse::CLOSE_CONNECTION) {
QUIC_DVLOG(1) << "Special response: closing connection.";
OnUnrecoverableError(QUIC_NO_ERROR, "Toy server forcing close");
@@ -275,10 +311,11 @@ void QuicSimpleServerStream::OnResponseBackendComplete(
return;
}
Http2HeaderBlock headers = response->headers().Clone();
- headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(generate_bytes_length_);
+ headers["content-length"] = absl::StrCat(generate_bytes_length_);
WriteHeaders(std::move(headers), false, nullptr);
+ QUICHE_DCHECK(!response_sent_);
+ response_sent_ = true;
WriteGeneratedBytes();
@@ -310,8 +347,7 @@ void QuicSimpleServerStream::SendNotFoundResponse() {
QUIC_DVLOG(1) << "Stream " << id() << " sending not found response.";
Http2HeaderBlock headers;
headers[":status"] = "404";
- headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(strlen(kNotFoundResponseBody));
+ headers["content-length"] = absl::StrCat(strlen(kNotFoundResponseBody));
SendHeadersAndBody(std::move(headers), kNotFoundResponseBody);
}
@@ -325,10 +361,9 @@ void QuicSimpleServerStream::SendErrorResponse(int resp_code) {
if (resp_code <= 0) {
headers[":status"] = "500";
} else {
- headers[":status"] = quiche::QuicheTextUtils::Uint64ToString(resp_code);
+ headers[":status"] = absl::StrCat(resp_code);
}
- headers["content-length"] =
- quiche::QuicheTextUtils::Uint64ToString(strlen(kErrorResponseBody));
+ headers["content-length"] = absl::StrCat(strlen(kErrorResponseBody));
SendHeadersAndBody(std::move(headers), kErrorResponseBody);
}
@@ -338,6 +373,8 @@ void QuicSimpleServerStream::SendIncompleteResponse(
QUIC_DLOG(INFO) << "Stream " << id() << " writing headers (fin = false) : "
<< response_headers.DebugString();
WriteHeaders(std::move(response_headers), /*fin=*/false, nullptr);
+ QUICHE_DCHECK(!response_sent_);
+ response_sent_ = true;
QUIC_DLOG(INFO) << "Stream " << id()
<< " writing body (fin = false) with size: " << body.size();
@@ -362,6 +399,8 @@ void QuicSimpleServerStream::SendHeadersAndBodyAndTrailers(
QUIC_DLOG(INFO) << "Stream " << id() << " writing headers (fin = " << send_fin
<< ") : " << response_headers.DebugString();
WriteHeaders(std::move(response_headers), send_fin, nullptr);
+ QUICHE_DCHECK(!response_sent_);
+ response_sent_ = true;
if (send_fin) {
// Nothing else to send.
return;
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h
index bbed95a2bcd..2dd59f9fc91 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream.h
@@ -99,6 +99,8 @@ class QuicSimpleServerStream : public QuicSpdyServerStreamBase,
private:
uint64_t generate_bytes_length_;
+ // Whether response headers have already been sent.
+ bool response_sent_ = false;
QuicSimpleServerBackend* quic_simple_server_backend_; // Not owned.
};
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
index 5806ad72de1..bf80d476020 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_simple_server_stream_test.cc
@@ -9,6 +9,7 @@
#include <utility>
#include "absl/base/macros.h"
+#include "absl/memory/memory.h"
#include "absl/strings/string_view.h"
#include "absl/types/optional.h"
#include "quic/core/crypto/null_encrypter.h"
@@ -18,7 +19,6 @@
#include "quic/core/quic_types.h"
#include "quic/core/quic_utils.h"
#include "quic/platform/api/quic_expect_bug.h"
-#include "quic/platform/api/quic_ptr_util.h"
#include "quic/platform/api/quic_socket_address.h"
#include "quic/platform/api/quic_test.h"
#include "quic/test_tools/crypto_test_utils.h"
@@ -59,12 +59,17 @@ class TestStream : public QuicSimpleServerStream {
~TestStream() override = default;
MOCK_METHOD(void, WriteHeadersMock, (bool fin), ());
+ MOCK_METHOD(void, WriteEarlyHintsHeadersMock, (bool fin), ());
- size_t WriteHeaders(spdy::Http2HeaderBlock /*header_block*/,
+ size_t WriteHeaders(spdy::Http2HeaderBlock header_block,
bool fin,
QuicReferenceCountedPointer<QuicAckListenerInterface>
/*ack_listener*/) override {
- WriteHeadersMock(fin);
+ if (header_block[":status"] == "103") {
+ WriteEarlyHintsHeadersMock(fin);
+ } else {
+ WriteHeadersMock(fin);
+ }
return 0;
}
@@ -77,6 +82,9 @@ class TestStream : public QuicSimpleServerStream {
const std::string& body() const { return body_; }
int content_length() const { return content_length_; }
bool send_response_was_called() const { return send_response_was_called_; }
+ bool send_error_response_was_called() const {
+ return send_error_response_was_called_;
+ }
absl::string_view GetHeader(absl::string_view key) const {
auto it = request_headers_.find(key);
@@ -90,8 +98,14 @@ class TestStream : public QuicSimpleServerStream {
QuicSimpleServerStream::SendResponse();
}
+ void SendErrorResponse() override {
+ send_error_response_was_called_ = true;
+ QuicSimpleServerStream::SendErrorResponse();
+ }
+
private:
bool send_response_was_called_ = false;
+ bool send_error_response_was_called_ = false;
};
namespace {
@@ -266,7 +280,7 @@ class QuicSimpleServerStreamTest : public QuicTestWithParam<ParsedQuicVersion> {
connection_->transport_version(), 0),
&session_, BIDIRECTIONAL, &memory_cache_backend_);
// Register stream_ in dynamic_stream_map_ and pass ownership to session_.
- session_.ActivateStream(QuicWrapUnique(stream_));
+ session_.ActivateStream(absl::WrapUnique(stream_));
QuicConfigPeer::SetReceivedInitialSessionFlowControlWindow(
session_.config(), kMinimumFlowControlSendWindow);
QuicConfigPeer::SetReceivedInitialMaxStreamDataBytesUnidirectional(
@@ -474,7 +488,7 @@ TEST_P(QuicSimpleServerStreamTest, SendPushResponseWith404Response) {
GetNthServerInitiatedUnidirectionalStreamId(
connection_->transport_version(), 3),
&session_, WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
- session_.ActivateStream(QuicWrapUnique(promised_stream));
+ session_.ActivateStream(absl::WrapUnique(promised_stream));
// Send a push response with response status 404, which will be regarded as
// invalid server push response.
@@ -572,6 +586,50 @@ TEST_P(QuicSimpleServerStreamTest, SendResponseWithPushResources) {
EXPECT_EQ(*request_headers, session_.original_request_headers_);
}
+TEST_P(QuicSimpleServerStreamTest, SendResponseWithEarlyHints) {
+ std::string host = "www.google.com";
+ std::string request_path = "/foo";
+ std::string body = "Yummm";
+
+ // Add a request and response with early hints.
+ spdy::Http2HeaderBlock* request_headers = stream_->mutable_headers();
+ (*request_headers)[":path"] = request_path;
+ (*request_headers)[":authority"] = host;
+ (*request_headers)[":method"] = "GET";
+
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ HttpEncoder::SerializeDataFrameHeader(body.length(), &buffer);
+ std::vector<spdy::Http2HeaderBlock> early_hints;
+ // Add two Early Hints.
+ const size_t kNumEarlyHintsResponses = 2;
+ for (size_t i = 0; i < kNumEarlyHintsResponses; ++i) {
+ spdy::Http2HeaderBlock hints;
+ hints["link"] = "</image.png>; rel=preload; as=image";
+ early_hints.push_back(std::move(hints));
+ }
+
+ response_headers_[":status"] = "200";
+ response_headers_["content-length"] = "5";
+ memory_cache_backend_.AddResponseWithEarlyHints(
+ host, request_path, std::move(response_headers_), body, early_hints);
+ QuicStreamPeer::SetFinReceived(stream_);
+
+ InSequence s;
+ for (size_t i = 0; i < kNumEarlyHintsResponses; ++i) {
+ EXPECT_CALL(*stream_, WriteEarlyHintsHeadersMock(false));
+ }
+ EXPECT_CALL(*stream_, WriteHeadersMock(false));
+ if (UsesHttp3()) {
+ EXPECT_CALL(session_, WritevData(_, header_length, _, NO_FIN, _, _));
+ }
+ EXPECT_CALL(session_, WritevData(_, body.length(), _, FIN, _, _));
+
+ stream_->DoSendResponse();
+ EXPECT_FALSE(QuicStreamPeer::read_side_closed(stream_));
+ EXPECT_TRUE(stream_->write_side_closed());
+}
+
TEST_P(QuicSimpleServerStreamTest, PushResponseOnClientInitiatedStream) {
// EXPECT_QUIC_BUG tests are expensive so only run one instance of them.
if (GetParam() != AllSupportedVersions()[0]) {
@@ -597,7 +655,7 @@ TEST_P(QuicSimpleServerStreamTest, PushResponseOnServerInitiatedStream) {
auto server_initiated_stream =
new StrictMock<TestStream>(kServerInitiatedStreamId, &session_,
WRITE_UNIDIRECTIONAL, &memory_cache_backend_);
- session_.ActivateStream(QuicWrapUnique(server_initiated_stream));
+ session_.ActivateStream(absl::WrapUnique(server_initiated_stream));
const std::string kHost = "www.foo.com";
const std::string kPath = "/bar";
@@ -778,6 +836,33 @@ TEST_P(QuicSimpleServerStreamTest, ConnectSendsResponseBeforeFinReceived) {
EXPECT_EQ("CONNECT-SILLY", StreamHeadersValue(":method"));
EXPECT_EQ(body_, StreamBody());
EXPECT_TRUE(stream_->send_response_was_called());
+ EXPECT_FALSE(stream_->send_error_response_was_called());
+}
+
+TEST_P(QuicSimpleServerStreamTest, ConnectWithInvalidHeader) {
+ EXPECT_CALL(session_, WritevData(_, _, _, _, _, _))
+ .WillRepeatedly(
+ Invoke(&session_, &MockQuicSimpleServerSession::ConsumeData));
+ QuicHeaderList header_list;
+ header_list.OnHeaderBlockStart();
+ header_list.OnHeader(":authority", "www.google.com:4433");
+ header_list.OnHeader(":method", "CONNECT-SILLY");
+ // QUIC requires lower-case header names.
+ header_list.OnHeader("InVaLiD-HeAdEr", "Well that's just wrong!");
+ header_list.OnHeaderBlockEnd(128, 128);
+ EXPECT_CALL(*stream_, WriteHeadersMock(/*fin=*/false));
+ stream_->OnStreamHeaderList(/*fin=*/false, kFakeFrameLen, header_list);
+ std::unique_ptr<char[]> buffer;
+ QuicByteCount header_length =
+ HttpEncoder::SerializeDataFrameHeader(body_.length(), &buffer);
+ std::string header = std::string(buffer.get(), header_length);
+ std::string data = UsesHttp3() ? header + body_ : body_;
+ stream_->OnStreamFrame(
+ QuicStreamFrame(stream_->id(), /*fin=*/false, /*offset=*/0, data));
+ EXPECT_EQ("CONNECT-SILLY", StreamHeadersValue(":method"));
+ EXPECT_EQ(body_, StreamBody());
+ EXPECT_FALSE(stream_->send_response_was_called());
+ EXPECT_TRUE(stream_->send_error_response_was_called());
}
} // namespace
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
index d28eb771a7d..974344ed4aa 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.cc
@@ -50,8 +50,7 @@ QuicSpdyClientBase::QuicSpdyClientBase(
std::move(proof_verifier),
std::move(session_cache)),
store_response_(false),
- latest_response_code_(-1),
- max_allowed_push_id_(0) {}
+ latest_response_code_(-1) {}
QuicSpdyClientBase::~QuicSpdyClientBase() {
// We own the push promise index. We need to explicitly kill
@@ -70,10 +69,6 @@ const QuicSpdyClientSession* QuicSpdyClientBase::client_session() const {
void QuicSpdyClientBase::InitializeSession() {
client_session()->Initialize();
client_session()->CryptoConnect();
- if (max_allowed_push_id_ > 0 &&
- VersionUsesHttp3(client_session()->transport_version())) {
- client_session()->SetMaxPushId(max_allowed_push_id_);
- }
}
void QuicSpdyClientBase::OnClose(QuicSpdyStream* stream) {
@@ -146,7 +141,7 @@ void QuicSpdyClientBase::SendRequestInternal(Http2HeaderBlock sanitized_headers,
QuicSpdyClientStream* stream = CreateClientStream();
if (stream == nullptr) {
- QUIC_BUG << "stream creation failed!";
+ QUIC_BUG(quic_bug_10949_1) << "stream creation failed!";
return;
}
stream->SendRequest(std::move(sanitized_headers), body, fin);
@@ -166,7 +161,7 @@ void QuicSpdyClientBase::SendRequestsAndWaitForResponse(
for (size_t i = 0; i < url_list.size(); ++i) {
Http2HeaderBlock headers;
if (!SpdyUtils::PopulateHeaderBlockFromUrl(url_list[i], &headers)) {
- QUIC_BUG << "Unable to create request";
+ QUIC_BUG(quic_bug_10949_2) << "Unable to create request";
continue;
}
SendRequest(headers, "", true);
@@ -260,33 +255,33 @@ void QuicSpdyClientBase::OnRendezvousResult(QuicSpdyStream* stream) {
}
int QuicSpdyClientBase::latest_response_code() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ QUIC_BUG_IF(quic_bug_10949_3, !store_response_) << "Response not stored!";
return latest_response_code_;
}
const std::string& QuicSpdyClientBase::latest_response_headers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ QUIC_BUG_IF(quic_bug_10949_4, !store_response_) << "Response not stored!";
return latest_response_headers_;
}
const std::string& QuicSpdyClientBase::preliminary_response_headers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ QUIC_BUG_IF(quic_bug_10949_5, !store_response_) << "Response not stored!";
return preliminary_response_headers_;
}
const Http2HeaderBlock& QuicSpdyClientBase::latest_response_header_block()
const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ QUIC_BUG_IF(quic_bug_10949_6, !store_response_) << "Response not stored!";
return latest_response_header_block_;
}
const std::string& QuicSpdyClientBase::latest_response_body() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ QUIC_BUG_IF(quic_bug_10949_7, !store_response_) << "Response not stored!";
return latest_response_body_;
}
const std::string& QuicSpdyClientBase::latest_response_trailers() const {
- QUIC_BUG_IF(!store_response_) << "Response not stored!";
+ QUIC_BUG_IF(quic_bug_10949_8, !store_response_) << "Response not stored!";
return latest_response_trailers_;
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h
index 54c73f780cf..2ba55f11693 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_spdy_client_base.h
@@ -139,9 +139,10 @@ class QuicSpdyClientBase : public QuicClientBase,
}
bool drop_response_body() const { return drop_response_body_; }
- // Set the max promise id for the client session.
- // TODO(b/151641466): Rename this method.
- void SetMaxAllowedPushId(PushId max) { max_allowed_push_id_ = max; }
+ void set_enable_web_transport(bool enable_web_transport) {
+ enable_web_transport_ = enable_web_transport;
+ }
+ bool enable_web_transport() const { return enable_web_transport_; }
// QuicClientBase methods.
bool goaway_received() const override;
@@ -221,9 +222,7 @@ class QuicSpdyClientBase : public QuicClientBase,
std::unique_ptr<ClientQuicDataToResend> push_promise_data_to_resend_;
bool drop_response_body_ = false;
-
- // The max promise id to set on the client session when created.
- PushId max_allowed_push_id_;
+ bool enable_web_transport_ = false;
};
} // namespace quic
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc
index 37e23b60c76..22e873185b6 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_tcp_like_trace_converter.cc
@@ -30,7 +30,7 @@ QuicIntervalSet<uint64_t> QuicTcpLikeTraceConverter::OnCryptoFrameSent(
QuicStreamOffset offset,
QuicByteCount data_length) {
if (level >= NUM_ENCRYPTION_LEVELS) {
- QUIC_BUG << "Invalid encryption level";
+ QUIC_BUG(quic_bug_10907_1) << "Invalid encryption level";
return {};
}
return OnFrameSent(offset, data_length, /*fin=*/false,
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc
index 7029cf70be9..25730eda818 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.cc
@@ -39,7 +39,8 @@ QuicTransportSimpleServerDispatcher::CreateQuicSession(
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
absl::string_view /*alpn*/,
- const ParsedQuicVersion& version) {
+ const ParsedQuicVersion& version,
+ absl::string_view /*sni*/) {
auto connection = std::make_unique<QuicConnection>(
server_connection_id, self_address, peer_address, helper(),
alarm_factory(), writer(),
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h
index 500b02d55fb..bb38596bf19 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_dispatcher.h
@@ -32,7 +32,8 @@ class QuicTransportSimpleServerDispatcher : public QuicDispatcher {
const QuicSocketAddress& self_address,
const QuicSocketAddress& peer_address,
absl::string_view alpn,
- const ParsedQuicVersion& version) override;
+ const ParsedQuicVersion& version,
+ absl::string_view sni) override;
std::vector<url::Origin> accepted_origins_;
};
diff --git a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc
index ad93115705f..bc7ef192860 100644
--- a/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc
+++ b/chromium/net/third_party/quiche/src/quic/tools/quic_transport_simple_server_session.cc
@@ -15,115 +15,10 @@
#include "quic/platform/api/quic_logging.h"
#include "quic/quic_transport/quic_transport_protocol.h"
#include "quic/quic_transport/quic_transport_stream.h"
+#include "quic/tools/web_transport_test_visitors.h"
namespace quic {
-namespace {
-
-// Discards any incoming data.
-class DiscardVisitor : public QuicTransportStream::Visitor {
- public:
- DiscardVisitor(QuicTransportStream* stream) : stream_(stream) {}
-
- void OnCanRead() override {
- std::string buffer;
- size_t bytes_read = stream_->Read(&buffer);
- QUIC_DVLOG(2) << "Read " << bytes_read << " bytes from stream "
- << stream_->id();
- }
-
- void OnFinRead() override {}
- void OnCanWrite() override {}
-
- private:
- QuicTransportStream* stream_;
-};
-
-// Echoes any incoming data back on the same stream.
-class BidirectionalEchoVisitor : public QuicTransportStream::Visitor {
- public:
- BidirectionalEchoVisitor(QuicTransportStream* stream) : stream_(stream) {}
-
- void OnCanRead() override {
- stream_->Read(&buffer_);
- OnCanWrite();
- }
-
- void OnFinRead() override {
- bool success = stream_->SendFin();
- QUICHE_DCHECK(success);
- }
-
- void OnCanWrite() override {
- if (buffer_.empty()) {
- return;
- }
-
- bool success = stream_->Write(buffer_);
- if (success) {
- buffer_ = "";
- }
- }
-
- private:
- QuicTransportStream* stream_;
- std::string buffer_;
-};
-
-// Buffers all of the data and calls EchoStreamBack() on the parent session.
-class UnidirectionalEchoReadVisitor : public QuicTransportStream::Visitor {
- public:
- UnidirectionalEchoReadVisitor(QuicTransportSimpleServerSession* session,
- QuicTransportStream* stream)
- : session_(session), stream_(stream) {}
-
- void OnCanRead() override {
- bool success = stream_->Read(&buffer_);
- QUICHE_DCHECK(success);
- }
-
- void OnFinRead() override {
- QUIC_DVLOG(1) << "Finished receiving data on stream " << stream_->id()
- << ", queueing up the echo";
- session_->EchoStreamBack(buffer_);
- }
-
- void OnCanWrite() override { QUIC_NOTREACHED(); }
-
- private:
- QuicTransportSimpleServerSession* session_;
- QuicTransportStream* stream_;
- std::string buffer_;
-};
-
-// Sends supplied data.
-class UnidirectionalEchoWriteVisitor : public QuicTransportStream::Visitor {
- public:
- UnidirectionalEchoWriteVisitor(QuicTransportStream* stream,
- const std::string& data)
- : stream_(stream), data_(data) {}
-
- void OnCanRead() override { QUIC_NOTREACHED(); }
- void OnFinRead() override { QUIC_NOTREACHED(); }
- void OnCanWrite() override {
- if (data_.empty()) {
- return;
- }
- if (!stream_->Write(data_)) {
- return;
- }
- data_ = "";
- bool fin_sent = stream_->SendFin();
- QUICHE_DCHECK(fin_sent);
- }
-
- private:
- QuicTransportStream* stream_;
- std::string data_;
-};
-
-} // namespace
-
QuicTransportSimpleServerSession::QuicTransportSimpleServerSession(
QuicConnection* connection,
bool owns_connection,
@@ -154,22 +49,24 @@ void QuicTransportSimpleServerSession::OnIncomingDataStream(
QuicTransportStream* stream) {
switch (mode_) {
case DISCARD:
- stream->set_visitor(std::make_unique<DiscardVisitor>(stream));
+ stream->SetVisitor(std::make_unique<WebTransportDiscardVisitor>(stream));
break;
case ECHO:
switch (stream->type()) {
case BIDIRECTIONAL:
QUIC_DVLOG(1) << "Opening bidirectional echo stream " << stream->id();
- stream->set_visitor(
- std::make_unique<BidirectionalEchoVisitor>(stream));
+ stream->SetVisitor(
+ std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
break;
case READ_UNIDIRECTIONAL:
QUIC_DVLOG(1)
<< "Started receiving data on unidirectional echo stream "
<< stream->id();
- stream->set_visitor(
- std::make_unique<UnidirectionalEchoReadVisitor>(this, stream));
+ stream->SetVisitor(
+ std::make_unique<WebTransportUnidirectionalEchoReadVisitor>(
+ stream,
+ [this](const std::string& s) { this->EchoStreamBack(s); }));
break;
default:
QUIC_NOTREACHED();
@@ -178,7 +75,7 @@ void QuicTransportSimpleServerSession::OnIncomingDataStream(
break;
case OUTGOING_BIDIRECTIONAL:
- stream->set_visitor(std::make_unique<DiscardVisitor>(stream));
+ stream->SetVisitor(std::make_unique<WebTransportDiscardVisitor>(stream));
++pending_outgoing_bidirectional_streams_;
MaybeCreateOutgoingBidirectionalStream();
break;
@@ -252,8 +149,9 @@ void QuicTransportSimpleServerSession::MaybeEchoStreamsBack() {
ActivateStream(std::move(stream_owned));
QUIC_DVLOG(1) << "Opened echo response stream " << stream->id();
- stream->set_visitor(
- std::make_unique<UnidirectionalEchoWriteVisitor>(stream, data));
+ stream->SetVisitor(
+ std::make_unique<WebTransportUnidirectionalEchoWriteVisitor>(stream,
+ data));
stream->visitor()->OnCanWrite();
}
}
@@ -267,7 +165,8 @@ void QuicTransportSimpleServerSession::
QuicTransportStream* stream = stream_owned.get();
ActivateStream(std::move(stream_owned));
QUIC_DVLOG(1) << "Opened outgoing bidirectional stream " << stream->id();
- stream->set_visitor(std::make_unique<BidirectionalEchoVisitor>(stream));
+ stream->SetVisitor(
+ std::make_unique<WebTransportBidirectionalEchoVisitor>(stream));
if (!stream->Write("hello")) {
QUIC_DVLOG(1) << "Write failed.";
}
diff --git a/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h b/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h
new file mode 100644
index 00000000000..9bf6e6bca84
--- /dev/null
+++ b/chromium/net/third_party/quiche/src/quic/tools/web_transport_test_visitors.h
@@ -0,0 +1,137 @@
+// Copyright (c) 2021 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_
+#define QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_
+
+#include <string>
+
+#include "quic/core/web_transport_interface.h"
+#include "quic/platform/api/quic_logging.h"
+
+namespace quic {
+
+// Discards any incoming data.
+class WebTransportDiscardVisitor : public WebTransportStreamVisitor {
+ public:
+ WebTransportDiscardVisitor(WebTransportStream* stream) : stream_(stream) {}
+
+ void OnCanRead() override {
+ std::string buffer;
+ WebTransportStream::ReadResult result = stream_->Read(&buffer);
+ QUIC_DVLOG(2) << "Read " << result.bytes_read
+ << " bytes from WebTransport stream "
+ << stream_->GetStreamId() << ", fin: " << result.fin;
+ }
+
+ void OnCanWrite() override {}
+
+ private:
+ WebTransportStream* stream_;
+};
+
+// Echoes any incoming data back on the same stream.
+class WebTransportBidirectionalEchoVisitor : public WebTransportStreamVisitor {
+ public:
+ WebTransportBidirectionalEchoVisitor(WebTransportStream* stream)
+ : stream_(stream) {}
+
+ void OnCanRead() override {
+ WebTransportStream::ReadResult result = stream_->Read(&buffer_);
+ QUIC_DVLOG(1) << "Attempted reading on WebTransport bidirectional stream "
+ << stream_->GetStreamId()
+ << ", bytes read: " << result.bytes_read;
+ if (result.fin) {
+ send_fin_ = true;
+ }
+ OnCanWrite();
+ }
+
+ void OnCanWrite() override {
+ if (!buffer_.empty()) {
+ bool success = stream_->Write(buffer_);
+ QUIC_DVLOG(1) << "Attempted writing on WebTransport bidirectional stream "
+ << stream_->GetStreamId()
+ << ", success: " << (success ? "yes" : "no");
+ if (!success) {
+ return;
+ }
+
+ buffer_ = "";
+ }
+
+ if (send_fin_) {
+ bool success = stream_->SendFin();
+ QUICHE_DCHECK(success);
+ }
+ }
+
+ private:
+ WebTransportStream* stream_;
+ std::string buffer_;
+ bool send_fin_ = false;
+};
+
+// Buffers all of the data and calls |callback| with the entirety of the stream
+// data.
+class WebTransportUnidirectionalEchoReadVisitor
+ : public WebTransportStreamVisitor {
+ public:
+ using Callback = std::function<void(const std::string&)>;
+
+ WebTransportUnidirectionalEchoReadVisitor(WebTransportStream* stream,
+ Callback callback)
+ : stream_(stream), callback_(std::move(callback)) {}
+
+ void OnCanRead() override {
+ WebTransportStream::ReadResult result = stream_->Read(&buffer_);
+ QUIC_DVLOG(1) << "Attempted reading on WebTransport unidirectional stream "
+ << stream_->GetStreamId()
+ << ", bytes read: " << result.bytes_read;
+ if (result.fin) {
+ QUIC_DVLOG(1) << "Finished receiving data on a WebTransport stream "
+ << stream_->GetStreamId() << ", queueing up the echo";
+ callback_(buffer_);
+ }
+ }
+
+ void OnCanWrite() override { QUIC_NOTREACHED(); }
+
+ private:
+ WebTransportStream* stream_;
+ std::string buffer_;
+ Callback callback_;
+};
+
+// Sends supplied data.
+class WebTransportUnidirectionalEchoWriteVisitor
+ : public WebTransportStreamVisitor {
+ public:
+ WebTransportUnidirectionalEchoWriteVisitor(WebTransportStream* stream,
+ const std::string& data)
+ : stream_(stream), data_(data) {}
+
+ void OnCanRead() override { QUIC_NOTREACHED(); }
+ void OnCanWrite() override {
+ if (data_.empty()) {
+ return;
+ }
+ if (!stream_->Write(data_)) {
+ return;
+ }
+ data_ = "";
+ bool fin_sent = stream_->SendFin();
+ QUICHE_DVLOG(1)
+ << "WebTransportUnidirectionalEchoWriteVisitor finished sending data.";
+ QUICHE_DCHECK(fin_sent);
+ }
+
+ private:
+ WebTransportStream* stream_;
+ std::string data_;
+};
+
+} // namespace quic
+
+#endif // QUICHE_QUIC_TOOLS_WEB_TRANSPORT_TEST_VISITORS_H_