Update toy MASQUE code to connect-udp-12 We confirmed that this interoperates with Apple's latest implementation. PiperOrigin-RevId: 449547363
diff --git a/quiche/quic/masque/masque_client_bin.cc b/quiche/quic/masque/masque_client_bin.cc index f973227..0868e7d 100644 --- a/quiche/quic/masque/masque_client_bin.cc +++ b/quiche/quic/masque/masque_client_bin.cc
@@ -59,9 +59,11 @@ std::string uri_template = urls[0]; if (!absl::StrContains(uri_template, '/')) { - // Allow passing in authority instead of URI template. + // If an authority is passed in instead of a URI template, use the default + // URI template. uri_template = - absl::StrCat("https://", uri_template, "/{target_host}/{target_port}/"); + absl::StrCat("https://", uri_template, + "/.well-known/masque/udp/{target_host}/{target_port}/"); } url::Parsed parsed_uri_template; url::ParseStandardURL(uri_template.c_str(), uri_template.length(),
diff --git a/quiche/quic/masque/masque_client_session.cc b/quiche/quic/masque/masque_client_session.cc index 4dcdb45..28ba839 100644 --- a/quiche/quic/masque/masque_client_session.cc +++ b/quiche/quic/masque/masque_client_session.cc
@@ -4,12 +4,14 @@ #include "quiche/quic/masque/masque_client_session.h" +#include <cstring> #include <string> #include "absl/algorithm/container.h" #include "absl/container/flat_hash_map.h" #include "absl/container/flat_hash_set.h" #include "absl/strings/str_cat.h" +#include "absl/strings/string_view.h" #include "url/url_canon.h" #include "quiche/quic/core/http/spdy_utils.h" #include "quiche/quic/core/quic_data_reader.h" @@ -122,7 +124,7 @@ headers[":scheme"] = scheme; headers[":authority"] = authority; headers[":path"] = canonicalized_path; - headers["connect-udp-version"] = "6"; + headers["connect-udp-version"] = "12"; size_t bytes_sent = stream->SendRequest(std::move(headers), /*body=*/"", /*fin=*/false); if (bytes_sent == 0) { @@ -145,8 +147,12 @@ return; } + std::string http_payload; + http_payload.resize(1 + packet.size()); + http_payload[0] = 0; + memcpy(&http_payload[1], packet.data(), packet.size()); MessageStatus message_status = - SendHttp3Datagram(connect_udp->stream()->id(), packet); + SendHttp3Datagram(connect_udp->stream()->id(), http_payload); QUIC_DVLOG(1) << "Sent packet to " << target_server_address << " compressed with stream ID " << connect_udp->stream()->id() @@ -268,8 +274,21 @@ void MasqueClientSession::ConnectUdpClientState::OnHttp3Datagram( QuicStreamId stream_id, absl::string_view payload) { QUICHE_DCHECK_EQ(stream_id, stream()->id()); - encapsulated_client_session_->ProcessPacket(payload, target_server_address_); - QUIC_DVLOG(1) << "Sent " << payload.size() + QuicDataReader reader(payload); + uint64_t context_id; + if (!reader.ReadVarInt62(&context_id)) { + QUIC_DLOG(ERROR) << "Failed to read context ID"; + return; + } + if (context_id != 0) { + QUIC_DLOG(ERROR) << "Ignoring HTTP Datagram with unexpected context ID " + << context_id; + return; + } + absl::string_view http_payload = reader.ReadRemainingPayload(); + encapsulated_client_session_->ProcessPacket(http_payload, + target_server_address_); + QUIC_DVLOG(1) << "Sent " << http_payload.size() << " bytes to connection for stream ID " << stream_id; }
diff --git a/quiche/quic/masque/masque_server_session.cc b/quiche/quic/masque/masque_server_session.cc index bfc8cdf..742b0c6 100644 --- a/quiche/quic/masque/masque_server_session.cc +++ b/quiche/quic/masque/masque_server_session.cc
@@ -176,20 +176,21 @@ } // Extract target host and port from path using default template. std::vector<absl::string_view> path_split = absl::StrSplit(path, '/'); - if (path_split.size() != 4 || !path_split[0].empty() || - path_split[1].empty() || path_split[2].empty() || - !path_split[3].empty()) { + if (path_split.size() != 7 || !path_split[0].empty() || + path_split[1] != ".well-known" || path_split[2] != "masque" || + path_split[3] != "udp" || path_split[4].empty() || + path_split[5].empty() || !path_split[6].empty()) { QUIC_DLOG(ERROR) << "MASQUE request with bad path \"" << path << "\""; return CreateBackendErrorResponse("400", "Bad path"); } - absl::optional<std::string> host = quiche::AsciiUrlDecode(path_split[1]); + absl::optional<std::string> host = quiche::AsciiUrlDecode(path_split[4]); if (!host.has_value()) { - QUIC_DLOG(ERROR) << "Failed to decode host \"" << path_split[1] << "\""; + QUIC_DLOG(ERROR) << "Failed to decode host \"" << path_split[4] << "\""; return CreateBackendErrorResponse("500", "Failed to decode host"); } - absl::optional<std::string> port = quiche::AsciiUrlDecode(path_split[2]); + absl::optional<std::string> port = quiche::AsciiUrlDecode(path_split[5]); if (!port.has_value()) { - QUIC_DLOG(ERROR) << "Failed to decode port \"" << path_split[2] << "\""; + QUIC_DLOG(ERROR) << "Failed to decode port \"" << path_split[5] << "\""; return CreateBackendErrorResponse("500", "Failed to decode port"); } @@ -283,11 +284,12 @@ << " server " << expected_target_server_address; QuicUdpSocketApi socket_api; BitMask64 packet_info_interested(QuicUdpPacketInfoBit::PEER_ADDRESS); - char packet_buffer[kMaxIncomingPacketSize]; + char packet_buffer[1 + kMaxIncomingPacketSize]; + packet_buffer[0] = 0; // context ID. char control_buffer[kDefaultUdpPacketControlBufferSize]; while (true) { QuicUdpSocketApi::ReadPacketResult read_result; - read_result.packet_buffer = {packet_buffer, sizeof(packet_buffer)}; + read_result.packet_buffer = {packet_buffer + 1, sizeof(packet_buffer) - 1}; read_result.control_buffer = {control_buffer, sizeof(control_buffer)}; socket_api.ReadPacket(fd, packet_info_interested, &read_result); if (!read_result.ok) { @@ -316,9 +318,9 @@ return; } // The packet is valid, send it to the client in a DATAGRAM frame. - MessageStatus message_status = it->stream()->SendHttp3Datagram( - absl::string_view(read_result.packet_buffer.buffer, - read_result.packet_buffer.buffer_len)); + MessageStatus message_status = + it->stream()->SendHttp3Datagram(absl::string_view( + packet_buffer, read_result.packet_buffer.buffer_len + 1)); QUIC_DVLOG(1) << "Sent UDP packet from " << expected_target_server_address << " of length " << read_result.packet_buffer.buffer_len << " with stream ID " << it->stream()->id() @@ -409,12 +411,24 @@ void MasqueServerSession::ConnectUdpServerState::OnHttp3Datagram( QuicStreamId stream_id, absl::string_view payload) { QUICHE_DCHECK_EQ(stream_id, stream()->id()); + QuicDataReader reader(payload); + uint64_t context_id; + if (!reader.ReadVarInt62(&context_id)) { + QUIC_DLOG(ERROR) << "Failed to read context ID"; + return; + } + if (context_id != 0) { + QUIC_DLOG(ERROR) << "Ignoring HTTP Datagram with unexpected context ID " + << context_id; + return; + } + absl::string_view http_payload = reader.ReadRemainingPayload(); QuicUdpSocketApi socket_api; QuicUdpPacketInfo packet_info; packet_info.SetPeerAddress(target_server_address_); WriteResult write_result = socket_api.WritePacket( - fd_, payload.data(), payload.length(), packet_info); - QUIC_DVLOG(1) << "Wrote packet of length " << payload.length() << " to " + fd_, http_payload.data(), http_payload.length(), packet_info); + QUIC_DVLOG(1) << "Wrote packet of length " << http_payload.length() << " to " << target_server_address_ << " with result " << write_result; }