1 //! HTTP Request and response header handling. 2 3 use http::header::{HeaderMap, HeaderName, HeaderValue}; 4 use httparse::Status; 5 6 use super::machine::TryParse; 7 use crate::error::Result; 8 9 /// Limit for the number of header lines. 10 pub const MAX_HEADERS: usize = 124; 11 12 /// Trait to convert raw objects into HTTP parseables. 13 pub(crate) trait FromHttparse<T>: Sized { 14 /// Convert raw object into parsed HTTP headers. from_httparse(raw: T) -> Result<Self>15 fn from_httparse(raw: T) -> Result<Self>; 16 } 17 18 impl<'b: 'h, 'h> FromHttparse<&'b [httparse::Header<'h>]> for HeaderMap { from_httparse(raw: &'b [httparse::Header<'h>]) -> Result<Self>19 fn from_httparse(raw: &'b [httparse::Header<'h>]) -> Result<Self> { 20 let mut headers = HeaderMap::new(); 21 for h in raw { 22 headers.append( 23 HeaderName::from_bytes(h.name.as_bytes())?, 24 HeaderValue::from_bytes(h.value)?, 25 ); 26 } 27 28 Ok(headers) 29 } 30 } 31 impl TryParse for HeaderMap { try_parse(buf: &[u8]) -> Result<Option<(usize, Self)>>32 fn try_parse(buf: &[u8]) -> Result<Option<(usize, Self)>> { 33 let mut hbuffer = [httparse::EMPTY_HEADER; MAX_HEADERS]; 34 Ok(match httparse::parse_headers(buf, &mut hbuffer)? { 35 Status::Partial => None, 36 Status::Complete((size, hdr)) => Some((size, HeaderMap::from_httparse(hdr)?)), 37 }) 38 } 39 } 40 41 #[cfg(test)] 42 mod tests { 43 44 use super::{super::machine::TryParse, HeaderMap}; 45 46 #[test] headers()47 fn headers() { 48 const DATA: &[u8] = b"Host: foo.com\r\n\ 49 Connection: Upgrade\r\n\ 50 Upgrade: websocket\r\n\ 51 \r\n"; 52 let (_, hdr) = HeaderMap::try_parse(DATA).unwrap().unwrap(); 53 assert_eq!(hdr.get("Host").unwrap(), &b"foo.com"[..]); 54 assert_eq!(hdr.get("Upgrade").unwrap(), &b"websocket"[..]); 55 assert_eq!(hdr.get("Connection").unwrap(), &b"Upgrade"[..]); 56 } 57 58 #[test] headers_iter()59 fn headers_iter() { 60 const DATA: &[u8] = b"Host: foo.com\r\n\ 61 Sec-WebSocket-Extensions: permessage-deflate\r\n\ 62 Connection: Upgrade\r\n\ 63 Sec-WebSocket-ExtenSIONS: permessage-unknown\r\n\ 64 Upgrade: websocket\r\n\ 65 \r\n"; 66 let (_, hdr) = HeaderMap::try_parse(DATA).unwrap().unwrap(); 67 let mut iter = hdr.get_all("Sec-WebSocket-Extensions").iter(); 68 assert_eq!(iter.next().unwrap(), &b"permessage-deflate"[..]); 69 assert_eq!(iter.next().unwrap(), &b"permessage-unknown"[..]); 70 assert_eq!(iter.next(), None); 71 } 72 73 #[test] headers_incomplete()74 fn headers_incomplete() { 75 const DATA: &[u8] = b"Host: foo.com\r\n\ 76 Connection: Upgrade\r\n\ 77 Upgrade: websocket\r\n"; 78 let hdr = HeaderMap::try_parse(DATA).unwrap(); 79 assert!(hdr.is_none()); 80 } 81 } 82