Move Datagram-Flow-Id header to SpdyUtils This code is not used in production. PiperOrigin-RevId: 359912077 Change-Id: Ifdf163e92b6f184f0e5f8bc9c6629d3c2805d9c3
diff --git a/quic/core/http/spdy_utils.cc b/quic/core/http/spdy_utils.cc index a3d800a..d3a3c92 100644 --- a/quic/core/http/spdy_utils.cc +++ b/quic/core/http/spdy_utils.cc
@@ -12,6 +12,7 @@ #include "absl/strings/str_cat.h" #include "absl/strings/str_split.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" #include "quic/platform/api/quic_flag_utils.h" #include "quic/platform/api/quic_flags.h" #include "quic/platform/api/quic_logging.h" @@ -153,4 +154,45 @@ return true; } +// static +absl::optional<QuicDatagramFlowId> SpdyUtils::ParseDatagramFlowIdHeader( + const spdy::SpdyHeaderBlock& headers) { + auto flow_id_pair = headers.find("datagram-flow-id"); + if (flow_id_pair == headers.end()) { + return absl::nullopt; + } + std::vector<absl::string_view> flow_id_strings = + absl::StrSplit(flow_id_pair->second, ','); + absl::optional<QuicDatagramFlowId> first_named_flow_id; + for (absl::string_view flow_id_string : flow_id_strings) { + std::vector<absl::string_view> flow_id_components = + absl::StrSplit(flow_id_string, ';'); + if (flow_id_components.empty()) { + continue; + } + absl::string_view flow_id_value_string = flow_id_components[0]; + quiche::QuicheTextUtils::RemoveLeadingAndTrailingWhitespace( + &flow_id_value_string); + QuicDatagramFlowId flow_id; + if (!absl::SimpleAtoi(flow_id_value_string, &flow_id)) { + continue; + } + if (flow_id_components.size() == 1) { + // This flow ID is unnamed, return this one. + return flow_id; + } + // Otherwise this is a named flow ID. + if (!first_named_flow_id.has_value()) { + first_named_flow_id = flow_id; + } + } + return first_named_flow_id; +} + +// static +void SpdyUtils::AddDatagramFlowIdHeader(spdy::SpdyHeaderBlock* headers, + QuicDatagramFlowId flow_id) { + (*headers)["datagram-flow-id"] = absl::StrCat(flow_id); +} + } // namespace quic
diff --git a/quic/core/http/spdy_utils.h b/quic/core/http/spdy_utils.h index a3b3134..e3a8a97 100644 --- a/quic/core/http/spdy_utils.h +++ b/quic/core/http/spdy_utils.h
@@ -9,6 +9,7 @@ #include <cstdint> #include <string> +#include "absl/types/optional.h" #include "quic/core/http/http_constants.h" #include "quic/core/http/quic_header_list.h" #include "quic/core/quic_packets.h" @@ -51,6 +52,15 @@ // which must be fully-qualified. static bool PopulateHeaderBlockFromUrl(const std::string url, spdy::SpdyHeaderBlock* headers); + + // Parses the "datagram-flow-id" header, returns the flow ID on success, or + // returns absl::nullopt if the header was not present or failed to parse. + static absl::optional<QuicDatagramFlowId> ParseDatagramFlowIdHeader( + const spdy::SpdyHeaderBlock& headers); + + // Adds the "datagram-flow-id" header. + static void AddDatagramFlowIdHeader(spdy::SpdyHeaderBlock* headers, + QuicDatagramFlowId flow_id); }; } // namespace quic
diff --git a/quic/core/http/spdy_utils_test.cc b/quic/core/http/spdy_utils_test.cc index 5cb391d..c7207f3 100644 --- a/quic/core/http/spdy_utils_test.cc +++ b/quic/core/http/spdy_utils_test.cc
@@ -33,6 +33,14 @@ return headers; } +static void ValidateDatagramFlowId( + const std::string& header_value, + absl::optional<QuicDatagramFlowId> expected_flow_id) { + SpdyHeaderBlock headers; + headers["datagram-flow-id"] = header_value; + ASSERT_EQ(SpdyUtils::ParseDatagramFlowIdHeader(headers), expected_flow_id); +} + } // anonymous namespace using CopyAndValidateHeaders = QuicTest; @@ -377,5 +385,29 @@ SpdyUtils::PopulateHeaderBlockFromUrl("www.google.com/", &headers)); } +using DatagramFlowIdTest = QuicTest; + +TEST_F(DatagramFlowIdTest, DatagramFlowId) { + // Test missing header. + SpdyHeaderBlock headers; + EXPECT_EQ(SpdyUtils::ParseDatagramFlowIdHeader(headers), absl::nullopt); + // Add header and verify it parses. + QuicDatagramFlowId flow_id = 123; + SpdyUtils::AddDatagramFlowIdHeader(&headers, flow_id); + EXPECT_EQ(SpdyUtils::ParseDatagramFlowIdHeader(headers), flow_id); + // Test empty header. + ValidateDatagramFlowId("", absl::nullopt); + // Test invalid header. + ValidateDatagramFlowId("M4SQU3", absl::nullopt); + // Test simple header. + ValidateDatagramFlowId("42", 42); + // Test with parameter. + ValidateDatagramFlowId("42; abc=def", 42); + // Test list. + ValidateDatagramFlowId("42, 44; ecn-ect0, 46; ecn-ect1, 48; ecn-ce", 42); + // Test reordered list. + ValidateDatagramFlowId("44; ecn-ect0, 42, 48; ecn-ce, 46; ecn-ect1", 42); +} + } // namespace test } // namespace quic
diff --git a/quic/masque/masque_client_session.cc b/quic/masque/masque_client_session.cc index e158125..79ab509 100644 --- a/quic/masque/masque_client_session.cc +++ b/quic/masque/masque_client_session.cc
@@ -4,6 +4,7 @@ #include "quic/masque/masque_client_session.h" #include "absl/algorithm/container.h" +#include "quic/core/http/spdy_utils.h" #include "quic/core/quic_data_reader.h" #include "common/platform/api/quiche_text_utils.h" @@ -99,7 +100,7 @@ headers[":scheme"] = "masque"; headers[":path"] = "/"; headers[":authority"] = target_server_address.ToString(); - headers["datagram-flow-id"] = absl::StrCat(flow_id); + SpdyUtils::AddDatagramFlowIdHeader(&headers, flow_id); size_t bytes_sent = stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false); if (bytes_sent == 0) {
diff --git a/quic/masque/masque_server_session.cc b/quic/masque/masque_server_session.cc index 1e420b9..4f065ee 100644 --- a/quic/masque/masque_server_session.cc +++ b/quic/masque/masque_server_session.cc
@@ -8,6 +8,8 @@ #include "absl/strings/str_cat.h" #include "absl/strings/string_view.h" +#include "absl/types/optional.h" +#include "quic/core/http/spdy_utils.h" #include "quic/core/quic_data_reader.h" #include "quic/core/quic_udp_socket.h" #include "quic/tools/quic_url.h" @@ -174,12 +176,10 @@ auto path_pair = request_headers.find(":path"); auto scheme_pair = request_headers.find(":scheme"); auto method_pair = request_headers.find(":method"); - auto flow_id_pair = request_headers.find("datagram-flow-id"); auto authority_pair = request_headers.find(":authority"); if (path_pair == request_headers.end() || scheme_pair == request_headers.end() || method_pair == request_headers.end() || - flow_id_pair == request_headers.end() || authority_pair == request_headers.end()) { QUIC_DLOG(ERROR) << "MASQUE request is missing required headers"; return CreateBackendErrorResponse("400", "Missing required headers"); @@ -187,7 +187,6 @@ absl::string_view path = path_pair->second; absl::string_view scheme = scheme_pair->second; absl::string_view method = method_pair->second; - absl::string_view flow_id_str = flow_id_pair->second; absl::string_view authority = authority_pair->second; if (path.empty()) { QUIC_DLOG(ERROR) << "MASQUE request with empty path"; @@ -201,11 +200,13 @@ QUIC_DLOG(ERROR) << "MASQUE request with bad method \"" << method << "\""; return CreateBackendErrorResponse("400", "Bad method"); } - QuicDatagramFlowId flow_id; - if (!absl::SimpleAtoi(flow_id_str, &flow_id)) { - QUIC_DLOG(ERROR) << "MASQUE request with bad flow_id \"" << flow_id_str - << "\""; - return CreateBackendErrorResponse("400", "Bad flow ID"); + absl::optional<QuicDatagramFlowId> flow_id = + SpdyUtils::ParseDatagramFlowIdHeader(request_headers); + if (!flow_id.has_value()) { + QUIC_DLOG(ERROR) + << "MASQUE request with bad or missing DatagramFlowId header"; + return CreateBackendErrorResponse("400", + "Bad or missing DatagramFlowId header"); } QuicUrl url(absl::StrCat("https://", authority)); if (!url.IsValid() || url.PathParamsQuery() != "/") { @@ -232,7 +233,7 @@ info_list, freeaddrinfo); QuicSocketAddress target_server_address(info_list->ai_addr, info_list->ai_addrlen); - QUIC_DLOG(INFO) << "Got CONNECT_UDP request flow_id=" << flow_id + QUIC_DLOG(INFO) << "Got CONNECT_UDP request flow_id=" << *flow_id << " target_server_address=\"" << target_server_address << "\""; @@ -250,12 +251,12 @@ epoll_server_->RegisterFDForRead(fd_wrapper.fd(), this); connect_udp_server_states_.emplace_back(ConnectUdpServerState( - flow_id, request_handler->stream_id(), target_server_address, + *flow_id, request_handler->stream_id(), target_server_address, fd_wrapper.extract_fd(), this)); spdy::Http2HeaderBlock response_headers; response_headers[":status"] = "200"; - response_headers["datagram-flow-id"] = absl::StrCat(flow_id); + SpdyUtils::AddDatagramFlowIdHeader(&response_headers, *flow_id); auto response = std::make_unique<QuicBackendResponse>(); response->set_response_type(QuicBackendResponse::INCOMPLETE_RESPONSE); response->set_headers(std::move(response_headers));