135 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
			
		
		
	
	
			135 lines
		
	
	
		
			3.9 KiB
		
	
	
	
		
			Rust
		
	
	
	
	
	
| use super::DecoderError;
 | |
| use util::byte_str::{ByteStr, FromUtf8Error};
 | |
| 
 | |
| use http::{Method, StatusCode};
 | |
| use http::header::{HeaderName, HeaderValue};
 | |
| use bytes::Bytes;
 | |
| 
 | |
| /// HPack table entry
 | |
| #[derive(Debug, Clone)]
 | |
| pub enum Entry {
 | |
|     Header {
 | |
|         name: HeaderName,
 | |
|         value: HeaderValue,
 | |
|     },
 | |
|     Authority(ByteStr),
 | |
|     Method(Method),
 | |
|     Scheme(ByteStr),
 | |
|     Path(ByteStr),
 | |
|     Status(StatusCode),
 | |
| }
 | |
| 
 | |
| /// The name component of an Entry
 | |
| pub enum Key<'a> {
 | |
|     Header(&'a HeaderName),
 | |
|     Authority,
 | |
|     Method,
 | |
|     Scheme,
 | |
|     Path,
 | |
|     Status,
 | |
| }
 | |
| 
 | |
| impl Entry {
 | |
|     pub fn new(name: Bytes, value: Bytes) -> Result<Entry, DecoderError> {
 | |
|         if name[0] == b':' {
 | |
|             match &name[1..] {
 | |
|                 b"authority" => {
 | |
|                     let value = try!(ByteStr::from_utf8(value));
 | |
|                     Ok(Entry::Authority(value))
 | |
|                 }
 | |
|                 b"method" => {
 | |
|                     let method = try!(Method::from_bytes(&value));
 | |
|                     Ok(Entry::Method(method))
 | |
|                 }
 | |
|                 b"scheme" => {
 | |
|                     let value = try!(ByteStr::from_utf8(value));
 | |
|                     Ok(Entry::Scheme(value))
 | |
|                 }
 | |
|                 b"path" => {
 | |
|                     let value = try!(ByteStr::from_utf8(value));
 | |
|                     Ok(Entry::Path(value))
 | |
|                 }
 | |
|                 b"status" => {
 | |
|                     let status = try!(StatusCode::from_slice(&value));
 | |
|                     Ok(Entry::Status(status))
 | |
|                 }
 | |
|                 _ => {
 | |
|                     Err(DecoderError::InvalidPseudoheader)
 | |
|                 }
 | |
|             }
 | |
|         } else {
 | |
|             let name = try!(HeaderName::from_bytes(&name));
 | |
|             let value = try!(HeaderValue::try_from_slice(&value));
 | |
| 
 | |
|             Ok(Entry::Header { name: name, value: value })
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn len(&self) -> usize {
 | |
|         match *self {
 | |
|             Entry::Header { ref name, ref value } => {
 | |
|                 let n: &str = name.as_ref();
 | |
|                 32 + n.len() + value.len()
 | |
|             }
 | |
|             Entry::Authority(ref v) => {
 | |
|                 32 + 10 + v.len()
 | |
|             }
 | |
|             Entry::Method(ref v) => {
 | |
|                 32 + 7 + v.as_ref().len()
 | |
|             }
 | |
|             Entry::Scheme(ref v) => {
 | |
|                 32 + 7 + v.len()
 | |
|             }
 | |
|             Entry::Path(ref v) => {
 | |
|                 32 + 5 + v.len()
 | |
|             }
 | |
|             Entry::Status(ref v) => {
 | |
|                 32 + 7 + 3
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| 
 | |
|     pub fn key(&self) -> Key {
 | |
|         match *self {
 | |
|             Entry::Header { ref name, .. } => Key::Header(name),
 | |
|             Entry::Authority(..) => Key::Authority,
 | |
|             Entry::Method(..) => Key::Method,
 | |
|             Entry::Scheme(..) => Key::Scheme,
 | |
|             Entry::Path(..) => Key::Path,
 | |
|             Entry::Status(..) => Key::Status,
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 | |
| impl<'a> Key<'a> {
 | |
|     pub fn into_entry(self, value: Bytes) -> Result<Entry, DecoderError> {
 | |
|         match self {
 | |
|             Key::Header(name) => {
 | |
|                 Ok(Entry::Header {
 | |
|                     name: name.clone(),
 | |
|                     value: try!(HeaderValue::try_from_slice(&*value)),
 | |
|                 })
 | |
|             }
 | |
|             Key::Authority => {
 | |
|                 Ok(Entry::Authority(try!(ByteStr::from_utf8(value))))
 | |
|             }
 | |
|             Key::Method => {
 | |
|                 Ok(Entry::Scheme(try!(ByteStr::from_utf8(value))))
 | |
|             }
 | |
|             Key::Scheme => {
 | |
|                 Ok(Entry::Scheme(try!(ByteStr::from_utf8(value))))
 | |
|             }
 | |
|             Key::Path => {
 | |
|                 Ok(Entry::Path(try!(ByteStr::from_utf8(value))))
 | |
|             }
 | |
|             Key::Status => {
 | |
|                 match StatusCode::from_slice(&value) {
 | |
|                     Ok(status) => Ok(Entry::Status(status)),
 | |
|                     // TODO: better error handling
 | |
|                     Err(_) => Err(DecoderError::InvalidStatusCode),
 | |
|                 }
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 |