Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  header_block.rs   Sprache: unbekannt

 
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{
    mem,
    ops::{Deref, Div},
};

use neqo_common::{qtrace, Header};

use crate::{
    prefix::{
        BASE_PREFIX_NEGATIVE, BASE_PREFIX_POSITIVE, HEADER_FIELD_INDEX_DYNAMIC,
        HEADER_FIELD_INDEX_DYNAMIC_POST, HEADER_FIELD_INDEX_STATIC,
        HEADER_FIELD_LITERAL_NAME_LITERAL, HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC,
        HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST, HEADER_FIELD_LITERAL_NAME_REF_STATIC,
        NO_PREFIX,
    },
    qpack_send_buf::QpackData,
    reader::{parse_utf8, ReceiverBufferWrapper},
    table::HeaderTable,
    Error, Res,
};

#[derive(Default, Debug, PartialEq, Eq)]
pub struct HeaderEncoder {
    buf: QpackData,
    base: u64,
    use_huffman: bool,
    max_entries: u64,
    max_dynamic_index_ref: Option<u64>,
}

impl ::std::fmt::Display for HeaderEncoder {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "HeaderEncoder")
    }
}

impl HeaderEncoder {
    pub fn new(base: u64, use_huffman: bool, max_entries: u64) -> Self {
        Self {
            buf: QpackData::default(),
            base,
            use_huffman,
            max_entries,
            max_dynamic_index_ref: None,
        }
    }

    pub fn len(&self) -> usize {
        self.buf.len()
    }

    pub fn read(&mut self, r: usize) {
        self.buf.read(r);
    }

    pub fn encode_indexed_static(&mut self, index: u64) {
        qtrace!([self], "encode static index {}.", index);
        self.buf
            .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_STATIC, index);
    }

    fn new_ref(&mut self, index: u64) {
        if let Some(r) = self.max_dynamic_index_ref {
            if r < index {
                self.max_dynamic_index_ref = Some(index);
            }
        } else {
            self.max_dynamic_index_ref = Some(index);
        }
    }

    pub fn encode_indexed_dynamic(&mut self, index: u64) {
        qtrace!([self], "encode dynamic index {}.", index);
        if index < self.base {
            self.buf
                .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_DYNAMIC, self.base - index - 1);
        } else {
            self.buf
                .encode_prefixed_encoded_int(HEADER_FIELD_INDEX_DYNAMIC_POST, index - self.base);
        }
        self.new_ref(index);
    }

    pub fn encode_literal_with_name_ref(&mut self, is_static: bool, index: u64, value: &[u8]) {
        qtrace!(
            [self],
            "encode literal with name ref - index={}, static={}, value={:x?}",
            index,
            is_static,
            value
        );
        if is_static {
            self.buf
                .encode_prefixed_encoded_int(HEADER_FIELD_LITERAL_NAME_REF_STATIC, index);
        } else if index < self.base {
            self.buf.encode_prefixed_encoded_int(
                HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC,
                self.base - index - 1,
            );
            self.new_ref(index);
        } else {
            self.buf.encode_prefixed_encoded_int(
                HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST,
                index - self.base,
            );
            self.new_ref(index);
        }

        self.buf.encode_literal(self.use_huffman, NO_PREFIX, value);
    }

    pub fn encode_literal_with_name_literal(&mut self, name: &[u8], value: &[u8]) {
        qtrace!(
            [self],
            "encode literal with name literal - name={:x?}, value={:x?}.",
            name,
            value
        );
        self.buf
            .encode_literal(self.use_huffman, HEADER_FIELD_LITERAL_NAME_LITERAL, name);
        self.buf.encode_literal(self.use_huffman, NO_PREFIX, value);
    }

    pub fn encode_header_block_prefix(&mut self) {
        let tmp = mem::take(&mut self.buf);
        let (enc_insert_cnt, delta, prefix) =
            self.max_dynamic_index_ref
                .map_or((0, self.base, BASE_PREFIX_POSITIVE), |r| {
                    let req_insert_cnt = r + 1;
                    if req_insert_cnt <= self.base {
                        (
                            req_insert_cnt % (2 * self.max_entries) + 1,
                            self.base - req_insert_cnt,
                            BASE_PREFIX_POSITIVE,
                        )
                    } else {
                        (
                            req_insert_cnt % (2 * self.max_entries) + 1,
                            req_insert_cnt - self.base - 1,
                            BASE_PREFIX_NEGATIVE,
                        )
                    }
                });
        qtrace!(
            [self],
            "encode header block prefix max_dynamic_index_ref={:?}, base={}, enc_insert_cnt={}, delta={}, prefix={:?}.",
            self.max_dynamic_index_ref,
            self.base,
            enc_insert_cnt,
            delta,
            prefix
        );

        self.buf
            .encode_prefixed_encoded_int(NO_PREFIX, enc_insert_cnt);
        self.buf.encode_prefixed_encoded_int(prefix, delta);

        self.buf.write_bytes(&tmp);
    }
}

