// Copyright (C) 2019, Cloudflare, Inc. // All rights reserved. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are // met: // // * Redistributions of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. use super::Error; use super::Result; use crate::h3::Header; use super::INDEXED; use super::INDEXED_WITH_POST_BASE; use super::LITERAL; use super::LITERAL_WITH_NAME_REF; #[derive(Clone, Copy, Debug, PartialEq)] enum Representation { Indexed, IndexedWithPostBase, Literal, LiteralWithNameRef, LiteralWithPostBase, } impl Representation { pub fn from_byte(b: u8) -> Representation { if b & INDEXED == INDEXED { return Representation::Indexed; } if b & LITERAL_WITH_NAME_REF == LITERAL_WITH_NAME_REF { return Representation::LiteralWithNameRef; } if b & LITERAL == LITERAL { return Representation::Literal; } if b & INDEXED_WITH_POST_BASE == INDEXED_WITH_POST_BASE { return Representation::IndexedWithPostBase; } Representation::LiteralWithPostBase } } /// A QPACK decoder. #[derive(Default)] pub struct Decoder {} impl Decoder { /// Creates a new QPACK decoder. pub fn new() -> Decoder { Decoder::default() } /// Processes control instructions from the encoder. pub fn control(&mut self, _buf: &mut [u8]) -> Result<()> { // TODO: process control instructions Ok(()) } /// Decodes a QPACK header block into a list of headers. pub fn decode(&mut self, buf: &[u8], max_size: u64) -> Result> { let mut b = octets::Octets::with_slice(buf); let mut out = Vec::new(); let mut left = max_size; let req_insert_count = decode_int(&mut b, 8)?; let base = decode_int(&mut b, 7)?; trace!("Header count={} base={}", req_insert_count, base); while b.cap() > 0 { let first = b.peek_u8()?; match Representation::from_byte(first) { Representation::Indexed => { const STATIC: u8 = 0x40; let s = first & STATIC == STATIC; let index = decode_int(&mut b, 6)?; trace!("Indexed index={} static={}", index, s); if !s { // TODO: implement dynamic table return Err(Error::InvalidHeaderValue); } let (name, value) = lookup_static(index)?; left = left .checked_sub((name.len() + value.len()) as u64) .ok_or(Error::HeaderListTooLarge)?; let hdr = Header::new(name, value); out.push(hdr); }, Representation::IndexedWithPostBase => { let index = decode_int(&mut b, 4)?; trace!("Indexed With Post Base index={}", index); // TODO: implement dynamic table return Err(Error::InvalidHeaderValue); }, Representation::Literal => { let name_huff = b.as_ref()[0] & 0x08 == 0x08; let name_len = decode_int(&mut b, 3)? as usize; let mut name = b.get_bytes(name_len)?; let name = if name_huff { super::huffman::decode(&mut name)? } else { name.to_vec() }; let name = name.to_vec(); let value = decode_str(&mut b)?; trace!( "Literal Without Name Reference name={:?} value={:?}", name, value, ); left = left .checked_sub((name.len() + value.len()) as u64) .ok_or(Error::HeaderListTooLarge)?; // Instead of calling Header::new(), create Header directly // from `name` and `value`, which are already String. let hdr = Header(name, value); out.push(hdr); }, Representation::LiteralWithNameRef => { const STATIC: u8 = 0x10; let s = first & STATIC == STATIC; let name_idx = decode_int(&mut b, 4)?; let value = decode_str(&mut b)?; trace!( "Literal name_idx={} static={} value={:?}", name_idx, s, value ); if !s { // TODO: implement dynamic table return Err(Error::InvalidHeaderValue); } let (name, _) = lookup_static(name_idx)?; left = left .checked_sub((name.len() + value.len()) as u64) .ok_or(Error::HeaderListTooLarge)?; // 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_vec(), value); out.push(hdr); }, Representation::LiteralWithPostBase => { trace!("Literal With Post Base"); // TODO: implement dynamic table return Err(Error::InvalidHeaderValue); }, } } Ok(out) } } fn lookup_static(idx: u64) -> Result<(&'static [u8], &'static [u8])> { if idx >= super::static_table::STATIC_TABLE.len() as u64 { return Err(Error::InvalidStaticTableIndex); } Ok(super::static_table::STATIC_TABLE[idx as usize]) } fn decode_int(b: &mut octets::Octets, prefix: usize) -> Result { let mask = 2u64.pow(prefix as u32) - 1; let mut val = u64::from(b.get_u8()?); val &= mask; if val < mask { return Ok(val); } let mut shift = 0; while b.cap() > 0 { let byte = b.get_u8()?; let inc = u64::from(byte & 0x7f) .checked_shl(shift) .ok_or(Error::BufferTooShort)?; val = val.checked_add(inc).ok_or(Error::BufferTooShort)?; shift += 7; if byte & 0x80 == 0 { return Ok(val); } } Err(Error::BufferTooShort) } fn decode_str(b: &mut octets::Octets) -> Result> { let first = b.peek_u8()?; let huff = first & 0x80 == 0x80; let len = decode_int(b, 7)? as usize; let mut val = b.get_bytes(len)?; let val = if huff { super::huffman::decode(&mut val)? } else { val.to_vec() }; Ok(val) } #[cfg(test)] mod tests { use super::*; #[test] fn decode_int1() { let mut encoded = [0b01010, 0x02]; let mut b = octets::Octets::with_slice(&mut encoded); assert_eq!(decode_int(&mut b, 5), Ok(10)); } #[test] fn decode_int2() { let mut encoded = [0b11111, 0b10011010, 0b00001010]; let mut b = octets::Octets::with_slice(&mut encoded); assert_eq!(decode_int(&mut b, 5), Ok(1337)); } #[test] fn decode_int3() { let mut encoded = [0b101010]; let mut b = octets::Octets::with_slice(&mut encoded); assert_eq!(decode_int(&mut b, 8), Ok(42)); } }