commit ef4d71923326a188a37df61edfb981e0510bf412
parent da9586a9661510c87964f855f2cb433818aa9337
Author: Valentin Gosu <valentin.gosu@gmail.com>
Date: Sat, 22 Nov 2025 14:17:31 +0000
Bug 1999659 - fix build r=necko-reviewers,kershaw,mxinden
http3server and neqo_glue must now expect header values to be a byte array,
not a string
Differential Revision: https://phabricator.services.mozilla.com/D273461
Diffstat:
2 files changed, 62 insertions(+), 62 deletions(-)
diff --git a/netwerk/socket/neqo_glue/src/lib.rs b/netwerk/socket/neqo_glue/src/lib.rs
@@ -1796,13 +1796,13 @@ fn convert_h3_to_h1_headers(headers: &[Header], ret_headers: &mut ThinVec<u8>) -
.value();
ret_headers.extend_from_slice(b"HTTP/3 ");
- ret_headers.extend_from_slice(status_val.as_bytes());
+ ret_headers.extend_from_slice(status_val);
ret_headers.extend_from_slice(b"\r\n");
for hdr in headers.iter().filter(|&h| h.name() != ":status") {
ret_headers.extend_from_slice(&sanitize_header(Cow::from(hdr.name().as_bytes())));
ret_headers.extend_from_slice(b": ");
- ret_headers.extend_from_slice(&sanitize_header(Cow::from(hdr.value().as_bytes())));
+ ret_headers.extend_from_slice(&sanitize_header(Cow::from(hdr.value())));
ret_headers.extend_from_slice(b"\r\n");
}
ret_headers.extend_from_slice(b"\r\n");
diff --git a/netwerk/test/http3server/src/main.rs b/netwerk/test/http3server/src/main.rs
@@ -248,8 +248,8 @@ impl HttpServer for Http3TestServer {
match path_hdr {
Some(ph) if !ph.value().is_empty() => {
let path = ph.value();
- qtrace!("Serve request {}", path);
- if path == "/Response421" {
+ qtrace!("Serve request {:?}", ph.value_utf8().unwrap_or("<invalid utf8>"));
+ if path == b"/Response421" {
let response_body = b"0123456789".to_vec();
stream
.send_headers(&[
@@ -263,30 +263,30 @@ impl HttpServer for Http3TestServer {
])
.unwrap();
self.new_response(stream, response_body, now);
- } else if path == "/RequestCancelled" {
+ } else if path == b"/RequestCancelled" {
stream
.stream_stop_sending(Error::HttpRequestCancelled.code())
.unwrap();
stream
.stream_reset_send(Error::HttpRequestCancelled.code())
.unwrap();
- } else if path == "/VersionFallback" {
+ } else if path == b"/VersionFallback" {
stream
.stream_stop_sending(Error::HttpVersionFallback.code())
.unwrap();
stream
.stream_reset_send(Error::HttpVersionFallback.code())
.unwrap();
- } else if path == "/EarlyResponse" {
+ } else if path == b"/EarlyResponse" {
stream.stream_stop_sending(Error::HttpNone.code()).unwrap();
- } else if path == "/RequestRejected" {
+ } else if path == b"/RequestRejected" {
stream
.stream_stop_sending(Error::HttpRequestRejected.code())
.unwrap();
stream
.stream_reset_send(Error::HttpRequestRejected.code())
.unwrap();
- } else if path == "/closeafter1000ms" {
+ } else if path == b"/closeafter1000ms" {
let response_body = b"0123456789".to_vec();
stream
.send_headers(&[
@@ -309,13 +309,13 @@ impl HttpServer for Http3TestServer {
.push(stream.conn.clone());
self.new_response(stream, response_body, now);
- } else if path == "/.well-known/http-opportunistic" {
+ } else if path == b"/.well-known/http-opportunistic" {
let host_hdr = headers.iter().find(|&h| h.name() == ":authority");
match host_hdr {
Some(host) if !host.value().is_empty() => {
let mut content = b"[\"http://".to_vec();
- content.extend(host.value().as_bytes());
- content.extend(b"\"]".to_vec());
+ content.extend(host.value());
+ content.extend(b"\"]");
stream
.send_headers(&[
Header::new(":status", "200"),
@@ -334,7 +334,7 @@ impl HttpServer for Http3TestServer {
self.new_response(stream, default_ret, now);
}
}
- } else if path == "/no_body" {
+ } else if path == b"/no_body" {
qdebug!("Request for no_body");
stream
.send_headers(&[
@@ -343,7 +343,7 @@ impl HttpServer for Http3TestServer {
])
.unwrap();
stream.stream_close_send(now).unwrap();
- } else if path == "/no_content_length" {
+ } else if path == b"/no_content_length" {
stream
.send_headers(&[
Header::new(":status", "200"),
@@ -351,7 +351,7 @@ impl HttpServer for Http3TestServer {
])
.unwrap();
self.new_response(stream, vec![b'a'; 4000], now);
- } else if path == "/content_length_smaller" {
+ } else if path == b"/content_length_smaller" {
stream
.send_headers(&[
Header::new(":status", "200"),
@@ -361,10 +361,10 @@ impl HttpServer for Http3TestServer {
])
.unwrap();
self.new_response(stream, vec![b'a'; 8000], now);
- } else if path == "/post" {
+ } else if path == b"/post" {
// Read all data before responding.
self.posts.insert(stream, 0);
- } else if path == "/priority_mirror" {
+ } else if path == b"/priority_mirror" {
if let Some(priority) =
headers.iter().find(|h| h.name() == "priority")
{
@@ -373,7 +373,7 @@ impl HttpServer for Http3TestServer {
Header::new(":status", "200"),
Header::new("cache-control", "no-cache"),
Header::new("content-type", "text/plain"),
- Header::new("priority-mirror", priority.value()),
+ Header::new("priority-mirror", priority.value_utf8().unwrap()),
Header::new(
"content-length",
priority.value().len().to_string(),
@@ -382,7 +382,7 @@ impl HttpServer for Http3TestServer {
.unwrap();
self.new_response(
stream,
- priority.value().as_bytes().to_vec(),
+ priority.value().to_vec(),
now,
);
} else {
@@ -394,11 +394,11 @@ impl HttpServer for Http3TestServer {
.unwrap();
stream.stream_close_send(now).unwrap();
}
- } else if path == "/103_response" {
+ } else if path == b"/103_response" {
if let Some(early_hint) =
headers.iter().find(|h| h.name() == "link-to-set")
{
- for l in early_hint.value().split(',') {
+ for l in early_hint.value_utf8().unwrap().split(',') {
stream
.send_headers(&[
Header::new(":status", "103"),
@@ -415,7 +415,7 @@ impl HttpServer for Http3TestServer {
])
.unwrap();
stream.stream_close_send(now).unwrap();
- } else if path == "/get_webtransport_datagram" {
+ } else if path == b"/get_webtransport_datagram" {
if let Some(dgram) = self.received_datagram.take() {
stream
.send_headers(&[
@@ -433,7 +433,7 @@ impl HttpServer for Http3TestServer {
.unwrap();
stream.stream_close_send(now).unwrap();
}
- } else if path == "/alt_svc_header" {
+ } else if path == b"/alt_svc_header" {
if let Some(alt_svc) =
headers.iter().find(|h| h.name() == "x-altsvc")
{
@@ -445,7 +445,7 @@ impl HttpServer for Http3TestServer {
Header::new("content-length", 100.to_string()),
Header::new(
"alt-svc",
- format!("h3={}", alt_svc.value()),
+ format!("h3={}", alt_svc.value_utf8().unwrap()),
),
])
.unwrap();
@@ -460,8 +460,8 @@ impl HttpServer for Http3TestServer {
self.new_response(stream, vec![b'a'; 100], now);
}
} else {
- match path.trim_matches(|p| p == '/').parse::<usize>() {
- Ok(v) => {
+ match ph.value_utf8().ok().and_then(|s| s.trim_matches(|p| p == '/').parse::<usize>().ok()) {
+ Some(v) => {
stream
.send_headers(&[
Header::new(":status", "200"),
@@ -472,7 +472,7 @@ impl HttpServer for Http3TestServer {
.unwrap();
self.new_response(stream, vec![b'a'; v], now);
}
- Err(_) => {
+ None => {
stream.send_headers(&default_headers).unwrap();
self.new_response(stream, default_ret, now);
}
@@ -555,10 +555,10 @@ impl HttpServer for Http3TestServer {
match path_hdr {
Some(ph) if !ph.value().is_empty() => {
let path = ph.value();
- qtrace!("Serve request {}", path);
- if path == "/success" {
+ qtrace!("Serve request {:?}", ph.value_utf8().unwrap_or("<invalid utf8>"));
+ if path == b"/success" {
session.response(&SessionAcceptAction::Accept, now).unwrap();
- } else if path == "/redirect" {
+ } else if path == b"/redirect" {
session
.response(
&SessionAcceptAction::Reject(
@@ -571,7 +571,7 @@ impl HttpServer for Http3TestServer {
now,
)
.unwrap();
- } else if path == "/reject" {
+ } else if path == b"/reject" {
session
.response(
&SessionAcceptAction::Reject(
@@ -580,13 +580,13 @@ impl HttpServer for Http3TestServer {
now,
)
.unwrap();
- } else if path == "/closeafter0ms" {
+ } else if path == b"/closeafter0ms" {
session.response(&SessionAcceptAction::Accept, now).unwrap();
if !self.sessions_to_close.contains_key(&now) {
self.sessions_to_close.insert(now, Vec::new());
}
self.sessions_to_close.get_mut(&now).unwrap().push(session);
- } else if path == "/closeafter100ms" {
+ } else if path == b"/closeafter100ms" {
session.response(&SessionAcceptAction::Accept, now).unwrap();
let expires = Instant::now() + Duration::from_millis(100);
if !self.sessions_to_close.contains_key(&expires) {
@@ -596,28 +596,28 @@ impl HttpServer for Http3TestServer {
.get_mut(&expires)
.unwrap()
.push(session);
- } else if path == "/create_unidi_stream" {
+ } else if path == b"/create_unidi_stream" {
session.response(&SessionAcceptAction::Accept, now).unwrap();
self.sessions_to_create_stream.push((
session,
StreamType::UniDi,
None,
));
- } else if path == "/create_unidi_stream_and_hello" {
+ } else if path == b"/create_unidi_stream_and_hello" {
session.response(&SessionAcceptAction::Accept, now).unwrap();
self.sessions_to_create_stream.push((
session,
StreamType::UniDi,
Some(Vec::from("qwerty")),
));
- } else if path == "/create_bidi_stream" {
+ } else if path == b"/create_bidi_stream" {
session.response(&SessionAcceptAction::Accept, now).unwrap();
self.sessions_to_create_stream.push((
session,
StreamType::BiDi,
None,
));
- } else if path == "/create_bidi_stream_and_hello" {
+ } else if path == b"/create_bidi_stream_and_hello" {
self.webtransport_bidi_stream.clear();
session.response(&SessionAcceptAction::Accept, now).unwrap();
self.sessions_to_create_stream.push((
@@ -625,7 +625,7 @@ impl HttpServer for Http3TestServer {
StreamType::BiDi,
Some(Vec::from("asdfg")),
));
- } else if path == "/create_bidi_stream_and_large_data" {
+ } else if path == b"/create_bidi_stream_and_large_data" {
self.webtransport_bidi_stream.clear();
let data: Vec<u8> = vec![1u8; 32 * 1024 * 1024];
session.response(&SessionAcceptAction::Accept, now).unwrap();
@@ -857,23 +857,23 @@ impl Http3ReverseProxyServer {
for hdr in request_headers.iter() {
match hdr.name() {
":method" => {
- *request.method_mut() = Method::from_bytes(hdr.value().as_bytes()).unwrap();
+ *request.method_mut() = Method::from_bytes(hdr.value()).unwrap();
}
":scheme" => {}
":authority" => {
request.headers_mut().insert(
hyper::header::HOST,
- HeaderValue::from_str(hdr.value()).unwrap(),
+ HeaderValue::from_bytes(hdr.value()).unwrap(),
);
}
":path" => {
- path = String::from(hdr.value());
+ path = hdr.value_utf8().unwrap_or("/").to_string();
}
_ => {
if let Ok(hdr_name) = HeaderName::from_lowercase(hdr.name().as_bytes()) {
request
.headers_mut()
- .insert(hdr_name, HeaderValue::from_str(hdr.value()).unwrap());
+ .insert(hdr_name, HeaderValue::from_bytes(hdr.value()).unwrap());
}
}
}
@@ -993,11 +993,11 @@ impl HttpServer for Http3ReverseProxyServer {
let method_hdr = headers.iter().find(|&h| h.name() == ":method");
match method_hdr {
Some(method) => match method.value() {
- "POST" => {
+ b"POST" => {
let content_length =
headers.iter().find(|&h| h.name() == "content-length");
if let Some(length_str) = content_length {
- if let Ok(len) = length_str.value().parse::<u32>() {
+ if let Ok(len) = length_str.value_utf8().unwrap_or("0").parse::<u32>() {
if len > 0 {
self.requests.insert(stream, (headers, Vec::new()));
} else {
@@ -1016,16 +1016,14 @@ impl HttpServer for Http3ReverseProxyServer {
let path_hdr = headers.iter().find(|&h| h.name() == ":path");
match path_hdr {
Some(ph) if !ph.value().is_empty() => {
- let path = ph.value();
- match &path[..6] {
- "/port?" => {
- let port = path[6..].parse::<i32>();
- if let Ok(port) = port {
+ if let Some(path_str) = ph.value_utf8().ok() {
+ if let Some(port_str) = path_str.strip_prefix("/port?") {
+ let port = port_str.parse::<i32>().ok();
+ if let Some(port) = port {
qtrace!("got port {}", port);
self.server_port = port;
}
}
- _ => {}
}
}
_ => {}
@@ -1123,17 +1121,18 @@ impl HttpServer for Http3ConnectProxyServer {
let method_hdr = headers.iter().find(|&h| h.name() == ":method").unwrap();
assert_eq!(
method_hdr.value(),
- "CONNECT",
- "{} not supported",
- method_hdr.value()
+ b"CONNECT",
+ "{:?} not supported",
+ method_hdr.value_utf8().unwrap_or("<invalid utf8>")
);
let host_hdr = headers.iter().find(|&h| h.name() == ":authority").unwrap();
+ let host_str = host_hdr.value_utf8().unwrap();
// Check if we should fallback to 127.0.0.1 before attempting connection
- let host_without_port = if let Some(colon_pos) = host_hdr.value().rfind(':') {
- &host_hdr.value()[..colon_pos]
+ let host_without_port = if let Some(colon_pos) = host_str.rfind(':') {
+ &host_str[..colon_pos]
} else {
- host_hdr.value()
+ host_str
};
let should_fallback = matches!(
@@ -1142,14 +1141,14 @@ impl HttpServer for Http3ConnectProxyServer {
);
let target = if should_fallback {
- if let Some(port_start) = host_hdr.value().rfind(':') {
- format!("127.0.0.1:{}", &host_hdr.value()[port_start + 1..])
+ if let Some(port_start) = host_str.rfind(':') {
+ format!("127.0.0.1:{}", &host_str[port_start + 1..])
} else {
// No port specified, assume default HTTP port 80
"127.0.0.1:80".to_string()
}
} else {
- host_hdr.value().to_string()
+ host_str.to_string()
};
let tcp_stream = match std::net::TcpStream::connect(&target) {
@@ -1217,18 +1216,19 @@ impl HttpServer for Http3ConnectProxyServer {
session.response(&SessionAcceptAction::Accept, now).unwrap();
let host_hdr = headers.iter().find(|&h| h.name() == ":path").unwrap();
- let path_parts: Vec<&str> = host_hdr.value().split('/').collect();
+ let path_str = host_hdr.value_utf8().unwrap();
+ let path_parts: Vec<&str> = path_str.split('/').collect();
// Format is /.well-known/masque/udp/{target_host}/{target_port}/
if path_parts.len() < 6 {
- panic!("{}", host_hdr.value())
+ panic!("{}", path_str)
}
let target_host = path_parts[4];
let target_port = match path_parts[5].trim_end_matches('/').parse::<u16>() {
Ok(port) => port,
Err(_) => {
- panic!("{}", host_hdr.value())
+ panic!("{}", path_str)
}
};