impl Deref for HeaderEncoder {
    type Target = [u8];
    fn deref(&self) -> &Self::Target {
        &self.buf
    }
}

pub struct HeaderDecoder<'a> {
    buf: ReceiverBufferWrapper<'a>,
    base: u64,
    req_insert_cnt: u64,
}

impl ::std::fmt::Display for HeaderDecoder<'_> {
    fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result {
        write!(f, "HeaderDecoder")
    }
}

#[derive(Debug, PartialEq, Eq)]
pub enum HeaderDecoderResult {
    Blocked(u64),
    Headers(Vec<Header>),
}

impl<'a> HeaderDecoder<'a> {
    pub const fn new(buf: &'a [u8]) -> Self {
        Self {
            buf: ReceiverBufferWrapper::new(buf),
            base: 0,
            req_insert_cnt: 0,
        }
    }

    pub fn refers_dynamic_table(
        &mut self,
        max_entries: u64,
        total_num_of_inserts: u64,
    ) -> Res<bool> {
        Error::map_error(
            self.read_base(max_entries, total_num_of_inserts),
            Error::DecompressionFailed,
        )?;
        Ok(self.req_insert_cnt != 0)
    }

    pub fn decode_header_block(
        &mut self,
        table: &HeaderTable,
        max_entries: u64,
        total_num_of_inserts: u64,
    ) -> Res<HeaderDecoderResult> {
        Error::map_error(
            self.read_base(max_entries, total_num_of_inserts),
            Error::DecompressionFailed,
        )?;

        if table.base() < self.req_insert_cnt {
            qtrace!(
                [self],
                "decoding is blocked, requested inserts count={}",
                self.req_insert_cnt
            );
            return Ok(HeaderDecoderResult::Blocked(self.req_insert_cnt));
        }
        let mut h: Vec<Header> = Vec::new();

        while !self.buf.done() {
            let b = Error::map_error(self.buf.peek(), Error::DecompressionFailed)?;
            if HEADER_FIELD_INDEX_STATIC.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_indexed_static(),
                    Error::DecompressionFailed,
                )?);
            } else if HEADER_FIELD_INDEX_DYNAMIC.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_indexed_dynamic(table),
                    Error::DecompressionFailed,
                )?);
            } else if HEADER_FIELD_INDEX_DYNAMIC_POST.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_indexed_dynamic_post(table),
                    Error::DecompressionFailed,
                )?);
            } else if HEADER_FIELD_LITERAL_NAME_REF_STATIC.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_literal_with_name_ref_static(),
                    Error::DecompressionFailed,
                )?);
            } else if HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_literal_with_name_ref_dynamic(table),
                    Error::DecompressionFailed,
                )?);
            } else if HEADER_FIELD_LITERAL_NAME_LITERAL.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_literal_with_name_literal(),
                    Error::DecompressionFailed,
                )?);
            } else if HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST.cmp_prefix(b) {
                h.push(Error::map_error(
                    self.read_literal_with_name_ref_dynamic_post(table),
                    Error::DecompressionFailed,
                )?);
            } else {
                unreachable!("All prefixes are covered");
            }
        }

        qtrace!([self], "done decoding header block.");
        Ok(HeaderDecoderResult::Headers(h))
    }

    pub const fn get_req_insert_cnt(&self) -> u64 {
        self.req_insert_cnt
    }

    fn read_base(&mut self, max_entries: u64, total_num_of_inserts: u64) -> Res<()> {
        let insert_cnt = self.buf.read_prefixed_int(0)?;
        self.req_insert_cnt =
            HeaderDecoder::calc_req_insert_cnt(insert_cnt, max_entries, total_num_of_inserts)?;

        let s = self.buf.peek()? & 0x80 != 0;
        let base_delta = self.buf.read_prefixed_int(1)?;
        self.base = if s {
            if self.req_insert_cnt <= base_delta {
                return Err(Error::DecompressionFailed);
            }
            self.req_insert_cnt - base_delta - 1
        } else {
            self.req_insert_cnt
                .checked_add(base_delta)
                .ok_or(Error::DecompressionFailed)?
        };
        qtrace!(
            [self],
            "requested inserts count is {} and base is {}",
            self.req_insert_cnt,
            self.base
        );
        Ok(())
    }

    fn calc_req_insert_cnt(encoded: u64, max_entries: u64, total_num_of_inserts: u64) -> Res<u64> {
        if encoded == 0 {
            Ok(0)
        } else if max_entries == 0 {
            Err(Error::DecompressionFailed)
        } else {
            let full_range = 2 * max_entries;
            if encoded > full_range {
                return Err(Error::DecompressionFailed);
            }
            let max_value = total_num_of_inserts + max_entries;
            let max_wrapped = max_value.div(full_range) * full_range;
            let mut req_insert_cnt = max_wrapped + encoded - 1;
            if req_insert_cnt > max_value {
                if req_insert_cnt < full_range {
                    return Err(Error::DecompressionFailed);
                }
                req_insert_cnt -= full_range;
            }
            Ok(req_insert_cnt)
        }
    }

    fn read_indexed_static(&mut self) -> Res<Header> {
        let index = self
            .buf
            .read_prefixed_int(HEADER_FIELD_INDEX_STATIC.len())?;
        qtrace!([self], "decoder static indexed {}.", index);
        let entry = HeaderTable::get_static(index)?;
        Ok(Header::new(
            parse_utf8(entry.name())?,
            parse_utf8(entry.value())?,
        ))
    }

    fn read_indexed_dynamic(&mut self, table: &HeaderTable) -> Res<Header> {
        let index = self
            .buf
            .read_prefixed_int(HEADER_FIELD_INDEX_DYNAMIC.len())?;
        qtrace!([self], "decoder dynamic indexed {}.", index);
        let entry = table.get_dynamic(index, self.base, false)?;
        Ok(Header::new(
            parse_utf8(entry.name())?,
            parse_utf8(entry.value())?,
        ))
    }

    fn read_indexed_dynamic_post(&mut self, table: &HeaderTable) -> Res<Header> {
        let index = self
            .buf
            .read_prefixed_int(HEADER_FIELD_INDEX_DYNAMIC_POST.len())?;
        qtrace!([self], "decode post-based {}.", index);
        let entry = table.get_dynamic(index, self.base, true)?;
        Ok(Header::new(
            parse_utf8(entry.name())?,
            parse_utf8(entry.value())?,
        ))
    }

    fn read_literal_with_name_ref_static(&mut self) -> Res<Header> {
        qtrace!(
            [self],
            "read literal with name reference to the static table."
        );

        let index = self
            .buf
            .read_prefixed_int(HEADER_FIELD_LITERAL_NAME_REF_STATIC.len())?;

        Ok(Header::new(
            parse_utf8(HeaderTable::get_static(index)?.name())?,
            self.buf.read_literal_from_buffer(0)?,
        ))
    }

    fn read_literal_with_name_ref_dynamic(&mut self, table: &HeaderTable) -> Res<Header> {
        qtrace!(
            [self],
            "read literal with name reference ot the dynamic table."
        );

        let index = self
            .buf
            .read_prefixed_int(HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC.len())?;

        Ok(Header::new(
            parse_utf8(table.get_dynamic(index, self.base, false)?.name())?,
            self.buf.read_literal_from_buffer(0)?,
        ))
    }

    fn read_literal_with_name_ref_dynamic_post(&mut self, table: &HeaderTable) -> Res<Header> {
        qtrace!([self], "decoder literal with post-based index.");

        let index = self
            .buf
            .read_prefixed_int(HEADER_FIELD_LITERAL_NAME_REF_DYNAMIC_POST.len())?;

        Ok(Header::new(
            parse_utf8(table.get_dynamic(index, self.base, true)?.name())?,
            self.buf.read_literal_from_buffer(0)?,
        ))
    }

    fn read_literal_with_name_literal(&mut self) -> Res<Header> {
        qtrace!([self], "decode literal with name literal.");

        let name = self
            .buf
            .read_literal_from_buffer(HEADER_FIELD_LITERAL_NAME_LITERAL.len())?;

        Ok(Header::new(name, self.buf.read_literal_from_buffer(0)?))
    }
}

