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"));