h3: don't use UTF-8 strings to represent headers
There is not requirement for HTTP/3 header names and values to be valid
UTF-8, so don't require it.
diff --git a/examples/http3-client.rs b/examples/http3-client.rs
index 07a5a1a..2acb2ca 100644
--- a/examples/http3-client.rs
+++ b/examples/http3-client.rs
@@ -141,11 +141,14 @@
}
let req = vec![
- quiche::h3::Header::new(":method", "GET"),
- quiche::h3::Header::new(":scheme", url.scheme()),
- quiche::h3::Header::new(":authority", url.host_str().unwrap()),
- quiche::h3::Header::new(":path", &path),
- quiche::h3::Header::new("user-agent", "quiche"),
+ quiche::h3::Header::new(b":method", b"GET"),
+ quiche::h3::Header::new(b":scheme", url.scheme().as_bytes()),
+ quiche::h3::Header::new(
+ b":authority",
+ url.host_str().unwrap().as_bytes(),
+ ),
+ quiche::h3::Header::new(b":path", path.as_bytes()),
+ quiche::h3::Header::new(b"user-agent", b"quiche"),
];
let req_start = std::time::Instant::now();
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index b1fc1ed..e84d1ea 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -560,25 +560,24 @@
) -> (Vec<quiche::h3::Header>, Vec<u8>) {
let mut file_path = std::path::PathBuf::from(root);
let mut path = std::path::Path::new("");
- let mut method = "";
+ let mut method = None;
// Look for the request's path and method.
for hdr in request {
match hdr.name() {
- ":path" => {
- path = std::path::Path::new(hdr.value());
- },
+ b":path" =>
+ path = std::path::Path::new(
+ std::str::from_utf8(hdr.value()).unwrap(),
+ ),
- ":method" => {
- method = hdr.value();
- },
+ b":method" => method = Some(hdr.value()),
_ => (),
}
}
let (status, body) = match method {
- "GET" => {
+ Some(b"GET") => {
for c in path.components() {
if let std::path::Component::Normal(v) = c {
file_path.push(v)
@@ -596,9 +595,12 @@
};
let headers = vec![
- quiche::h3::Header::new(":status", &status.to_string()),
- quiche::h3::Header::new("server", "quiche"),
- quiche::h3::Header::new("content-length", &body.len().to_string()),
+ quiche::h3::Header::new(b":status", status.to_string().as_bytes()),
+ quiche::h3::Header::new(b"server", b"quiche"),
+ quiche::h3::Header::new(
+ b"content-length",
+ body.len().to_string().as_bytes(),
+ ),
];
(headers, body)
diff --git a/examples/qpack-decode.rs b/examples/qpack-decode.rs
index 8468a85..d2aaaa5 100644
--- a/examples/qpack-decode.rs
+++ b/examples/qpack-decode.rs
@@ -77,7 +77,9 @@
}
for hdr in dec.decode(&data[..len], std::u64::MAX).unwrap() {
- println!("{}\t{}", hdr.name(), hdr.value());
+ let name = std::str::from_utf8(hdr.name()).unwrap();
+ let value = std::str::from_utf8(hdr.value()).unwrap();
+ println!("{}\t{}", name, value);
}
println!();
diff --git a/examples/qpack-encode.rs b/examples/qpack-encode.rs
index e381227..5215fe4 100644
--- a/examples/qpack-encode.rs
+++ b/examples/qpack-encode.rs
@@ -83,6 +83,6 @@
let name = line.split('\t').next().unwrap();
let value = line.split('\t').last().unwrap();
- headers.push(h3::Header::new(name, value));
+ headers.push(h3::Header::new(name.as_bytes(), value.as_bytes()));
}
}
diff --git a/src/h3/ffi.rs b/src/h3/ffi.rs
index 66cd9c5..fc254b0 100644
--- a/src/h3/ffi.rs
+++ b/src/h3/ffi.rs
@@ -27,7 +27,6 @@
use std::ffi;
use std::ptr;
use std::slice;
-use std::str;
use libc::c_char;
use libc::c_int;
@@ -324,15 +323,8 @@
for h in headers {
out.push({
- let name = unsafe {
- let slice = slice::from_raw_parts(h.name, h.name_len);
- str::from_utf8_unchecked(slice)
- };
-
- let value = unsafe {
- let slice = slice::from_raw_parts(h.value, h.value_len);
- str::from_utf8_unchecked(slice)
- };
+ let name = unsafe { slice::from_raw_parts(h.name, h.name_len) };
+ let value = unsafe { slice::from_raw_parts(h.value, h.value_len) };
h3::HeaderRef::new(name, value)
});
diff --git a/src/h3/mod.rs b/src/h3/mod.rs
index 60fd3af..24b84b0 100644
--- a/src/h3/mod.rs
+++ b/src/h3/mod.rs
@@ -81,11 +81,11 @@
//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! let req = vec![
-//! quiche::h3::Header::new(":method", "GET"),
-//! quiche::h3::Header::new(":scheme", "https"),
-//! quiche::h3::Header::new(":authority", "quic.tech"),
-//! quiche::h3::Header::new(":path", "/"),
-//! quiche::h3::Header::new("user-agent", "quiche"),
+//! quiche::h3::Header::new(b":method", b"GET"),
+//! quiche::h3::Header::new(b":scheme", b"https"),
+//! quiche::h3::Header::new(b":authority", b"quic.tech"),
+//! quiche::h3::Header::new(b":path", b"/"),
+//! quiche::h3::Header::new(b"user-agent", b"quiche"),
//! ];
//!
//! h3_conn.send_request(&mut conn, &req, true)?;
@@ -103,11 +103,11 @@
//! # let h3_config = quiche::h3::Config::new()?;
//! # let mut h3_conn = quiche::h3::Connection::with_transport(&mut conn, &h3_config)?;
//! let req = vec![
-//! quiche::h3::Header::new(":method", "GET"),
-//! quiche::h3::Header::new(":scheme", "https"),
-//! quiche::h3::Header::new(":authority", "quic.tech"),
-//! quiche::h3::Header::new(":path", "/"),
-//! quiche::h3::Header::new("user-agent", "quiche"),
+//! quiche::h3::Header::new(b":method", b"GET"),
+//! quiche::h3::Header::new(b":scheme", b"https"),
+//! quiche::h3::Header::new(b":authority", b"quic.tech"),
+//! quiche::h3::Header::new(b":path", b"/"),
+//! quiche::h3::Header::new(b"user-agent", b"quiche"),
//! ];
//!
//! let stream_id = h3_conn.send_request(&mut conn, &req, false)?;
@@ -139,15 +139,15 @@
//! let mut headers = list.into_iter();
//!
//! // Look for the request's method.
-//! let method = headers.find(|h| h.name() == ":method").unwrap();
+//! let method = headers.find(|h| h.name() == b":method").unwrap();
//!
//! // Look for the request's path.
-//! let path = headers.find(|h| h.name() == ":path").unwrap();
+//! let path = headers.find(|h| h.name() == b":path").unwrap();
//!
-//! if method.value() == "GET" && path.value() == "/" {
+//! if method.value() == b"GET" && path.value() == b"/" {
//! let resp = vec![
-//! quiche::h3::Header::new(":status", &200.to_string()),
-//! quiche::h3::Header::new("server", "quiche"),
+//! quiche::h3::Header::new(b":status", 200.to_string().as_bytes()),
+//! quiche::h3::Header::new(b"server", b"quiche"),
//! ];
//!
//! h3_conn.send_response(&mut conn, stream_id, &resp, false)?;
@@ -198,9 +198,10 @@
//! loop {
//! match h3_conn.poll(&mut conn) {
//! Ok((stream_id, quiche::h3::Event::Headers{list, has_body})) => {
-//! let status = list.iter().find(|h| h.name() == ":status").unwrap();
+//! let status = list.iter().find(|h| h.name() == b":status").unwrap();
//! println!("Received {} response on stream {}",
-//! status.value(), stream_id);
+//! std::str::from_utf8(status.value()).unwrap(),
+//! stream_id);
//! },
//!
//! Ok((stream_id, quiche::h3::Event::Data)) => {
@@ -494,52 +495,52 @@
/// A trait for types with associated string name and value.
pub trait NameValue {
/// Returns the object's name.
- fn name(&self) -> &str;
+ fn name(&self) -> &[u8];
/// Returns the object's value.
- fn value(&self) -> &str;
+ fn value(&self) -> &[u8];
}
/// An owned name-value pair representing a raw HTTP header.
#[derive(Clone, Debug, PartialEq)]
-pub struct Header(String, String);
+pub struct Header(Vec<u8>, Vec<u8>);
impl Header {
/// Creates a new header.
///
/// Both `name` and `value` will be cloned.
- pub fn new(name: &str, value: &str) -> Self {
- Self(String::from(name), String::from(value))
+ pub fn new(name: &[u8], value: &[u8]) -> Self {
+ Self(name.to_vec(), value.to_vec())
}
}
impl NameValue for Header {
- fn name(&self) -> &str {
+ fn name(&self) -> &[u8] {
&self.0
}
- fn value(&self) -> &str {
+ fn value(&self) -> &[u8] {
&self.1
}
}
/// A non-owned name-value pair representing a raw HTTP header.
#[derive(Clone, Debug, PartialEq)]
-pub struct HeaderRef<'a>(&'a str, &'a str);
+pub struct HeaderRef<'a>(&'a [u8], &'a [u8]);
impl<'a> HeaderRef<'a> {
/// Creates a new header.
- pub fn new(name: &'a str, value: &'a str) -> Self {
+ pub fn new(name: &'a [u8], value: &'a [u8]) -> Self {
Self(name, value)
}
}
impl<'a> NameValue for HeaderRef<'a> {
- fn name(&self) -> &str {
+ fn name(&self) -> &[u8] {
self.0
}
- fn value(&self) -> &str {
+ fn value(&self) -> &[u8] {
self.1
}
}
@@ -2201,11 +2202,11 @@
/// On success it returns the newly allocated stream and the headers.
pub fn send_request(&mut self, fin: bool) -> Result<(u64, Vec<Header>)> {
let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
- Header::new("user-agent", "quiche-test"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
+ Header::new(b"user-agent", b"quiche-test"),
];
let stream =
@@ -2223,8 +2224,8 @@
&mut self, stream: u64, fin: bool,
) -> Result<Vec<Header>> {
let resp = vec![
- Header::new(":status", "200"),
- Header::new("server", "quiche-test"),
+ Header::new(b":status", b"200"),
+ Header::new(b"server", b"quiche-test"),
];
self.server.send_response(
@@ -3242,11 +3243,11 @@
s.handshake().unwrap();
let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
- Header::new("user-agent", "quiche-test"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
+ Header::new(b"user-agent", b"quiche-test"),
];
assert_eq!(
@@ -3384,11 +3385,11 @@
s.handshake().unwrap();
let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
- Header::new("aaaaaaa", "aaaaaaaa"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
+ Header::new(b"aaaaaaa", b"aaaaaaaa"),
];
let stream = s
@@ -3415,11 +3416,11 @@
s.handshake().unwrap();
let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
- Header::new("user-agent", "quiche-test"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
+ Header::new(b"user-agent", b"quiche-test"),
];
// We need to open all streams in the same flight, so we can't use the
@@ -3520,10 +3521,10 @@
s.handshake().unwrap();
let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
];
assert_eq!(s.client.send_request(&mut s.pipe.client, &req, true), Ok(0));
@@ -3621,10 +3622,10 @@
s.handshake().unwrap();
let req = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "https"),
- Header::new(":authority", "quic.tech"),
- Header::new(":path", "/test"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"https"),
+ Header::new(b":authority", b"quic.tech"),
+ Header::new(b":path", b"/test"),
];
assert_eq!(
@@ -4295,7 +4296,7 @@
// Send more data, then HEADERS, then more data.
let body = s.send_body_client(stream, false).unwrap();
- let trailers = vec![Header::new("hello", "world")];
+ let trailers = vec![Header::new(b"hello", b"world")];
s.client
.send_headers(&mut s.pipe.client, stream, &trailers, false)
diff --git a/src/h3/qpack/decoder.rs b/src/h3/qpack/decoder.rs
index 3f787c7..1bc5755 100644
--- a/src/h3/qpack/decoder.rs
+++ b/src/h3/qpack/decoder.rs
@@ -149,9 +149,7 @@
name.to_vec()
};
- let name = String::from_utf8(name)
- .map_err(|_| Error::InvalidHeaderValue)?;
-
+ let name = name.to_vec();
let value = decode_str(&mut b)?;
trace!(
@@ -198,7 +196,7 @@
// Instead of calling Header::new(), create Header directly
// from `value`, which is already String, but clone `name`
// as it is just a reference.
- let hdr = Header(name.to_string(), value);
+ let hdr = Header(name.to_vec(), value);
out.push(hdr);
},
@@ -215,7 +213,7 @@
}
}
-fn lookup_static(idx: u64) -> Result<(&'static str, &'static str)> {
+fn lookup_static(idx: u64) -> Result<(&'static [u8], &'static [u8])> {
if idx >= super::static_table::STATIC_TABLE.len() as u64 {
return Err(Error::InvalidStaticTableIndex);
}
@@ -254,7 +252,7 @@
Err(Error::BufferTooShort)
}
-fn decode_str(b: &mut octets::Octets) -> Result<String> {
+fn decode_str(b: &mut octets::Octets) -> Result<Vec<u8>> {
let first = b.peek_u8()?;
let huff = first & 0x80 == 0x80;
@@ -269,7 +267,6 @@
val.to_vec()
};
- let val = String::from_utf8(val).map_err(|_| Error::InvalidHeaderValue)?;
Ok(val)
}
diff --git a/src/h3/qpack/encoder.rs b/src/h3/qpack/encoder.rs
index 24a28c2..09c8b08 100644
--- a/src/h3/qpack/encoder.rs
+++ b/src/h3/qpack/encoder.rs
@@ -80,14 +80,12 @@
None => {
// Encode as fully literal.
- let name_len = super::huffman::encode_output_length(
- h.name().as_bytes(),
- true,
- )?;
+ let name_len =
+ super::huffman::encode_output_length(h.name(), true)?;
encode_int(name_len as u64, LITERAL | 0x08, 3, &mut b)?;
- super::huffman::encode(h.name().as_bytes(), &mut b, true)?;
+ super::huffman::encode(h.name(), &mut b, true)?;
encode_str(h.value(), 7, &mut b)?;
},
@@ -151,12 +149,12 @@
Ok(())
}
-fn encode_str(v: &str, prefix: usize, b: &mut octets::OctetsMut) -> Result<()> {
- let len = super::huffman::encode_output_length(v.as_bytes(), false)?;
+fn encode_str(v: &[u8], prefix: usize, b: &mut octets::OctetsMut) -> Result<()> {
+ let len = super::huffman::encode_output_length(v, false)?;
encode_int(len as u64, 0x80, prefix, b)?;
- super::huffman::encode(v.as_bytes(), b, false)?;
+ super::huffman::encode(v, b, false)?;
Ok(())
}
diff --git a/src/h3/qpack/mod.rs b/src/h3/qpack/mod.rs
index 6f2bdda..0a23306 100644
--- a/src/h3/qpack/mod.rs
+++ b/src/h3/qpack/mod.rs
@@ -87,15 +87,15 @@
let mut encoded = [0u8; 240];
let headers = vec![
- h3::Header::new(":path", "/rsrc.php/v3/yn/r/rIPZ9Qkrdd9.png"),
- h3::Header::new("accept-encoding", "gzip, deflate, br"),
- h3::Header::new("accept-language", "en-US,en;q=0.9"),
- h3::Header::new("user-agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.70 Safari/537.36"),
- h3::Header::new("accept", "image/webp,image/apng,image/*,*/*;q=0.8"),
- h3::Header::new("referer", "https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/dzXGESIlGQQ.css"),
- h3::Header::new(":authority", "static.xx.fbcdn.net"),
- h3::Header::new(":scheme", "https"),
- h3::Header::new(":method", "GET"),
+ h3::Header::new(b":path", b"/rsrc.php/v3/yn/r/rIPZ9Qkrdd9.png"),
+ h3::Header::new(b"accept-encoding", b"gzip, deflate, br"),
+ h3::Header::new(b"accept-language", b"en-US,en;q=0.9"),
+ h3::Header::new(b"user-agent", b"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.70 Safari/537.36"),
+ h3::Header::new(b"accept", b"image/webp,image/apng,image/*,*/*;q=0.8"),
+ h3::Header::new(b"referer", b"https://static.xx.fbcdn.net/rsrc.php/v3/yT/l/0,cross/dzXGESIlGQQ.css"),
+ h3::Header::new(b":authority", b"static.xx.fbcdn.net"),
+ h3::Header::new(b":scheme", b"https"),
+ h3::Header::new(b":method", b"GET"),
];
let mut enc = Encoder::new();
@@ -110,20 +110,20 @@
let mut encoded = [0u8; 35];
let headers_expected = vec![
- crate::h3::Header::new(":status", "200"),
- crate::h3::Header::new(":path", "/HeLlO"),
- crate::h3::Header::new("woot", "woot"),
- crate::h3::Header::new("hello", "WorlD"),
- crate::h3::Header::new("foo", "BaR"),
+ crate::h3::Header::new(b":status", b"200"),
+ crate::h3::Header::new(b":path", b"/HeLlO"),
+ crate::h3::Header::new(b"woot", b"woot"),
+ crate::h3::Header::new(b"hello", b"WorlD"),
+ crate::h3::Header::new(b"foo", b"BaR"),
];
// Header.
let headers_in = vec![
- crate::h3::Header::new(":StAtUs", "200"),
- crate::h3::Header::new(":PaTh", "/HeLlO"),
- crate::h3::Header::new("WooT", "woot"),
- crate::h3::Header::new("hello", "WorlD"),
- crate::h3::Header::new("fOo", "BaR"),
+ crate::h3::Header::new(b":StAtUs", b"200"),
+ crate::h3::Header::new(b":PaTh", b"/HeLlO"),
+ crate::h3::Header::new(b"WooT", b"woot"),
+ crate::h3::Header::new(b"hello", b"WorlD"),
+ crate::h3::Header::new(b"fOo", b"BaR"),
];
let mut enc = Encoder::new();
@@ -136,11 +136,11 @@
// HeaderRef.
let headers_in = vec![
- crate::h3::HeaderRef::new(":StAtUs", "200"),
- crate::h3::HeaderRef::new(":PaTh", "/HeLlO"),
- crate::h3::HeaderRef::new("WooT", "woot"),
- crate::h3::HeaderRef::new("hello", "WorlD"),
- crate::h3::HeaderRef::new("fOo", "BaR"),
+ crate::h3::HeaderRef::new(b":StAtUs", b"200"),
+ crate::h3::HeaderRef::new(b":PaTh", b"/HeLlO"),
+ crate::h3::HeaderRef::new(b"WooT", b"woot"),
+ crate::h3::HeaderRef::new(b"hello", b"WorlD"),
+ crate::h3::HeaderRef::new(b"fOo", b"BaR"),
];
let mut enc = Encoder::new();
diff --git a/src/h3/qpack/static_table.rs b/src/h3/qpack/static_table.rs
index 4010d12..3cc10d4 100644
--- a/src/h3/qpack/static_table.rs
+++ b/src/h3/qpack/static_table.rs
@@ -24,113 +24,113 @@
// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-pub const STATIC_TABLE: [(&str, &str); 99] = [
- (":authority", ""),
- (":path", "/"),
- ("age", "0"),
- ("content-disposition", ""),
- ("content-length", "0"),
- ("cookie", ""),
- ("date", ""),
- ("etag", ""),
- ("if-modified-since", ""),
- ("if-none-match", ""),
- ("last-modified", ""),
- ("link", ""),
- ("location", ""),
- ("referer", ""),
- ("set-cookie", ""),
- (":method", "CONNECT"),
- (":method", "DELETE"),
- (":method", "GET"),
- (":method", "HEAD"),
- (":method", "OPTIONS"),
- (":method", "POST"),
- (":method", "PUT"),
- (":scheme", "http"),
- (":scheme", "https"),
- (":status", "103"),
- (":status", "200"),
- (":status", "304"),
- (":status", "404"),
- (":status", "503"),
- ("accept", "*/*"),
- ("accept", "application/dns-message"),
- ("accept-encoding", "gzip, deflate, br"),
- ("accept-ranges", "bytes"),
- ("access-control-allow-headers", "cache-control"),
- ("access-control-allow-headers", "content-type"),
- ("access-control-allow-origin", "*"),
- ("cache-control", "max-age=0"),
- ("cache-control", "max-age=2592000"),
- ("cache-control", "max-age=604800"),
- ("cache-control", "no-cache"),
- ("cache-control", "no-store"),
- ("cache-control", "public, max-age=31536000"),
- ("content-encoding", "br"),
- ("content-encoding", "gzip"),
- ("content-type", "application/dns-message"),
- ("content-type", "application/javascript"),
- ("content-type", "application/json"),
- ("content-type", "application/x-www-form-urlencoded"),
- ("content-type", "image/gif"),
- ("content-type", "image/jpeg"),
- ("content-type", "image/png"),
- ("content-type", "text/css"),
- ("content-type", "text/html; charset=utf-8"),
- ("content-type", "text/plain"),
- ("content-type", "text/plain;charset=utf-8"),
- ("range", "bytes=0-"),
- ("strict-transport-security", "max-age=31536000"),
+pub const STATIC_TABLE: [(&[u8], &[u8]); 99] = [
+ (b":authority", b""),
+ (b":path", b"/"),
+ (b"age", b"0"),
+ (b"content-disposition", b""),
+ (b"content-length", b"0"),
+ (b"cookie", b""),
+ (b"date", b""),
+ (b"etag", b""),
+ (b"if-modified-since", b""),
+ (b"if-none-match", b""),
+ (b"last-modified", b""),
+ (b"link", b""),
+ (b"location", b""),
+ (b"referer", b""),
+ (b"set-cookie", b""),
+ (b":method", b"CONNECT"),
+ (b":method", b"DELETE"),
+ (b":method", b"GET"),
+ (b":method", b"HEAD"),
+ (b":method", b"OPTIONS"),
+ (b":method", b"POST"),
+ (b":method", b"PUT"),
+ (b":scheme", b"http"),
+ (b":scheme", b"https"),
+ (b":status", b"103"),
+ (b":status", b"200"),
+ (b":status", b"304"),
+ (b":status", b"404"),
+ (b":status", b"503"),
+ (b"accept", b"*/*"),
+ (b"accept", b"application/dns-message"),
+ (b"accept-encoding", b"gzip, deflate, br"),
+ (b"accept-ranges", b"bytes"),
+ (b"access-control-allow-headers", b"cache-control"),
+ (b"access-control-allow-headers", b"content-type"),
+ (b"access-control-allow-origin", b"*"),
+ (b"cache-control", b"max-age=0"),
+ (b"cache-control", b"max-age=2592000"),
+ (b"cache-control", b"max-age=604800"),
+ (b"cache-control", b"no-cache"),
+ (b"cache-control", b"no-store"),
+ (b"cache-control", b"public, max-age=31536000"),
+ (b"content-encoding", b"br"),
+ (b"content-encoding", b"gzip"),
+ (b"content-type", b"application/dns-message"),
+ (b"content-type", b"application/javascript"),
+ (b"content-type", b"application/json"),
+ (b"content-type", b"application/x-www-form-urlencoded"),
+ (b"content-type", b"image/gif"),
+ (b"content-type", b"image/jpeg"),
+ (b"content-type", b"image/png"),
+ (b"content-type", b"text/css"),
+ (b"content-type", b"text/html; charset=utf-8"),
+ (b"content-type", b"text/plain"),
+ (b"content-type", b"text/plain;charset=utf-8"),
+ (b"range", b"bytes=0-"),
+ (b"strict-transport-security", b"max-age=31536000"),
(
- "strict-transport-security",
- "max-age=31536000; includesubdomains",
+ b"strict-transport-security",
+ b"max-age=31536000; includesubdomains",
),
(
- "strict-transport-security",
- "max-age=31536000; includesubdomains; preload",
+ b"strict-transport-security",
+ b"max-age=31536000; includesubdomains; preload",
),
- ("vary", "accept-encoding"),
- ("vary", "origin"),
- ("x-content-type-options", "nosniff"),
- ("x-xss-protection", "1; mode=block"),
- (":status", "100"),
- (":status", "204"),
- (":status", "206"),
- (":status", "302"),
- (":status", "400"),
- (":status", "403"),
- (":status", "421"),
- (":status", "425"),
- (":status", "500"),
- ("accept-language", ""),
- ("access-control-allow-credentials", "FALSE"),
- ("access-control-allow-credentials", "TRUE"),
- ("access-control-allow-headers", "*"),
- ("access-control-allow-methods", "get"),
- ("access-control-allow-methods", "get, post, options"),
- ("access-control-allow-methods", "options"),
- ("access-control-expose-headers", "content-length"),
- ("access-control-request-headers", "content-type"),
- ("access-control-request-method", "get"),
- ("access-control-request-method", "post"),
- ("alt-svc", "clear"),
- ("authorization", ""),
+ (b"vary", b"accept-encoding"),
+ (b"vary", b"origin"),
+ (b"x-content-type-options", b"nosniff"),
+ (b"x-xss-protection", b"1; mode=block"),
+ (b":status", b"100"),
+ (b":status", b"204"),
+ (b":status", b"206"),
+ (b":status", b"302"),
+ (b":status", b"400"),
+ (b":status", b"403"),
+ (b":status", b"421"),
+ (b":status", b"425"),
+ (b":status", b"500"),
+ (b"accept-language", b""),
+ (b"access-control-allow-credentials", b"FALSE"),
+ (b"access-control-allow-credentials", b"TRUE"),
+ (b"access-control-allow-headers", b"*"),
+ (b"access-control-allow-methods", b"get"),
+ (b"access-control-allow-methods", b"get, post, options"),
+ (b"access-control-allow-methods", b"options"),
+ (b"access-control-expose-headers", b"content-length"),
+ (b"access-control-request-headers", b"content-type"),
+ (b"access-control-request-method", b"get"),
+ (b"access-control-request-method", b"post"),
+ (b"alt-svc", b"clear"),
+ (b"authorization", b""),
(
- "content-security-policy",
- "script-src 'none'; object-src 'none'; base-uri 'none'",
+ b"content-security-policy",
+ b"script-src 'none'; object-src 'none'; base-uri 'none'",
),
- ("early-data", "1"),
- ("expect-ct", ""),
- ("forwarded", ""),
- ("if-range", ""),
- ("origin", ""),
- ("purpose", "prefetch"),
- ("server", ""),
- ("timing-allow-origin", "*"),
- ("upgrade-insecure-requests", "1"),
- ("user-agent", ""),
- ("x-forwarded-for", ""),
- ("x-frame-options", "deny"),
- ("x-frame-options", "sameorigin"),
+ (b"early-data", b"1"),
+ (b"expect-ct", b""),
+ (b"forwarded", b""),
+ (b"if-range", b""),
+ (b"origin", b""),
+ (b"purpose", b"prefetch"),
+ (b"server", b""),
+ (b"timing-allow-origin", b"*"),
+ (b"upgrade-insecure-requests", b"1"),
+ (b"user-agent", b""),
+ (b"x-forwarded-for", b""),
+ (b"x-frame-options", b"deny"),
+ (b"x-frame-options", b"sameorigin"),
];
diff --git a/tools/apps/src/common.rs b/tools/apps/src/common.rs
index fa1d7d8..c97274f 100644
--- a/tools/apps/src/common.rs
+++ b/tools/apps/src/common.rs
@@ -174,8 +174,20 @@
let mut req_hdrs = req.hdrs.iter().peekable();
while let Some(h) = req_hdrs.next() {
writeln!(out, " {{").unwrap();
- writeln!(out, " \"name\": \"{}\",", h.name()).unwrap();
- writeln!(out, " \"value\": \"{}\"", h.value()).unwrap();
+ writeln!(
+ out,
+ " \"name\": \"{}\",",
+ std::str::from_utf8(h.name()).unwrap()
+ )
+ .unwrap();
+ writeln!(
+ out,
+ " \"value\": \"{}\"",
+ std::str::from_utf8(h.value())
+ .unwrap()
+ .replace("\"", "\\\"")
+ )
+ .unwrap();
if req_hdrs.peek().is_some() {
writeln!(out, " }},").unwrap();
@@ -191,11 +203,18 @@
let mut response_hdrs = req.response_hdrs.iter().peekable();
while let Some(h) = response_hdrs.next() {
writeln!(out, " {{").unwrap();
- writeln!(out, " \"name\": \"{}\",", h.name()).unwrap();
+ writeln!(
+ out,
+ " \"name\": \"{}\",",
+ std::str::from_utf8(h.name()).unwrap()
+ )
+ .unwrap();
writeln!(
out,
" \"value\": \"{}\"",
- h.value().replace("\"", "\\\"")
+ std::str::from_utf8(h.value())
+ .unwrap()
+ .replace("\"", "\\\"")
)
.unwrap();
@@ -790,34 +809,35 @@
};
let mut hdrs = vec![
- quiche::h3::Header::new(":method", &method),
- quiche::h3::Header::new(":scheme", url.scheme()),
- quiche::h3::Header::new(":authority", &authority),
+ quiche::h3::Header::new(b":method", method.as_bytes()),
+ quiche::h3::Header::new(b":scheme", url.scheme().as_bytes()),
+ quiche::h3::Header::new(b":authority", authority.as_bytes()),
quiche::h3::Header::new(
- ":path",
- &url[url::Position::BeforePath..],
+ b":path",
+ &url[url::Position::BeforePath..].as_bytes(),
),
- quiche::h3::Header::new("user-agent", "quiche"),
+ quiche::h3::Header::new(b"user-agent", b"quiche"),
];
// Add custom headers to the request.
for header in req_headers {
let header_split: Vec<&str> =
header.splitn(2, ": ").collect();
+
if header_split.len() != 2 {
panic!("malformed header provided - \"{}\"", header);
}
hdrs.push(quiche::h3::Header::new(
- header_split[0],
- header_split[1],
+ header_split[0].as_bytes(),
+ header_split[1].as_bytes(),
));
}
if body.is_some() {
hdrs.push(quiche::h3::Header::new(
- "content-length",
- &body.as_ref().unwrap().len().to_string(),
+ b"content-length",
+ body.as_ref().unwrap().len().to_string().as_bytes(),
));
}
@@ -892,25 +912,17 @@
// Parse some of the request headers.
for hdr in request {
match hdr.name() {
- ":scheme" => {
- scheme = hdr.value();
- },
+ b":scheme" => scheme = std::str::from_utf8(hdr.value()).unwrap(),
- ":authority" | "host" => {
- host = hdr.value();
- },
+ b":authority" | b"host" =>
+ host = std::str::from_utf8(hdr.value()).unwrap(),
- ":path" => {
- path = hdr.value();
- },
+ b":path" => path = std::str::from_utf8(hdr.value()).unwrap(),
- ":method" => {
- method = hdr.value();
- },
+ b":method" => method = std::str::from_utf8(hdr.value()).unwrap(),
- "priority" => {
- priority = hdr.value();
- },
+ b"priority" =>
+ priority = std::str::from_utf8(hdr.value()).unwrap(),
_ => (),
}
@@ -918,8 +930,8 @@
if scheme != "http" && scheme != "https" {
let headers = vec![
- quiche::h3::Header::new(":status", &"400".to_string()),
- quiche::h3::Header::new("server", "quiche"),
+ quiche::h3::Header::new(b":status", "400".to_string().as_bytes()),
+ quiche::h3::Header::new(b"server", b"quiche"),
];
return (headers, b"Invalid scheme".to_vec(), priority.to_string());
@@ -967,13 +979,17 @@
};
let mut headers = vec![
- quiche::h3::Header::new(":status", &status.to_string()),
- quiche::h3::Header::new("server", "quiche"),
- quiche::h3::Header::new("content-length", &body.len().to_string()),
+ quiche::h3::Header::new(b":status", status.to_string().as_bytes()),
+ quiche::h3::Header::new(b"server", b"quiche"),
+ quiche::h3::Header::new(
+ b"content-length",
+ body.len().to_string().as_bytes(),
+ ),
];
if !priority.is_empty() {
- headers.push(quiche::h3::Header::new("priority", &priority));
+ headers
+ .push(quiche::h3::Header::new(b"priority", priority.as_bytes()));
}
(headers, body, priority.to_string())
diff --git a/tools/http3_test/src/lib.rs b/tools/http3_test/src/lib.rs
index ea36b99..15937c9 100644
--- a/tools/http3_test/src/lib.rs
+++ b/tools/http3_test/src/lib.rs
@@ -43,7 +43,7 @@
//! let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
//! let mut reqs = Vec::new();
//!
-//! reqs.push(http3_test::Http3Req::new("GET", &url, None, None));
+//! reqs.push(http3_test::Http3Req::new(b"GET", &url, None, None));
//! ```
//!
//! Assertions are used to check the received response headers and body
@@ -69,8 +69,8 @@
//! let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
//! let mut reqs = Vec::new();
//!
-//! let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
-//! reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! let expect_hdrs = Some(vec![quiche::h3::Header::new(b":status", "200")]);
+//! reqs.push(http3_test::Http3Req::new(b"GET", &url, None, expect_hdrs));
//! ```
//!
//! The [`assert_headers!`] macro can be used to validate the received headers,
@@ -89,8 +89,8 @@
//! let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
//! let mut reqs = Vec::new();
//!
-//! let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
-//! reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! let expect_hdrs = Some(vec![quiche::h3::Header::new(b":status", "200")]);
+//! reqs.push(http3_test::Http3Req::new(b"GET", &url, None, expect_hdrs));
//!
//! // Using a closure...
//! let assert =
@@ -113,8 +113,8 @@
//! ```no_run
//! # let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
//! # let mut reqs = Vec::new();
-//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
-//! # reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(b":status", "200")]);
+//! # reqs.push(http3_test::Http3Req::new(b"GET", &url, None, expect_hdrs));
//! # // Using a closure...
//! # let assert = |reqs: &[http3_test::Http3Req]| {
//! # http3_test::assert_headers!(reqs[0]);
@@ -144,8 +144,8 @@
//! ```no_run
//! # let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
//! # let mut reqs = Vec::new();
-//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
-//! # reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(b":status", "200")]);
+//! # reqs.push(http3_test::Http3Req::new(b"GET", &url, None, expect_hdrs));
//! # // Using a closure...
//! # let assert = |reqs: &[http3_test::Http3Req]| {
//! # http3_test::assert_headers!(reqs[0]);
@@ -184,8 +184,8 @@
//! ```no_run
//! # let mut url = url::Url::parse("https://cloudflare-quic.com/b/get").unwrap();
//! # let mut reqs = Vec::new();
-//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(":status", "200")]);
-//! # reqs.push(http3_test::Http3Req::new("GET", &url, None, expect_hdrs));
+//! # let expect_hdrs = Some(vec![quiche::h3::Header::new(b":status", "200")]);
+//! # reqs.push(http3_test::Http3Req::new(b"GET", &url, None, expect_hdrs));
//! # // Using a closure...
//! # let assert = |reqs: &[http3_test::Http3Req]| {
//! # http3_test::assert_headers!(reqs[0]);
@@ -231,7 +231,7 @@
use quiche::h3::Header;
-pub const USER_AGENT: &str = "quiche-http3-integration-client";
+pub const USER_AGENT: &[u8] = b"quiche-http3-integration-client";
/// Stores the request, the expected response headers, and the actual response.
///
@@ -259,15 +259,18 @@
}
let mut hdrs = vec![
- Header::new(":method", method),
- Header::new(":scheme", url.scheme()),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", method.as_bytes()),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
if let Some(body) = &body {
- hdrs.push(Header::new("content-length", &body.len().to_string()));
+ hdrs.push(Header::new(
+ b"content-length",
+ body.len().to_string().as_bytes(),
+ ));
}
Http3Req {
@@ -297,11 +300,10 @@
if let Some(expect_hdrs) = &$req.expect_resp_hdrs {
for hdr in expect_hdrs {
match $req.resp_hdrs.iter().find(|&x| x.name() == hdr.name()) {
- Some(h) => { assert_eq!(hdr.value(), h.value());},
+ Some(h) => assert_eq!(hdr.value(), h.value()),
- None => {
- panic!("assertion failed: expected response header field {} not present!", hdr.name());
- }
+ None =>
+ panic!("assertion failed: expected response header field {} not present!", std::str::from_utf8(hdr.name()).unwrap()),
}
}
}
diff --git a/tools/http3_test/tests/httpbin_tests.rs b/tools/http3_test/tests/httpbin_tests.rs
index 49d200e..ff53ebb 100644
--- a/tools/http3_test/tests/httpbin_tests.rs
+++ b/tools/http3_test/tests/httpbin_tests.rs
@@ -226,7 +226,8 @@
// Build a single request and expected response with status code
fn request_check_status(testpoint: &str, status: usize) -> Vec<Http3Req> {
- let expect_hdrs = Some(vec![Header::new(":status", &status.to_string())]);
+ let expect_hdrs =
+ Some(vec![Header::new(b":status", status.to_string().as_bytes())]);
let url = endpoint(Some(testpoint));
@@ -235,7 +236,7 @@
// Build a single request with a simple JSON body using the provided method
fn request_with_body(method: &str) -> Vec<Http3Req> {
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some(&method.to_ascii_lowercase()));
@@ -249,7 +250,7 @@
);
req.hdrs
- .push(Header::new("content-type", "application/json"));
+ .push(Header::new(b"content-type", b"application/json"));
vec![req]
}
@@ -272,7 +273,7 @@
#[test]
fn get() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let mut url = endpoint(Some("get"));
@@ -300,16 +301,16 @@
#[test]
fn req_no_method() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":scheme", url.scheme()),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -333,17 +334,17 @@
#[test]
fn req_empty_method() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", ""),
- Header::new(":scheme", url.scheme()),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b""),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -367,17 +368,17 @@
#[test]
fn req_invalid_method() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "$GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":path", &path),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"$GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -401,16 +402,16 @@
#[test]
fn req_no_scheme() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -434,17 +435,17 @@
#[test]
fn req_empty_scheme() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", ""),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b""),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -468,17 +469,17 @@
#[test]
fn req_invalid_scheme() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", "$fail"),
- Header::new(":path", &path),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", b"$fail"),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -502,16 +503,16 @@
#[test]
fn req_no_authority() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -535,17 +536,17 @@
#[test]
fn req_empty_authority() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":authority", ""),
- Header::new(":path", &path),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":authority", b""),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -569,15 +570,15 @@
#[test]
fn req_no_path() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -601,16 +602,16 @@
#[test]
fn req_empty_path() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":path", ""),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":path", b""),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -634,17 +635,17 @@
#[test]
fn req_invalid_pseudoheader_name() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":$method", "GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":path", &path),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new("user-agent", USER_AGENT),
+ Header::new(b":$method", b"GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
];
let req = Http3Req {
@@ -668,18 +669,18 @@
#[test]
fn req_duplicate_pseudoheader_bad_order() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "400")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"400")]);
let url = endpoint(Some("get"));
let path = String::from(url.path());
let hdrs = vec![
- Header::new(":method", "GET"),
- Header::new(":scheme", url.scheme()),
- Header::new(":path", &path),
- Header::new(":authority", url.host_str().unwrap()),
- Header::new("user-agent", USER_AGENT),
- Header::new(":method", "GET"),
+ Header::new(b":method", b"GET"),
+ Header::new(b":scheme", url.scheme().as_bytes()),
+ Header::new(b":path", path.as_bytes()),
+ Header::new(b":authority", url.host_str().unwrap().as_bytes()),
+ Header::new(b"user-agent", USER_AGENT),
+ Header::new(b":method", b"GET"),
];
let req = Http3Req {
@@ -703,7 +704,7 @@
#[test]
fn req_too_large_headers() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -714,7 +715,10 @@
if let Some(headers) = &extra_headers() {
for (name, val) in headers {
println!("{}: {}", name, val);
- reqs[0].hdrs.push(Header::new(&name, val.as_str().unwrap()));
+ reqs[0].hdrs.push(Header::new(
+ name.as_bytes(),
+ val.as_str().unwrap().as_bytes(),
+ ));
}
};
@@ -728,7 +732,7 @@
#[test]
fn frames_duplicate_settings() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -761,7 +765,7 @@
#[test]
fn frames_max_push_on_request() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -791,7 +795,7 @@
#[test]
fn frames_data_on_control() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -821,7 +825,7 @@
#[test]
fn frames_data_before_headers() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -851,7 +855,7 @@
#[test]
fn frames_too_small_headers() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -881,7 +885,7 @@
#[test]
fn stream_close_control() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -904,7 +908,7 @@
#[test]
fn stream_close_qpack_enc() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -927,7 +931,7 @@
#[test]
fn stream_close_qpack_dec() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("get"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs.clone()));
@@ -969,7 +973,10 @@
assert_headers!(reqs[0]);
let json = jsonify(&reqs[0].resp_body);
- assert_eq!(json.user_agent, Some(USER_AGENT.to_string()));
+ assert_eq!(
+ json.user_agent,
+ String::from_utf8(USER_AGENT.to_vec()).ok()
+ );
};
assert_eq!(Ok(()), do_test(reqs, assert, true));
@@ -978,7 +985,7 @@
#[test]
fn headers() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let mut url = endpoint(Some("headers"));
url.set_query(Some("show_env=1")); // reveal X-Forwarded-* headers
@@ -986,7 +993,10 @@
if let Some(headers) = &extra_headers() {
for (name, val) in headers {
- reqs[0].hdrs.push(Header::new(&name, val.as_str().unwrap()));
+ reqs[0].hdrs.push(Header::new(
+ name.as_bytes(),
+ val.as_str().unwrap().as_bytes(),
+ ));
}
};
@@ -1050,8 +1060,8 @@
let mut reqs = Vec::new();
let expect_hdrs = Some(vec![
- Header::new(":status", "200"),
- Header::new("content-type", "text/html; charset=utf-8"),
+ Header::new(b":status", b"200"),
+ Header::new(b"content-type", b"text/html; charset=utf-8"),
]);
let url = endpoint(Some("encoding/utf8"));
@@ -1066,14 +1076,14 @@
let mut reqs = Vec::new();
let expect_hdrs = Some(vec![
- Header::new(":status", "200"),
- Header::new("content-encoding", "gzip"),
+ Header::new(b":status", b"200"),
+ Header::new(b"content-encoding", b"gzip"),
]);
let url = endpoint(Some("gzip"));
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("accept-encoding", "gzip"));
+ req.hdrs.push(Header::new(b"accept-encoding", b"gzip"));
reqs.push(req);
@@ -1086,12 +1096,12 @@
// Not all servers actually take up the deflate option,
// so don't check content-type response header.
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("deflate"));
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("accept-encoding", "deflate"));
+ req.hdrs.push(Header::new(b"accept-encoding", b"deflate"));
reqs.push(req);
assert_eq!(Ok(()), do_test(reqs, assert_headers_only, true));
@@ -1103,8 +1113,10 @@
for i in (200..600).step_by(100) {
for j in 0..5 {
- let expect_hdrs =
- Some(vec![Header::new(":status", &(i + j).to_string())]);
+ let expect_hdrs = Some(vec![Header::new(
+ b":status",
+ (i + j).to_string().as_bytes(),
+ )]);
let testpoint = format!("{}/{}", "status", i + j);
let url = endpoint(Some(&testpoint));
@@ -1119,7 +1131,7 @@
#[test]
fn response_headers() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let mut url = endpoint(Some("response-headers"));
url.set_query(Some(
@@ -1149,8 +1161,8 @@
// Request 1
let expect_hdrs = Some(vec![
- Header::new(":status", "302"),
- Header::new("location", "https://example.com"),
+ Header::new(b":status", b"302"),
+ Header::new(b"location", b"https://example.com"),
]);
url.set_query(Some("url=https://example.com"));
@@ -1159,15 +1171,15 @@
// Request 2
let expect_hdrs = Some(vec![
- Header::new(":status", "307"),
- Header::new("location", "https://example.com"),
+ Header::new(b":status", b"307"),
+ Header::new(b"location", b"https://example.com"),
]);
url.set_query(Some("url=https://example.com&status_code=307"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
// Request 3
- let expect_hdrs = Some(vec![Header::new(":status", "302")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"302")]);
let url = endpoint(Some("relative-redirect/3"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
@@ -1180,14 +1192,14 @@
let mut reqs = Vec::new();
// Request 1
- let expect_hdrs = Some(vec![Header::new(":status", "302")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"302")]);
let mut url = endpoint(Some("cookies/set"));
url.set_query(Some("k1=v1"));
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
// Request 2
- let expect_hdrs = Some(vec![Header::new(":status", "302")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"302")]);
let mut url = endpoint(Some("cookies/set"));
url.set_query(Some("k1=v1"));
@@ -1203,8 +1215,8 @@
let url = endpoint(Some("basic-auth/user/passwd"));
let expect_hdrs = Some(vec![
- Header::new(":status", "401"),
- Header::new("www-authenticate", "Basic realm=\"Fake Realm\""),
+ Header::new(b":status", b"401"),
+ Header::new(b"www-authenticate", b"Basic realm=\"Fake Realm\""),
]);
reqs.push(Http3Req::new("GET", &url, None, expect_hdrs));
@@ -1219,7 +1231,7 @@
let sizes = [1, 50, 100];
for size in &sizes {
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let testpoint = format!("{}/{}", "stream", size.to_string());
@@ -1262,7 +1274,7 @@
let delays = [1, 10, 30];
for delay in &delays {
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let testpoint = format!("{}/{}", "delay", delay);
let url = endpoint(Some(&testpoint));
@@ -1280,7 +1292,7 @@
let durations = [1, 10, 30];
for duration in &durations {
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let mut url = endpoint(Some("drip"));
url.set_query(Some(&format!(
@@ -1299,7 +1311,7 @@
let mut reqs = Vec::new();
// Request 1
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("range/102400"));
@@ -1308,21 +1320,21 @@
// Request 2
let expect_hdrs = Some(vec![
- Header::new(":status", "206"),
- Header::new("content-range", "bytes 0-49/102400"),
+ Header::new(b":status", b"206"),
+ Header::new(b"content-range", b"bytes 0-49/102400"),
]);
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("range", "bytes=0-49"));
+ req.hdrs.push(Header::new(b"range", b"bytes=0-49"));
reqs.push(req);
// Request 3
let expect_hdrs = Some(vec![
- Header::new(":status", "206"),
- Header::new("content-range", "bytes 100-10000/102400"),
+ Header::new(b":status", b"206"),
+ Header::new(b"content-range", b"bytes 100-10000/102400"),
]);
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("range", "bytes=100-10000"));
+ req.hdrs.push(Header::new(b"range", b"bytes=100-10000"));
reqs.push(req);
assert_eq!(Ok(()), do_test(reqs, assert_headers_only, true));
@@ -1333,7 +1345,7 @@
let mut reqs = Vec::new();
// Request 1
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("cache"));
@@ -1341,19 +1353,19 @@
reqs.push(req);
// Request 2
- let expect_hdrs = Some(vec![Header::new(":status", "304")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"304")]);
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
req.hdrs.push(Header::new(
- "if-modified-since",
- "Wed, 21 Oct 2015 07:28:00 GMT",
+ b"if-modified-since",
+ b"Wed, 21 Oct 2015 07:28:00 GMT",
));
reqs.push(req);
// Request 3
- let expect_hdrs = Some(vec![Header::new(":status", "304")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"304")]);
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("if-none-match", "*"));
+ req.hdrs.push(Header::new(b"if-none-match", b"*"));
reqs.push(req);
assert_eq!(Ok(()), do_test(reqs, assert_headers_only, true));
@@ -1367,8 +1379,8 @@
for size in &sizes {
let expect_hdrs = Some(vec![
- Header::new(":status", "200"),
- Header::new("content-length", &size.to_string()),
+ Header::new(b":status", b"200"),
+ Header::new(b"content-length", size.to_string().as_bytes()),
]);
let testpoint = format!("{}/{}", "bytes", size.to_string());
@@ -1387,7 +1399,7 @@
let sizes = [10, 100, 1000, 10000, 100_000];
for size in &sizes {
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let testpoint = format!("{}/{}", "stream-bytes", size.to_string());
let url = endpoint(Some(&testpoint));
@@ -1403,41 +1415,41 @@
let mut reqs = Vec::new();
// Request 1
- let expect_hdrs = Some(vec![Header::new(":status", "406")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"406")]);
let url = endpoint(Some("image"));
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("accept", "*/*"));
+ req.hdrs.push(Header::new(b"accept", b"*/*"));
reqs.push(req);
// Request 2
let expect_hdrs = Some(vec![
- Header::new(":status", "200"),
- Header::new("content-type", "image/png"),
+ Header::new(b":status", b"200"),
+ Header::new(b"content-type", b"image/png"),
]);
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("accept", "image/*"));
+ req.hdrs.push(Header::new(b"accept", b"image/*"));
reqs.push(req);
// Multiple requests based on accept
let formats = ["image/webp", "image/svg+xml", "image/jpeg", "image/png"];
for format in &formats {
let expect_hdrs = Some(vec![
- Header::new(":status", "200"),
- Header::new("content-type", &format),
+ Header::new(b":status", b"200"),
+ Header::new(b"content-type", format.as_bytes()),
]);
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("accept", &format));
+ req.hdrs.push(Header::new(b"accept", format.as_bytes()));
reqs.push(req);
}
// Multiple requests based on path
for format in &formats {
let expect_hdrs = Some(vec![
- Header::new(":status", "200"),
- Header::new("content-type", &format),
+ Header::new(b":status", b"200"),
+ Header::new(b"content-type", format.as_bytes()),
]);
let testpoint = if format == &"image/svg+xml" {
@@ -1448,7 +1460,7 @@
let url = endpoint(Some(&testpoint));
let mut req = Http3Req::new("GET", &url, None, expect_hdrs);
- req.hdrs.push(Header::new("accept", &format));
+ req.hdrs.push(Header::new(b"accept", format.as_bytes()));
reqs.push(req);
}
@@ -1458,7 +1470,7 @@
#[test]
fn form() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("post"));
@@ -1472,8 +1484,8 @@
);
req.hdrs.push(Header::new(
- "content-type",
- "application/x-www-form-urlencoded",
+ b"content-type",
+ b"application/x-www-form-urlencoded",
));
reqs.push(req);
@@ -1523,7 +1535,7 @@
fn zero_length_body() {
let mut reqs = Vec::new();
- let expect_hdrs = Some(vec![Header::new(":status", "200")]);
+ let expect_hdrs = Some(vec![Header::new(b":status", b"200")]);
let url = endpoint(Some("stream/0"));