#[cfg(test)]
mod tests {

    use super::{HeaderDecoder, HeaderDecoderResult, HeaderEncoder, HeaderTable};
    use crate::Error;

    const INDEX_STATIC_TEST: &[(u64, &[u8], &str, &str)] = &[
        (0, &[0x0, 0x0, 0xc0], ":authority", ""),
        (10, &[0x0, 0x0, 0xca], "last-modified", ""),
        (15, &[0x0, 0x0, 0xcf], ":method", "CONNECT"),
        (65, &[0x0, 0x0, 0xff, 0x02], ":status", "206"),
    ];

    const INDEX_DYNAMIC_TEST: &[(u64, &[u8], &str, &str)] = &[
        (0, &[0x02, 0x41, 0xbf, 0x2], "header0", "0"),
        (10, &[0x0c, 0x37, 0xb7], "header10", "10"),
        (15, &[0x11, 0x32, 0xb2], "header15", "15"),
        (65, &[0x43, 0x0, 0x80], "header65", "65"),
    ];

    const INDEX_DYNAMIC_POST_TEST: &[(u64, &[u8], &str, &str)] = &[
        (0, &[0x02, 0x80, 0x10], "header0", "0"),
        (10, &[0x0c, 0x8a, 0x1a], "header10", "10"),
        (15, &[0x11, 0x8f, 0x1f, 0x00], "header15", "15"),
        (65, &[0x43, 0xc1, 0x1f, 0x32], "header65", "65"),
    ];

