Work on huffman decoding
This commit is contained in:
		| @@ -1,6 +1,6 @@ | ||||
| use super::Entry; | ||||
|  | ||||
| use tower::http::{HeaderName, Str}; | ||||
| use tower::http::{HeaderName, StatusCode, Method, Str}; | ||||
| use bytes::{Buf, Bytes}; | ||||
|  | ||||
| use std::io::Cursor; | ||||
| @@ -19,6 +19,7 @@ pub struct Decoder { | ||||
| pub enum DecoderError { | ||||
|     InvalidRepresentation, | ||||
|     InvalidIntegerPrefix, | ||||
|     InvalidTableIndex, | ||||
|     IntegerUnderflow, | ||||
|     IntegerOverflow, | ||||
| } | ||||
| @@ -133,7 +134,7 @@ impl Decoder { | ||||
|  | ||||
|     /// Decodes the headers found in the given buffer. | ||||
|     pub fn decode<F>(&mut self, src: &Bytes, mut f: F) -> Result<(), DecoderError> | ||||
|         where F: FnMut(HeaderName, Str) | ||||
|         where F: FnMut(Entry) | ||||
|     { | ||||
|         use self::Representation::*; | ||||
|  | ||||
| @@ -145,7 +146,7 @@ impl Decoder { | ||||
|             // determined from the first byte. | ||||
|             match try!(Representation::load(peek_u8(&mut buf))) { | ||||
|                 Indexed => { | ||||
|                     unimplemented!(); | ||||
|                     f(try!(self.decode_indexed(&mut buf))); | ||||
|                 } | ||||
|                 LiteralWithIndexing => { | ||||
|                     unimplemented!(); | ||||
| @@ -167,12 +168,20 @@ impl Decoder { | ||||
|  | ||||
|     fn decode_indexed(&self, buf: &mut Cursor<&Bytes>) -> Result<Entry, DecoderError> { | ||||
|         let index = try!(decode_int(buf, 7)); | ||||
|         self.get_from_table(index) | ||||
|         self.table.get(index) | ||||
|     } | ||||
|  | ||||
|     fn get_from_table(&self, index: usize) -> Result<Entry, DecoderError> { | ||||
|     fn decode_literal(&self, buf: &mut Cursor<&Bytes>, index: bool) -> Result<Entry, DecoderError> { | ||||
|         let prefix = if index { | ||||
|             6 | ||||
|         } else { | ||||
|             4 | ||||
|         }; | ||||
|  | ||||
|         // Extract the table index for the name, or 0 if not indexed | ||||
|         let table_idx = try!(decode_int(buf, prefix)); | ||||
|  | ||||
|         unimplemented!(); | ||||
|         // self.header_table.get(index).o | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -280,21 +289,261 @@ impl Table { | ||||
|         self.max_size | ||||
|     } | ||||
|  | ||||
|  | ||||
|     /// Returns the entry located at the given index. | ||||
|     /// | ||||
|     /// The table is 1-indexed and constructed in such a way that the first | ||||
|     /// entries belong to the static table, followed by entries in the dynamic | ||||
|     /// table. They are merged into a single index address space, though. | ||||
|     /// | ||||
|     /// This is according to the [HPACK spec, section 2.3.3.] | ||||
|     /// (http://http2.github.io/http2-spec/compression.html#index.address.space) | ||||
|     pub fn get(&self, index: usize) -> Result<Entry, DecoderError> { | ||||
|         if index == 0 { | ||||
|             return Err(DecoderError::InvalidTableIndex); | ||||
|         } | ||||
|  | ||||
|         if index <= 61 { | ||||
|             return Ok(get_static(index)); | ||||
|         } | ||||
|  | ||||
|         // Convert the index for lookup in the entries structure. | ||||
|         match self.entries.get(index - 62) { | ||||
|             Some(e) => Ok(e.clone()), | ||||
|             None => Err(DecoderError::InvalidTableIndex), | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     fn insert(&mut self, entry: Entry) { | ||||
|         let len = entry.len(); | ||||
|  | ||||
|         debug_assert!(len <= self.max_size); | ||||
|  | ||||
|         while self.size + len > self.max_size { | ||||
|             let last = self.entries.pop_back() | ||||
|                 .expect("size of table != 0, but no headers left!"); | ||||
|  | ||||
|             self.size -= last.len(); | ||||
|         } | ||||
|         self.reserve(len); | ||||
|  | ||||
|         self.size += len; | ||||
|  | ||||
|         // Track the entry | ||||
|         self.entries.push_front(entry); | ||||
|     } | ||||
|  | ||||
|     fn reserve(&mut self, size: usize) { | ||||
|         debug_assert!(size <= self.max_size); | ||||
|  | ||||
|         while self.size + size > self.max_size { | ||||
|             let last = self.entries.pop_back() | ||||
|                 .expect("size of table != 0, but no headers left!"); | ||||
|  | ||||
|             self.size -= last.len(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| /// Get an entry from the static table | ||||
| pub fn get_static(idx: usize) -> Entry { | ||||
|     use tower::http::StandardHeader::*; | ||||
|  | ||||
|     match idx { | ||||
|         1 => Entry::Authority(Str::new()), | ||||
|         2 => Entry::Method(Method::Get), | ||||
|         3 => Entry::Method(Method::Post), | ||||
|         4 => Entry::Path(Str::from_static("/")), | ||||
|         5 => Entry::Path(Str::from_static("/index.html")), | ||||
|         6 => Entry::Scheme(Str::from_static("http")), | ||||
|         7 => Entry::Scheme(Str::from_static("https")), | ||||
|         8 => Entry::Status(StatusCode::Ok), | ||||
|         9 => Entry::Status(StatusCode::NoContent), | ||||
|         10 => Entry::Status(StatusCode::PartialContent), | ||||
|         11 => Entry::Status(StatusCode::NotModified), | ||||
|         12 => Entry::Status(StatusCode::BadRequest), | ||||
|         13 => Entry::Status(StatusCode::NotFound), | ||||
|         14 => Entry::Status(StatusCode::InternalServerError), | ||||
|         15 => Entry::Header { | ||||
|             name: AcceptCharset.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         16 => Entry::Header { | ||||
|             name: AcceptEncoding.into(), | ||||
|             value: Str::from_static("gzip, deflate"), | ||||
|         }, | ||||
|         17 => Entry::Header { | ||||
|             name: AcceptLanguage.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         18 => Entry::Header { | ||||
|             name: AcceptRanges.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         19 => Entry::Header { | ||||
|             name: Accept.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         20 => Entry::Header { | ||||
|             name: AccessControlAllowOrigin.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         21 => Entry::Header { | ||||
|             name: Age.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         22 => Entry::Header { | ||||
|             name: Allow.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         23 => Entry::Header { | ||||
|             name: Authorization.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         24 => Entry::Header { | ||||
|             name: CacheControl.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         25 => Entry::Header { | ||||
|             name: ContentDisposition.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         26 => Entry::Header { | ||||
|             name: ContentEncoding.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         27 => Entry::Header { | ||||
|             name: ContentLanguage.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         28 => Entry::Header { | ||||
|             name: ContentLength.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         29 => Entry::Header { | ||||
|             name: ContentLocation.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         30 => Entry::Header { | ||||
|             name: ContentRange.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         31 => Entry::Header { | ||||
|             name: ContentType.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         32 => Entry::Header { | ||||
|             name: Cookie.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         33 => Entry::Header { | ||||
|             name: Date.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         34 => Entry::Header { | ||||
|             name: Etag.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         35 => Entry::Header { | ||||
|             name: Expect.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         36 => Entry::Header { | ||||
|             name: Expires.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         37 => Entry::Header { | ||||
|             name: From.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         38 => Entry::Header { | ||||
|             name: Host.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         39 => Entry::Header { | ||||
|             name: IfMatch.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         40 => Entry::Header { | ||||
|             name: IfModifiedSince.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         41 => Entry::Header { | ||||
|             name: IfNoneMatch.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         42 => Entry::Header { | ||||
|             name: IfRange.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         43 => Entry::Header { | ||||
|             name: IfUnmodifiedSince.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         44 => Entry::Header { | ||||
|             name: LastModified.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         45 => Entry::Header { | ||||
|             name: Link.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         46 => Entry::Header { | ||||
|             name: Location.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         47 => Entry::Header { | ||||
|             name: MaxForwards.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         48 => Entry::Header { | ||||
|             name: ProxyAuthenticate.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         49 => Entry::Header { | ||||
|             name: ProxyAuthorization.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         50 => Entry::Header { | ||||
|             name: Range.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         51 => Entry::Header { | ||||
|             name: Referer.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         52 => Entry::Header { | ||||
|             name: Refresh.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         53 => Entry::Header { | ||||
|             name: RetryAfter.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         54 => Entry::Header { | ||||
|             name: Server.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         55 => Entry::Header { | ||||
|             name: SetCookie.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         56 => Entry::Header { | ||||
|             name: StrictTransportSecurity.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         57 => Entry::Header { | ||||
|             name: TransferEncoding.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         58 => Entry::Header { | ||||
|             name: UserAgent.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         59 => Entry::Header { | ||||
|             name: Vary.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         60 => Entry::Header { | ||||
|             name: Via.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         61 => Entry::Header { | ||||
|             name: WwwAuthenticate.into(), | ||||
|             value: Str::new(), | ||||
|         }, | ||||
|         _ => unreachable!(), | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user