diff options
Diffstat (limited to 'chromium/net/third_party/quiche/src/quic/tools')
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_ |