    const NAME_REF_STATIC: &[(u64, &[u8], &str, &str)] = &[
        (
            0,
            &[
                0x00, 0x00, 0x50, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79,
            ],
            ":authority",
            "custom-key",
        ),
        (
            10,
            &[
                0x00, 0x00, 0x5a, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79,
            ],
            "last-modified",
            "custom-key",
        ),
        (
            15,
            &[
                0x00, 0x00, 0x5f, 0x00, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            ":method",
            "custom-key",
        ),
        (
            65,
            &[
                0x00, 0x00, 0x5f, 0x32, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            ":status",
            "custom-key",
        ),
    ];

    const NAME_REF_DYNAMIC: &[(u64, &[u8], &str, &str)] = &[
        (
            0,
            &[
                0x02, 0x41, 0x4f, 0x32, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            "header0",
            "custom-key",
        ),
        (
            10,
            &[
                0x0c, 0x37, 0x4f, 0x28, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            "header10",
            "custom-key",
        ),
        (
            15,
            &[
                0x11, 0x32, 0x4f, 0x23, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            "header15",
            "custom-key",
        ),
        (
            65,
            &[
                0x43, 0x00, 0x40, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79,
            ],
            "header65",
            "custom-key",
        ),
    ];

    const NAME_REF_DYNAMIC_POST: &[(u64, &[u8], &str, &str)] = &[
        (
            0,
            &[
                0x02, 0x80, 0x00, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79,
            ],
            "header0",
            "custom-key",
        ),
        (
            10,
            &[
                0x0c, 0x8a, 0x07, 0x03, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            "header10",
            "custom-key",
        ),
        (
            15,
            &[
                0x11, 0x8f, 0x07, 0x08, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            "header15",
            "custom-key",
        ),
        (
            65,
            &[
                0x43, 0xc1, 0x07, 0x3a, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                0x79,
            ],
            "header65",
            "custom-key",
        ),
    ];

    const NAME_REF_DYNAMIC_HUFFMAN: &[(u64, &[u8], &str, &str)] = &[
        (
            0,
            &[
                0x02, 0x41, 0x4f, 0x32, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
            ],
            "header0",
            "custom-key",
        ),
        (
            10,
            &[
                0x0c, 0x37, 0x4f, 0x28, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
            ],
            "header10",
            "custom-key",
        ),
        (
            15,
            &[
                0x11, 0x32, 0x4f, 0x23, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
            ],
            "header15",
            "custom-key",
        ),
        (
            65,
            &[
                0x43, 0x00, 0x40, 0x88, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
            ],
            "header65",
            "custom-key",
        ),
    ];

    const VALUE: &[u8] = &[0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79];

    const LITERAL_LITERAL: &[u8] = &[
        0x0, 0x42, 0x27, 0x03, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79, 0x0a,
        0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79,
    ];
    const LITERAL_LITERAL_HUFFMAN: &[u8] = &[
        0x0, 0x42, 0x2f, 0x01, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, 0x88, 0x25, 0xa8,
        0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
    ];

    const LITERAL_VALUE: &str = "custom-key";

    #[test]
    fn encode_indexed_static() {
        for (index, result, _, _) in INDEX_STATIC_TEST {
            let mut encoded_h = HeaderEncoder::new(0, true, 1000);
            encoded_h.encode_indexed_static(*index);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }

    #[test]
    fn encode_indexed_dynamic() {
        for (index, result, _, _) in INDEX_DYNAMIC_TEST {
            let mut encoded_h = HeaderEncoder::new(66, true, 1000);
            encoded_h.encode_indexed_dynamic(*index);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }

    #[test]
    fn encode_indexed_dynamic_post() {
        for (index, result, _, _) in INDEX_DYNAMIC_POST_TEST {
            let mut encoded_h = HeaderEncoder::new(0, true, 1000);
            encoded_h.encode_indexed_dynamic(*index);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }

    #[test]
    fn encode_literal_with_name_ref_static() {
        for (index, result, _, _) in NAME_REF_STATIC {
            let mut encoded_h = HeaderEncoder::new(0, false, 1000);
            encoded_h.encode_literal_with_name_ref(true, *index, VALUE);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }

    #[test]
    fn encode_literal_with_name_ref_dynamic() {
        for (index, result, _, _) in NAME_REF_DYNAMIC {
            let mut encoded_h = HeaderEncoder::new(66, false, 1000);
            encoded_h.encode_literal_with_name_ref(false, *index, VALUE);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }

    #[test]
    fn encode_literal_with_name_ref_dynamic_post() {
        for (index, result, _, _) in NAME_REF_DYNAMIC_POST {
            let mut encoded_h = HeaderEncoder::new(0, false, 1000);
            encoded_h.encode_literal_with_name_ref(false, *index, VALUE);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }

    #[test]
    fn encode_literal_with_name_ref_dynamic_huffman() {
        for (index, result, _, _) in NAME_REF_DYNAMIC_HUFFMAN {
            let mut encoded_h = HeaderEncoder::new(66, true, 1000);
            encoded_h.encode_literal_with_name_ref(false, *index, VALUE);
            encoded_h.encode_header_block_prefix();
            assert_eq!(&&*encoded_h, result);
        }
    }
    #[test]
    fn encode_literal_with_literal() {
        let mut encoded_h = HeaderEncoder::new(66, false, 1000);
        encoded_h.encode_literal_with_name_literal(VALUE, VALUE);
        encoded_h.encode_header_block_prefix();
        assert_eq!(&*encoded_h, LITERAL_LITERAL);

        let mut encoded_h = HeaderEncoder::new(66, true, 1000);
        encoded_h.encode_literal_with_name_literal(VALUE, VALUE);
        encoded_h.encode_header_block_prefix();
        assert_eq!(&*encoded_h, LITERAL_LITERAL_HUFFMAN);
    }

    #[test]
    fn decode_indexed_static() {
        for (_, encoded, decoded1, decoded2) in INDEX_STATIC_TEST {
            let table = HeaderTable::new(false);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    fn fill_table(table: &mut HeaderTable) {
        table.set_capacity(10000).unwrap();
        for i in 0..66 {
            let mut v = b"header".to_vec();
            let mut num = i.to_string().as_bytes().to_vec();
            v.append(&mut num);
            table.insert(&v[..], i.to_string().as_bytes()).unwrap();
        }
    }

    #[test]
    fn decode_indexed_dynamic() {
        for (_, encoded, decoded1, decoded2) in INDEX_DYNAMIC_TEST {
            let mut table = HeaderTable::new(false);
            fill_table(&mut table);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    #[test]
    fn decode_indexed_dynamic_post() {
        for (_, encoded, decoded1, decoded2) in INDEX_DYNAMIC_POST_TEST {
            let mut table = HeaderTable::new(false);
            fill_table(&mut table);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    #[test]
    fn decode_literal_with_name_ref_static() {
        for (_, encoded, decoded1, decoded2) in NAME_REF_STATIC {
            let table = HeaderTable::new(false);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    #[test]
    fn decode_literal_with_name_ref_dynamic() {
        for (_, encoded, decoded1, decoded2) in NAME_REF_DYNAMIC {
            let mut table = HeaderTable::new(false);
            fill_table(&mut table);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    #[test]
    fn decode_literal_with_name_ref_dynamic_post() {
        for (_, encoded, decoded1, decoded2) in NAME_REF_DYNAMIC_POST {
            let mut table = HeaderTable::new(false);
            fill_table(&mut table);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    #[test]
    fn decode_literal_with_name_ref_dynamic_huffman() {
        for (_, encoded, decoded1, decoded2) in NAME_REF_DYNAMIC_HUFFMAN {
            let mut table = HeaderTable::new(false);
            fill_table(&mut table);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    #[test]
    fn decode_literal_literal() {
        let mut table = HeaderTable::new(false);
        fill_table(&mut table);
        let mut decoder_h = HeaderDecoder::new(LITERAL_LITERAL);
        if let HeaderDecoderResult::Headers(result) =
            decoder_h.decode_header_block(&table, 1000, 0).unwrap()
        {
            assert_eq!(result.len(), 1);
            assert_eq!(result[0].name(), LITERAL_VALUE);
            assert_eq!(result[0].value(), LITERAL_VALUE);
        } else {
            panic!("No headers");
        }

        let mut decoder_h = HeaderDecoder::new(LITERAL_LITERAL_HUFFMAN);
        if let HeaderDecoderResult::Headers(result) =
            decoder_h.decode_header_block(&table, 1000, 0).unwrap()
        {
            assert_eq!(result.len(), 1);
            assert_eq!(result[0].name(), LITERAL_VALUE);
            assert_eq!(result[0].value(), LITERAL_VALUE);
        } else {
            panic!("No headers");
        }
    }

    // Test that we are ignoring N-bit.
    #[test]
    fn decode_ignore_n_bit() {
        const TEST_N_BIT: &[(&[u8], &str, &str)] = &[
            (
                &[
                    0x02, 0x41, 0x6f, 0x32, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b,
                    0x65, 0x79,
                ],
                "header0",
                "custom-key",
            ),
            (
                &[
                    0x02, 0x80, 0x08, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                    0x79,
                ],
                "header0",
                "custom-key",
            ),
            (
                &[
                    0x0, 0x42, 0x37, 0x03, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65,
                    0x79, 0x0a, 0x63, 0x75, 0x73, 0x74, 0x6f, 0x6d, 0x2d, 0x6b, 0x65, 0x79,
                ],
                "custom-key",
                "custom-key",
            ),
            (
                &[
                    0x0, 0x42, 0x3f, 0x01, 0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f, 0x88,
                    0x25, 0xa8, 0x49, 0xe9, 0x5b, 0xa9, 0x7d, 0x7f,
                ],
                "custom-key",
                "custom-key",
            ),
        ];

        for (encoded, decoded1, decoded2) in TEST_N_BIT {
            let mut table = HeaderTable::new(false);
            fill_table(&mut table);
            let mut decoder_h = HeaderDecoder::new(encoded);
            if let HeaderDecoderResult::Headers(result) =
                decoder_h.decode_header_block(&table, 1000, 0).unwrap()
            {
                assert_eq!(result.len(), 1);
                assert_eq!(result[0].name(), *decoded1);
                assert_eq!(result[0].value(), *decoded2);
            } else {
                panic!("No headers");
            }
        }
    }

    /// If the base calculation goes negative, that is an error.
    #[test]
    fn negative_base() {
        let mut table = HeaderTable::new(false);
        fill_table(&mut table);
        let mut decoder_h = HeaderDecoder::new(&[0x0, 0x87, 0x01, 0x02, 0x03]);
        assert_eq!(
            Error::DecompressionFailed,
            decoder_h.decode_header_block(&table, 1000, 0).unwrap_err()
        );
    }

    /// If the base calculation overflows the largest value we support (`u64::MAX`),
    /// then that is an error.
    #[test]
    fn overflow_base() {
        let mut table = HeaderTable::new(false);
        fill_table(&mut table);
        // A small required insert count is necessary, but we can set the
        // base delta to u64::MAX.
        let mut decoder_h = HeaderDecoder::new(&[
            0xff, 0x01, 0x7f, 0x80, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x01, 0x02,
            0x03,
        ]);
        assert_eq!(
            Error::DecompressionFailed,
            decoder_h.decode_header_block(&table, 1000, 0).unwrap_err()
        );
    }
}

[ Dauer der Verarbeitung: 0.6 Sekunden  (vorverarbeitet)  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge