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;
}