From 872b840695eac41a585a569a1bad399a1d6b6b4b Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Mon, 21 Aug 2023 00:22:04 +0800 Subject: [PATCH] qpack Signed-off-by: Weng Shihao --- ylong_http/Cargo.toml | 2 +- ylong_http/src/h3/error.rs | 13 + ylong_http/src/h3/mod.rs | 5 + ylong_http/src/h3/parts.rs | 61 ++ ylong_http/src/h3/pseudo.rs | 506 +++++++++++++ ylong_http/src/h3/qpack/decoder.rs | 614 ++++++++++++++++ ylong_http/src/h3/qpack/encoder.rs | 167 +++++ ylong_http/src/h3/qpack/format/decoder.rs | 719 +++++++++++++++++++ ylong_http/src/h3/qpack/format/encoder.rs | 836 ++++++++++++++++++++++ ylong_http/src/h3/qpack/format/mod.rs | 7 + ylong_http/src/h3/qpack/integer.rs | 132 ++++ ylong_http/src/h3/qpack/mod.rs | 221 ++++++ ylong_http/src/h3/qpack/table.rs | 507 +++++++++++++ 13 files changed, 3789 insertions(+), 1 deletion(-) create mode 100644 ylong_http/src/h3/error.rs create mode 100644 ylong_http/src/h3/parts.rs create mode 100644 ylong_http/src/h3/pseudo.rs create mode 100644 ylong_http/src/h3/qpack/decoder.rs create mode 100644 ylong_http/src/h3/qpack/encoder.rs create mode 100644 ylong_http/src/h3/qpack/format/decoder.rs create mode 100644 ylong_http/src/h3/qpack/format/encoder.rs create mode 100644 ylong_http/src/h3/qpack/format/mod.rs create mode 100644 ylong_http/src/h3/qpack/integer.rs create mode 100644 ylong_http/src/h3/qpack/mod.rs create mode 100644 ylong_http/src/h3/qpack/table.rs diff --git a/ylong_http/Cargo.toml b/ylong_http/Cargo.toml index d6cb5df..195f1b6 100644 --- a/ylong_http/Cargo.toml +++ b/ylong_http/Cargo.toml @@ -10,7 +10,7 @@ keywords = ["ylong", "http"] # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -default = ["http1_1", "tokio_base"] +default = ["http1_1", "tokio_base","huffman","http3"] full = [ "http1_1", "http2", diff --git a/ylong_http/src/h3/error.rs b/ylong_http/src/h3/error.rs new file mode 100644 index 0000000..11de8bd --- /dev/null +++ b/ylong_http/src/h3/error.rs @@ -0,0 +1,13 @@ +pub enum H3Error { + //todo: add more + ConnectionError(ErrorCode), +} + +#[derive(Debug, Eq, PartialEq, Clone)] +pub enum ErrorCode { + QPACK_DECOMPRESSION_FAILED = 0x0200, + + QPACK_ENCODER_STREAM_ERROR = 0x0201, + + QPACK_DECODER_STREAM_ERROR = 0x0202, +} \ No newline at end of file diff --git a/ylong_http/src/h3/mod.rs b/ylong_http/src/h3/mod.rs index b75d4c3..22272cd 100644 --- a/ylong_http/src/h3/mod.rs +++ b/ylong_http/src/h3/mod.rs @@ -12,3 +12,8 @@ // limitations under the License. // TODO: `HTTP/3` Module. + +mod qpack; +mod parts; +mod pseudo; +mod error; \ No newline at end of file diff --git a/ylong_http/src/h3/parts.rs b/ylong_http/src/h3/parts.rs new file mode 100644 index 0000000..7bd4979 --- /dev/null +++ b/ylong_http/src/h3/parts.rs @@ -0,0 +1,61 @@ + + +use crate::h3::pseudo::PseudoHeaders; +use crate::headers::Headers; +use crate::h3::qpack::table::Field; +#[derive(PartialEq, Eq, Clone)] +pub struct Parts { + pub(crate) pseudo: PseudoHeaders, + pub(crate) map: Headers, +} + +impl Parts { + /// The constructor of `Parts` + pub fn new() -> Self { + Self { + pseudo: PseudoHeaders::new(), + map: Headers::new(), + } + } + + /// Sets pseudo headers for `Parts`. + pub fn set_pseudo(&mut self, pseudo: PseudoHeaders) { + self.pseudo = pseudo; + } + + /// Sets regular field lines for `Parts`. + pub fn set_header_lines(&mut self, headers: Headers) { + self.map = headers; + } + + pub(crate) fn is_empty(&self) -> bool { + self.pseudo.is_empty() && self.map.is_empty() + } + + pub(crate) fn update(&mut self, headers: Field, value: String) { + match headers { + Field::Authority => self.pseudo.set_authority(Some(value)), + Field::Method => self.pseudo.set_method(Some(value)), + Field::Path => self.pseudo.set_path(Some(value)), + Field::Scheme => self.pseudo.set_scheme(Some(value)), + Field::Status => self.pseudo.set_status(Some(value)), + Field::Other(header) => self.map.append(header.as_str(), value.as_str()).unwrap(), + } + } + + pub(crate) fn parts(&self) -> (&PseudoHeaders, &Headers) { + (&self.pseudo, &self.map) + } + + pub(crate) fn into_parts(self) -> (PseudoHeaders, Headers) { + (self.pseudo, self.map) + } +} + + + +impl Default for Parts { + fn default() -> Self { + Self::new() + } +} \ No newline at end of file diff --git a/ylong_http/src/h3/pseudo.rs b/ylong_http/src/h3/pseudo.rs new file mode 100644 index 0000000..b80ca75 --- /dev/null +++ b/ylong_http/src/h3/pseudo.rs @@ -0,0 +1,506 @@ +// Copyright (c) 2023 Huawei Device Co., Ltd. +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +/// [Pseudo-Header fields] that may appear in http2 header fields. +/// +/// [Pseudo-Header fields]: https://httpwg.org/specs/rfc9113.html#PseudoHeaderFields +/// +/// # Note +/// The current structure is not responsible for checking every value. +// TODO: 考虑将 PseudoHeaders 拆分成 `RequestPseudo` 和 `ResponsePseudo`. +#[derive(Clone, PartialEq, Eq)] +pub struct PseudoHeaders { + authority: Option, // Request. + method: Option, // Request. + path: Option, // Request. + scheme: Option, // Request. + status: Option, // Response. +} + +// TODO: 去掉冗余的方法。 +impl PseudoHeaders { + /// Create a new `PseudoHeaders`. + pub(crate) fn new() -> Self { + Self { + authority: None, + method: None, + path: None, + scheme: None, + status: None, + } + } + + pub(crate) fn is_empty(&self) -> bool { + self.authority.is_none() + && self.method.is_none() + && self.path.is_none() + && self.scheme.is_none() + && self.status.is_none() + } + + /// Check if it contains `Authority`. + pub(crate) fn contains_authority(&self) -> bool { + self.authority.is_some() + } + + /// Get the `&str` value of `Authority`. + pub fn authority(&self) -> Option<&str> { + self.authority.as_deref() + } + + /// Set the value of `Authority`. + pub fn set_authority(&mut self, authority: Option) { + self.authority = authority; + } + + /// Take the `String` value of `Authority`. + pub(crate) fn take_authority(&mut self) -> Option { + self.authority.take() + } + + /// Check if it contains `Method`. + pub(crate) fn contains_method(&self) -> bool { + self.method.is_some() + } + + /// Get the `&str` value of `Method`. + pub fn method(&self) -> Option<&str> { + self.method.as_deref() + } + + /// Set the value of `Method`. + pub fn set_method(&mut self, method: Option) { + self.method = method; + } + + /// Take the `String` value of `Method`. + pub(crate) fn take_method(&mut self) -> Option { + self.method.take() + } + + /// Check if it contains `Path`. + pub(crate) fn contains_path(&self) -> bool { + self.path.is_some() + } + + /// Get the `&str` value of `Path`. + pub fn path(&self) -> Option<&str> { + self.path.as_deref() + } + + /// Set the value of `Path`. + pub fn set_path(&mut self, path: Option) { + self.path = path; + } + + /// Take the `String` value of `Path`. + pub(crate) fn take_path(&mut self) -> Option { + self.path.take() + } + + /// Check if it contains `Scheme`. + pub(crate) fn contains_scheme(&self) -> bool { + self.scheme.is_some() + } + + /// Get the `&str` value of `Scheme`. + pub fn scheme(&self) -> Option<&str> { + self.scheme.as_deref() + } + + /// Set the value of `Scheme`. + pub fn set_scheme(&mut self, scheme: Option) { + self.scheme = scheme; + } + + /// Take the `String` value of `Scheme`. + pub(crate) fn take_scheme(&mut self) -> Option { + self.scheme.take() + } + + /// Check if it contains `Status`. + pub(crate) fn contains_status(&self) -> bool { + self.status.is_some() + } + + /// Get the `&str` value of `Status`. + pub fn status(&self) -> Option<&str> { + self.status.as_deref() + } + + /// Set the value of `Status`. + pub fn set_status(&mut self, status: Option) { + self.status = status; + } + + /// Take the `String` value of `Status`. + pub(crate) fn take_status(&mut self) -> Option { + self.status.take() + } +} + +impl Default for PseudoHeaders { + fn default() -> Self { + PseudoHeaders::new() + } +} + +#[cfg(test)] +mod ut_pseudo_headers { + use crate::h3::pseudo::PseudoHeaders; + + /// UT test cases for `PseudoHeaders::new`. + /// + /// # Brief + /// 1. Calls `PseudoHeaders::new` to create a `PseudoHeaders`. + /// 2. Checks if the result has a default value. + #[test] + fn ut_pseudo_headers_new() { + let pseudo = PseudoHeaders::new(); + assert!(pseudo.authority.is_none()); + assert!(pseudo.method.is_none()); + assert!(pseudo.path.is_none()); + assert!(pseudo.scheme.is_none()); + assert!(pseudo.status.is_none()); + } + + /// UT test cases for `PseudoHeaders::contains_authority`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::contains_authority` of it. + /// 3. Calls `PseudoHeaders::contains_authority` of it after its `authority` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_contains_authority() { + let mut pseudo = PseudoHeaders::new(); + assert!(!pseudo.contains_authority()); + + pseudo.authority = Some(String::from("authority")); + assert!(pseudo.contains_authority()); + } + + /// UT test cases for `PseudoHeaders::authority`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::authority` of it. + /// 3. Calls `PseudoHeaders::authority` of it after its `authority` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_authority() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.authority().is_none()); + + pseudo.authority = Some(String::from("authority")); + assert_eq!(pseudo.authority(), Some("authority")); + } + + /// UT test cases for `PseudoHeaders::set_authority`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::set_authority` of it to set `authority` a value. + /// 3. Checks the results. + #[test] + fn ut_pseudo_headers_set_authority() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.authority().is_none()); + + pseudo.set_authority(Some(String::from("authority"))); + assert_eq!(pseudo.authority(), Some("authority")); + + pseudo.set_authority(None); + assert!(pseudo.authority().is_none()); + } + + /// UT test cases for `PseudoHeaders::take_authority`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::take_authority` of it. + /// 3. Calls `PseudoHeaders::take_authority` of it after its `authority` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_take_authority() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.take_authority().is_none()); + + pseudo.authority = Some(String::from("authority")); + assert_eq!(pseudo.take_authority(), Some(String::from("authority"))); + } + + /// UT test cases for `PseudoHeaders::contains_method`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::contains_method` of it. + /// 3. Calls `PseudoHeaders::contains_method` of it after its `method` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_contains_method() { + let mut pseudo = PseudoHeaders::new(); + assert!(!pseudo.contains_method()); + + pseudo.method = Some(String::from("method")); + assert!(pseudo.contains_method()); + } + + /// UT test cases for `PseudoHeaders::method`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::method` of it. + /// 3. Calls `PseudoHeaders::method` of it after its `method` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_method() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.method().is_none()); + + pseudo.method = Some(String::from("method")); + assert_eq!(pseudo.method(), Some("method")); + } + + /// UT test cases for `PseudoHeaders::set_method`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::set_method` of it to set `method` a value. + /// 3. Checks the results. + #[test] + fn ut_pseudo_headers_set_method() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.method().is_none()); + + pseudo.set_method(Some(String::from("method"))); + assert_eq!(pseudo.method(), Some("method")); + + pseudo.set_method(None); + assert!(pseudo.method().is_none()); + } + + /// UT test cases for `PseudoHeaders::take_method`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::take_method` of it. + /// 3. Calls `PseudoHeaders::take_method` of it after its `method` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_take_method() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.take_method().is_none()); + + pseudo.method = Some(String::from("method")); + assert_eq!(pseudo.take_method(), Some(String::from("method"))); + } + + /// UT test cases for `PseudoHeaders::contains_path`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::contains_path` of it. + /// 3. Calls `PseudoHeaders::contains_path` of it after its `path` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_contains_path() { + let mut pseudo = PseudoHeaders::new(); + assert!(!pseudo.contains_path()); + + pseudo.path = Some(String::from("path")); + assert!(pseudo.contains_path()); + } + + /// UT test cases for `PseudoHeaders::path`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::path` of it. + /// 3. Calls `PseudoHeaders::path` of it after its `path` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_path() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.path().is_none()); + + pseudo.path = Some(String::from("path")); + assert_eq!(pseudo.path(), Some("path")); + } + + /// UT test cases for `PseudoHeaders::set_path`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::set_path` of it to set `path` a value. + /// 3. Checks the results. + #[test] + fn ut_pseudo_headers_set_path() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.path().is_none()); + + pseudo.set_path(Some(String::from("path"))); + assert_eq!(pseudo.path(), Some("path")); + + pseudo.set_path(None); + assert!(pseudo.path().is_none()); + } + + /// UT test cases for `PseudoHeaders::take_path`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::take_path` of it. + /// 3. Calls `PseudoHeaders::take_path` of it after its `path` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_take_path() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.take_path().is_none()); + + pseudo.path = Some(String::from("path")); + assert_eq!(pseudo.take_path(), Some(String::from("path"))); + } + + /// UT test cases for `PseudoHeaders::contains_scheme`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::contains_scheme` of it. + /// 3. Calls `PseudoHeaders::contains_scheme` of it after its `scheme` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_contains_scheme() { + let mut pseudo = PseudoHeaders::new(); + assert!(!pseudo.contains_scheme()); + + pseudo.scheme = Some(String::from("scheme")); + assert!(pseudo.contains_scheme()); + } + + /// UT test cases for `PseudoHeaders::scheme`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::scheme` of it. + /// 3. Calls `PseudoHeaders::scheme` of it after its `scheme` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_scheme() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.scheme().is_none()); + + pseudo.scheme = Some(String::from("scheme")); + assert_eq!(pseudo.scheme(), Some("scheme")); + } + + /// UT test cases for `PseudoHeaders::set_scheme`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::set_scheme` of it to set `scheme` a value. + /// 3. Checks the results. + #[test] + fn ut_pseudo_headers_set_scheme() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.scheme().is_none()); + + pseudo.set_scheme(Some(String::from("scheme"))); + assert_eq!(pseudo.scheme(), Some("scheme")); + + pseudo.set_scheme(None); + assert!(pseudo.scheme().is_none()); + } + + /// UT test cases for `PseudoHeaders::take_scheme`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::take_scheme` of it. + /// 3. Calls `PseudoHeaders::take_scheme` of it after its `scheme` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_take_scheme() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.take_scheme().is_none()); + + pseudo.scheme = Some(String::from("scheme")); + assert_eq!(pseudo.take_scheme(), Some(String::from("scheme"))); + } + + /// UT test cases for `PseudoHeaders::contains_status`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::contains_status` of it. + /// 3. Calls `PseudoHeaders::contains_status` of it after its `status` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_contains_status() { + let mut pseudo = PseudoHeaders::new(); + assert!(!pseudo.contains_status()); + + pseudo.status = Some(String::from("status")); + assert!(pseudo.contains_status()); + } + + /// UT test cases for `PseudoHeaders::status`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::status` of it. + /// 3. Calls `PseudoHeaders::status` of it after its `status` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_status() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.status().is_none()); + + pseudo.status = Some(String::from("status")); + assert_eq!(pseudo.status(), Some("status")); + } + + /// UT test cases for `PseudoHeaders::set_status`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::set_status` of it to set `status` a value. + /// 3. Checks the results. + #[test] + fn ut_pseudo_headers_set_status() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.status().is_none()); + + pseudo.set_status(Some(String::from("status"))); + assert_eq!(pseudo.status(), Some("status")); + + pseudo.set_status(None); + assert!(pseudo.status().is_none()); + } + + /// UT test cases for `PseudoHeaders::take_status`. + /// + /// # Brief + /// 1. Creates a `PseudoHeaders`. + /// 2. Calls `PseudoHeaders::take_status` of it. + /// 3. Calls `PseudoHeaders::take_status` of it after its `status` is set. + /// 4. Checks the results. + #[test] + fn ut_pseudo_headers_take_status() { + let mut pseudo = PseudoHeaders::new(); + assert!(pseudo.take_status().is_none()); + + pseudo.status = Some(String::from("status")); + assert_eq!(pseudo.take_status(), Some(String::from("status"))); + } +} diff --git a/ylong_http/src/h3/qpack/decoder.rs b/ylong_http/src/h3/qpack/decoder.rs new file mode 100644 index 0000000..a3b6fa3 --- /dev/null +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -0,0 +1,614 @@ +use std::mem::take; +use crate::h3::error::ErrorCode::{QPACK_DECOMPRESSION_FAILED, QPACK_ENCODER_STREAM_ERROR}; +use crate::h3::error::H3Error; +use crate::h3::parts::Parts; +use crate::h3::qpack::{Representation, MidBit, ReprPrefixBit, EncoderInstruction, EncoderInstPrefixBit}; + +use crate::h3::qpack::format::decoder::{EncInstDecoder, InstDecStateHolder, Name, ReprDecoder, ReprDecStateHolder}; +use crate::h3::qpack::integer::Integer; +use crate::h3::qpack::table::{DynamicTable, Field, TableSearcher}; + + +struct FiledLines { + parts: Parts, + header_size: usize, +} + +pub(crate) struct QpackDecoder<'a> { + field_list_size: usize, + table: &'a mut DynamicTable, + repr_holder: ReprDecStateHolder, + inst_holder: InstDecStateHolder, + lines: FiledLines, + base: usize, + require_insert_count: usize, +} + +impl<'a> QpackDecoder<'a> { + pub(crate) fn new(field_list_size: usize, table: &'a mut DynamicTable) -> Self { + Self { + field_list_size, + table, + repr_holder: ReprDecStateHolder::new(), + inst_holder: InstDecStateHolder::new(), + lines: FiledLines { + parts: Parts::new(), + header_size: 0, + }, + base: 0, + require_insert_count: 0, + } + } + + /// Users can call `decode_ins` multiple times to decode decoder instructions. + pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result<(), H3Error> { + let mut decoder = EncInstDecoder::new(buf); + decoder.load(&mut self.inst_holder); + let mut updater = Updater::new(&mut self.table); + loop { + match decoder.decode()? { + Some(inst) => { + match inst { + EncoderInstruction::SetCap { capacity } => { + println!("capacity: {}", capacity); + updater.update_capacity(capacity)?; + } + EncoderInstruction::InsertWithIndex { mid_bit, name, value } => { + let value_str = String::from_utf8(value.clone()).unwrap(); + println!("value: {}", value_str); + updater.update_table(mid_bit, name, value)?; + } + EncoderInstruction::InsertWithLiteral { mid_bit, name, value } => { + let value_str = String::from_utf8(value.clone()).unwrap(); + println!("value: {}", value_str); + updater.update_table(mid_bit, name, value)?; + } + EncoderInstruction::Duplicate { index } => { + updater.duplicate(index)?; + } + } + } + None => return Result::Ok(()) + } + } + } + + + /// User call `decoder_repr` once for decoding a complete field section, which start with the `field section prefix`: + /// 0 1 2 3 4 5 6 7 + /// +---+---+---+---+---+---+---+---+ + /// | Required Insert Count (8+) | + /// +---+---------------------------+ + /// | S | Delta Base (7+) | + /// +---+---------------------------+ + /// | Encoded Field Lines ... + /// +-------------------------------+ + pub(crate) fn decode_repr(&mut self, buf: &[u8]) -> Result<(), H3Error> { + let mut decoder = ReprDecoder::new(buf); + decoder.load(&mut self.repr_holder); + + let mut searcher = Searcher::new(self.field_list_size, &self.table, &mut self.lines); + loop { + match decoder.decode()? { + Some(repr) => { + match repr { + Representation::FieldSectionPrefix { require_insert_count, signal, delta_base } => { + if require_insert_count.0 == 0{ + self.require_insert_count = 0; + } + else { + let max_entries = self.table.max_entries(); + let full_range = 2 * max_entries; + let max_value = self.table.insert_count + max_entries; + let max_wrapped = (max_value / full_range) * full_range; + self.require_insert_count = max_wrapped + require_insert_count.0 - 1; + if self.require_insert_count > max_value{ + self.require_insert_count -= full_range; + } + + } + self.require_insert_count = require_insert_count.0; + println!("require_insert_count: {}", require_insert_count.0); + println!("signal: {}", signal); + println!("delta_base: {}", delta_base.0); + if signal { + self.base = require_insert_count.0 - delta_base.0 - 1; + } else { + self.base = require_insert_count.0 + delta_base.0; + } + searcher.base = self.base; + //todo:block + } + Representation::Indexed { mid_bit, index } => { + println!("T: {:#?}", mid_bit.t); + println!("N: {:#?}", mid_bit.n); + println!("H: {:#?}", mid_bit.h); + println!("index: {}", index); + searcher.search(Representation::Indexed { mid_bit, index })?; + } + Representation::IndexedWithPostIndex { index } => { + println!("post index: {}", index); + searcher.search(Representation::IndexedWithPostIndex { index })?; + } + Representation::LiteralWithIndexing { mid_bit, name, value } => { + // convert value to str according to ascii + let value_str = String::from_utf8(value.clone()).unwrap(); + println!("value: {}", value_str); + searcher.search_literal_with_indexing(mid_bit, name, value)?; + } + Representation::LiteralWithPostIndexing { mid_bit, name, value } => { + let value_str = String::from_utf8(value.clone()).unwrap(); + println!("value: {}", value_str); + searcher.search_literal_with_post_indexing(mid_bit, name, value)?; + } + Representation::LiteralWithLiteralName { mid_bit, name, value } => { + if let Name::Literal(_name) = name.clone() { + let name_str = String::from_utf8(_name.clone()).unwrap(); + println!("name: {}", name_str); + } else { + print!("error"); + } + let value_str = String::from_utf8(value.clone()).unwrap(); + println!("value: {}", value_str); + searcher.search_listeral_with_literal(mid_bit, name, value)?; + } + } + } + None => return Result::Ok(()) + } + }; + } + + /// Users call `finish` to stop decoding a field section. And send an `Section Acknowledgment` to encoder: + /// After processing an encoded field section whose declared Required Insert Count is not zero, + /// the decoder emits a Section Acknowledgment instruction. The instruction starts with the + /// '1' 1-bit pattern, followed by the field section's associated stream ID encoded as + /// a 7-bit prefix integer + /// 0 1 2 3 4 5 6 7 + /// +---+---+---+---+---+---+---+---+ + /// | 1 | Stream ID (7+) | + /// +---+---------------------------+ + pub(crate) fn finish(&mut self, stream_id: usize, buf: &mut [u8]) -> Result<(Parts, Option), H3Error> { + if !self.repr_holder.is_empty() { + return Err(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED)); + } + self.lines.header_size = 0; + if self.require_insert_count > 0 { + let mut ack = Integer::index(0x80, stream_id, 0x7f); + let size = ack.encode(buf); + if let Ok(size) = size { + return Ok((take(&mut self.lines.parts), Some(size))); + } + } + Ok((take(&mut self.lines.parts), None)) + } + + /// Users call `stream_cancel` to stop cancel a stream. And send an `Stream Cancellation` to encoder: + /// When a stream is reset or reading is abandoned, the decoder emits a Stream Cancellation + /// instruction. The instruction starts with the '01' 2-bit pattern, + /// followed by the stream ID of the affected stream encoded as a 6-bit prefix integer. + /// 0 1 2 3 4 5 6 7 + /// +---+---+---+---+---+---+---+---+ + /// | 0 | 1 | Stream ID (6+) | + /// +---+---+-----------------------+ + pub(crate) fn stream_cancel(&mut self, stream_id: usize, buf: &mut [u8]) -> Result { + let mut ack = Integer::index(0x40, stream_id, 0x3f); + let size = ack.encode(buf); + if let Ok(size) = size { + return Ok(size); + } + Err(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED)) + } +} + +struct Updater<'a> { + table: &'a mut DynamicTable, +} + +impl<'a> Updater<'a> { + fn new(table: &'a mut DynamicTable) -> Self { + Self { + table, + } + } + + fn update_capacity(&mut self, capacity: usize) -> Result<(), H3Error> { + self.table.update_size(capacity); + Ok(()) + } + + fn update_table(&mut self, mid_bit: MidBit, name: Name, value: Vec) -> Result<(), H3Error> { + let (f, v) = self.get_field_by_name_and_value(mid_bit, name, value, self.table.insert_count)?; + self.table.update(f, v); + Ok(()) + } + + fn duplicate(&mut self, index: usize) -> Result<(), H3Error> { + let table_searcher = TableSearcher::new(self.table); + let (f, v) = table_searcher + .find_field_dynamic(self.table.insert_count - index) + .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; + self.table.update(f, v); + Ok(()) + } + + fn get_field_by_name_and_value( + &self, + mid_bit: MidBit, + name: Name, + value: Vec, + insert_count: usize, + ) -> Result<(Field, String), H3Error> { + let h = match name { + Name::Index(index) => { + let searcher = TableSearcher::new(self.table); + if let Some(true) = mid_bit.t { + searcher + .find_field_name_static(index) + .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? + } else { + searcher + .find_field_name_dynamic(insert_count - index) + .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? + } + } + Name::Literal(octets) => Field::Other( + String::from_utf8(octets) + .map_err(|_| H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?, + ), + }; + let v = String::from_utf8(value) + .map_err(|_| H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; + Ok((h, v)) + } +} + + +struct Searcher<'a> { + field_list_size: usize, + table: &'a DynamicTable, + lines: &'a mut FiledLines, + base: usize, +} + +impl<'a> Searcher<'a> { + fn new(field_list_size: usize, table: &'a DynamicTable, lines: &'a mut FiledLines) -> Self { + Self { + field_list_size, + table, + lines, + base: 0, + } + } + + fn search(&mut self, repr: Representation) -> Result<(), H3Error> { + match repr { + Representation::Indexed { mid_bit, index } => { + self.search_indexed(mid_bit, index) + } + Representation::IndexedWithPostIndex { index } => { + self.search_post_indexed(index) + } + _ => { + Ok(()) + } + } + } + + fn search_indexed(&mut self, mid_bit: MidBit, index: usize) -> Result<(), H3Error> { + let table_searcher = TableSearcher::new(self.table); + if let Some(true) = mid_bit.t { + let (f, v) = table_searcher + .find_field_static(index) + .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + self.lines.parts.update(f, v); + return Ok(()); + } else { + let (f, v) = table_searcher + .find_field_dynamic(self.base - index - 1) + .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + self.lines.parts.update(f, v); + return Ok(()); + } + } + + fn search_post_indexed(&mut self, index: usize) -> Result<(), H3Error> { + let table_searcher = TableSearcher::new(self.table); + let (f, v) = table_searcher + .find_field_dynamic(self.base + index) + .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + self.check_field_list_size(&f, &v)?; + self.lines.parts.update(f, v); + return Ok(()); + } + + fn search_literal_with_indexing(&mut self, mid_bit: MidBit, name: Name, value: Vec) -> Result<(), H3Error> { + let (f, v) = self.get_field_by_name_and_value(mid_bit, name, value, ReprPrefixBit::LITERALWITHINDEXING)?; + self.check_field_list_size(&f, &v)?; + self.lines.parts.update(f, v); + Ok(()) + } + + fn search_literal_with_post_indexing(&mut self, mid_bit: MidBit, name: Name, value: Vec) -> Result<(), H3Error> { + let (f, v) = self.get_field_by_name_and_value(mid_bit, name, value, ReprPrefixBit::LITERALWITHPOSTINDEXING)?; + self.check_field_list_size(&f, &v)?; + self.lines.parts.update(f, v); + Ok(()) + } + + fn search_listeral_with_literal(&mut self, mid_bit: MidBit, name: Name, value: Vec) -> Result<(), H3Error> { + let (h, v) = self.get_field_by_name_and_value(mid_bit, name, value, ReprPrefixBit::LITERALWITHLITERALNAME)?; + self.check_field_list_size(&h, &v)?; + self.lines.parts.update(h, v); + Ok(()) + } + + + fn get_field_by_name_and_value( + &self, + mid_bit: MidBit, + name: Name, + value: Vec, + repr: ReprPrefixBit, + ) -> Result<(Field, String), H3Error> { + let h = match name { + Name::Index(index) => { + if repr == ReprPrefixBit::LITERALWITHINDEXING { + let searcher = TableSearcher::new(self.table); + if let Some(true) = mid_bit.t { + searcher + .find_field_name_static(index) + .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + } else { + searcher + .find_field_name_dynamic(self.base - index - 1) + .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + } + } else { + let searcher = TableSearcher::new(self.table); + searcher + .find_field_name_dynamic(self.base + index) + .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + } + } + Name::Literal(octets) => Field::Other( + String::from_utf8(octets) + .map_err(|_| H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?, + ), + }; + let v = String::from_utf8(value) + .map_err(|_| H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + Ok((h, v)) + } + pub(crate) fn update_size(&mut self, addition: usize) { + self.lines.header_size += addition; + } + fn check_field_list_size(&mut self, key: &Field, value: &String) -> Result<(), H3Error> { + let line_size = field_line_length(key.len(), value.len()); + self.update_size(line_size); + if self.lines.header_size > self.field_list_size { + Err(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED)) + } else { + Ok(()) + } + } +} + +fn field_line_length(key_size: usize, value_size: usize) -> usize { + key_size + value_size + 32 +} + +#[cfg(test)] +mod ut_qpack_decoder { + use crate::h3::qpack::table::{DynamicTable, Field}; + use crate::h3::qpack::QpackDecoder; + use crate::test_util::decode; + + const MAX_HEADER_LIST_SIZE: usize = 16 << 20; + + + #[test] + fn ut_qpack_decoder() { + // test_indexed_static(); + // test_indexed_dynamic(); + // test_post_indexed_dynamic(); + // test_literal_indexing_static(); + // test_literal_indexing_dynamic(); + // test_literal_post_indexing_dynamic(); + // test_literal_with_literal_name(); + test_setcap(); + macro_rules! check_pseudo { + ( + $pseudo: expr, + { $a: expr, $m: expr, $p: expr, $sc: expr, $st: expr } $(,)? + ) => { + assert_eq!($pseudo.authority(), $a); + assert_eq!($pseudo.method(), $m); + assert_eq!($pseudo.path(), $p); + assert_eq!($pseudo.scheme(), $sc); + assert_eq!($pseudo.status(), $st); + }; + } + + macro_rules! get_parts { + ($qpack: expr $(, $input: literal)*) => {{ + $( + let text = decode($input).unwrap(); + println!("text: {:#?}", text); + assert!($qpack.decode_repr(text.as_slice()).is_ok()); + )* + let mut ack = [0u8; 20]; + match $qpack.finish(1,&mut ack) { + Ok((parts,_)) => parts, + Err(_) => panic!("QpackDecoder::finish() failed!"), + } + }}; + } + macro_rules! check_map { + ($map: expr, { $($(,)? $k: literal => $v: literal)* } $(,)?) => { + $( + assert_eq!($map.get($k).unwrap().to_str().unwrap(), $v); + )* + } + } + macro_rules! qpack_test_case { + ( + $qpack: expr $(, $input: literal)*, + { $a: expr, $m: expr, $p: expr, $sc: expr, $st: expr }, + { $size: expr $(, $($k2: literal)? $($k3: ident)? => $v2: literal)* } $(,)? + ) => { + let mut _qpack = $qpack; + let (pseudo, _) = get_parts!(_qpack $(, $input)*).into_parts(); + check_pseudo!(pseudo, { $a, $m, $p, $sc, $st }); + }; + ( + $qpack: expr $(, $input: literal)*, + { $($(,)? $k1: literal => $v1: literal)* }, + { $size: expr $(, $($k2: literal)? $($k3: ident)? => $v2: literal)* } $(,)? + ) => { + let mut _qpack = $qpack; + let (_, map) = get_parts!(_qpack $(, $input)*).into_parts(); + check_map!(map, { $($k1 => $v1)* }); + }; + ( + $hpack: expr $(, $input: literal)*, + { $a: expr, $m: expr, $p: expr, $sc: expr, $st: expr }, + { $($(,)? $k1: literal => $v1: literal)* }, + { $size: expr $(, $($k2: literal)? $($k3: ident)? => $v2: literal)* } $(,)? + ) => { + let mut _hpack = $hpack; + let (pseudo, map) = get_parts!(_hpack $(, $input)*).into_parts(); + check_pseudo!(pseudo, { $a, $m, $p, $sc, $st }); + check_map!(map, { $($k1 => $v1)* }); + }; + } + + fn test_indexed_static() + { + let mut dynamic_table = DynamicTable::with_capacity(4096); + + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + "0000d1", + { None, Some("GET"), None, None, None }, + { 0 } + ); + } + fn test_indexed_dynamic() + { + // Test index "custom-field"=>"custom-value" in dynamic table + let mut dynamic_table = DynamicTable::with_capacity(4096); + //abs = 0 + dynamic_table.update(Field::Other(String::from("custom-field")), String::from("custom-value")); + //abs = 1 + dynamic_table.update(Field::Other(String::from("my-field")), String::from("my-value")); + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + //require_insert_count=2, signal=false, delta_base=0 + //so base=2 + //rel_index=1 (abs=2(base)-1-1=0) + "020081", + {"custom-field"=>"custom-value"}, + { 0 } + ); + } + fn test_post_indexed_dynamic() + { + // Test index "custom-field"=>"custom-value" in dynamic table + let mut dynamic_table = DynamicTable::with_capacity(4096); + //abs = 0 + dynamic_table.update(Field::Other(String::from("custom1-field")), String::from("custom1-value")); + //abs = 1 + dynamic_table.update(Field::Other(String::from("custom2-field")), String::from("custom2-value")); + //abs = 2 + dynamic_table.update(Field::Other(String::from("custom3-field")), String::from("custom3-value")); + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + //require_insert_count=3, signal=true, delta_base=2 + //so base = 3-2-1 = 0 + //rel_index=1 (abs=0(base)+1=1) + "038211", + {"custom2-field"=>"custom2-value"}, + { 0 } + ); + } + fn test_literal_indexing_static() + { + let mut dynamic_table = DynamicTable::with_capacity(4096); + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + "00007f020d637573746f6d312d76616c7565", + { None, Some("custom1-value"), None, None, None }, + { 0 } + ); + } + + fn test_literal_indexing_dynamic() + { + let mut dynamic_table = DynamicTable::with_capacity(4096); + //abs = 0 + dynamic_table.update(Field::Other(String::from("custom-field")), String::from("custom-value")); + //abs = 1 + dynamic_table.update(Field::Other(String::from("my-field")), String::from("my-value")); + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + //require_insert_count=2, signal=false, delta_base=0 + //so base=2 + //rel_index=1 (abs=2(base)-1-1=0) + "0200610d637573746f6d312d76616c7565", + {"custom-field"=>"custom1-value"}, + { 0 } + ); + } + + fn test_literal_post_indexing_dynamic() + { + // Test index "custom-field"=>"custom-value" in dynamic table + let mut dynamic_table = DynamicTable::with_capacity(4096); + //abs = 0 + dynamic_table.update(Field::Other(String::from("custom1-field")), String::from("custom1-value")); + //abs = 1 + dynamic_table.update(Field::Other(String::from("custom2-field")), String::from("custom2-value")); + //abs = 2 + dynamic_table.update(Field::Other(String::from("custom3-field")), String::from("custom3-value")); + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + //require_insert_count=3, signal=true, delta_base=2 + //so base = 3-2-1 = 0 + //rel_index=1 (abs=0(base)+1=1) + "0382010d637573746f6d312d76616c7565", + {"custom2-field"=>"custom1-value"}, + { 0 } + ); + } + + fn test_literal_with_literal_name() + { + let mut dynamic_table = DynamicTable::with_capacity(4096); + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table), + "00003706637573746f6d322d76616c75650d637573746f6d312d76616c7565", + {"custom2-value"=>"custom1-value"}, + {0}, + ); + } + + fn test_setcap() + { + let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + let text = decode("3f7f").unwrap(); + println!("text: {:#?}", text); + decoder.decode_ins(text.as_slice()); + print!("capacity: {}", dynamic_table.capacity()); + assert_eq!(dynamic_table.capacity(), 158); + } + } +} + + + + + + + diff --git a/ylong_http/src/h3/qpack/encoder.rs b/ylong_http/src/h3/qpack/encoder.rs new file mode 100644 index 0000000..c994d77 --- /dev/null +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -0,0 +1,167 @@ +use std::collections::{HashMap, VecDeque}; +use crate::h3::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; +use crate::h3::error::H3Error; +use crate::h3::parts::Parts; +use crate::h3::qpack::table::DynamicTable; +use crate::h3::qpack::format::{ReprEncoder, ReprEncStateHolder}; +use crate::h3::qpack::format::encoder::{DecInstDecoder, InstDecodeState, InstDecStateHolder}; +use crate::h3::qpack::{DecoderInstruction, PrefixMask}; +use crate::h3::qpack::integer::{Integer, IntegerEncoder}; + +pub(crate) struct QpackEncoder { + table: DynamicTable, + holder: ReprEncStateHolder, + inst_holder: InstDecStateHolder, + stream_reference: VecDeque>, + stream_id: usize, +} + +impl QpackEncoder { + pub(crate) fn with_capacity(max_size: usize, encoder_buf: &mut [u8], stream_id: usize) -> (QpackEncoder, usize) { + let mut s = Self { + table: DynamicTable::with_capacity(max_size), + holder: ReprEncStateHolder::new(), + inst_holder: InstDecStateHolder::new(), + stream_reference: VecDeque::new(), + stream_id, + }; + let cur = EncoderInst::SetCap(SetCap::new(max_size)).encode(&mut encoder_buf[..]); + (s, cur) + } + + + pub(crate) fn set_parts(&mut self, parts: Parts) { + self.holder.set_parts(parts) + } + + /// Users can call `decode_ins` multiple times to decode decoder instructions. + pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result, H3Error> { + let mut decoder = DecInstDecoder::new(buf); + decoder.load(&mut self.inst_holder); + loop { + match decoder.decode()? { + Some(inst) => { + match inst { + DecoderInstruction::Ack { stream_id } => { + println!("stream_id: {}", stream_id); + assert_eq!(stream_id, self.stream_id); + loop {// ack an field section's all index + let ack_index = self.stream_reference.pop_front(); + if let Some(index) = ack_index { + if index == None { + break;// end of field section + } + if let Some(ind) = index { + if let Some(count) = self.table.ref_count.get(&ind){ + self.table.ref_count.insert(ind, count - 1); + } + } + } + else { + return Err(H3Error::ConnectionError(QPACK_DECODER_STREAM_ERROR)); + } + } + self.table.known_received_count += 1; + } + DecoderInstruction::StreamCancel { stream_id } => { + println!("stream_id: {}", stream_id); + assert_eq!(stream_id, self.stream_id); + return Ok(Some(DecoderInst::StreamCancel)); + } + DecoderInstruction::InsertCountIncrement { increment } => { + println!("increment: {}", increment); + self.table.known_received_count += increment; + } + } + } + None => return Ok(None), + } + } + } + + /// Users can call `encode` multiple times to encode multiple complete field sections. + pub(crate) fn encode(&mut self, encoder_buf: &mut [u8], stream_buf: &mut [u8]) -> (usize, usize) { + let mut encoder = ReprEncoder::new(&mut self.table); + encoder.load(&mut self.holder); + let (cur_encoder, cur_stream) = encoder.encode(&mut encoder_buf[0..], &mut stream_buf[0..], &mut self.stream_reference); + let mut cur_prefix = 0; + if self.is_finished() { + // denote an end of field section + self.stream_reference.push_back(None); + let wireRIC = self.table.insert_count % (2 * self.table.max_entries()) + 1; + let mut prefix_buf = [0u8; 1024]; + cur_prefix = Integer::index(0x00, wireRIC, 0xff).encode(&mut prefix_buf[..]).unwrap_or(0); + if self.table.known_received_count >= self.table.insert_count { + cur_prefix = Integer::index(0x00, self.table.known_received_count - self.table.insert_count, 0x7f).encode(&mut prefix_buf[cur_prefix..]).unwrap_or(0); + } else { + cur_prefix = Integer::index(0x80, self.table.insert_count - self.table.known_received_count - 1, 0x7f).encode(&mut prefix_buf[cur_prefix..]).unwrap_or(0); + } + // add prefix_buf[..cur_prefix] to the front of stream_buf + stream_buf.to_vec().splice(0..0, prefix_buf[..cur_prefix].to_vec()); + } + (cur_encoder, cur_stream + cur_prefix) + } + + /// Check the previously set `Parts` if encoding is complete. + pub(crate) fn is_finished(&self) -> bool { + self.holder.is_empty() + } +} + + +pub(crate) enum DecoderInst { + Ack, + StreamCancel, + InsertCountIncrement, +} + +pub(crate) enum EncoderInst { + SetCap(SetCap), +} + +impl EncoderInst { + pub(crate) fn encode(self, encoder_buf: &mut [u8]) -> usize { + let resut = match self { + Self::SetCap(s) => s.encode(encoder_buf), + // _ => panic!("not support"), + }; + match resut { + Ok(size) => size, + Err(e) => panic!("encode error"), + } + } +} + + +pub(crate) struct SetCap { + capacity: Integer, +} + +impl SetCap { + fn from(capacity: Integer) -> Self { + Self { capacity } + } + + fn new(capacity: usize) -> Self { + Self { capacity: Integer::index(0x20, capacity, PrefixMask::SETCAP.0) } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.capacity + .encode(dst) + .map_err(|e| EncoderInst::SetCap(SetCap::from(e))) + } +} + + +#[cfg(test)] +mod ut_qpack_encoder { + use crate::h3::parts::Parts; + use crate::h3::qpack::encoder::{QpackEncoder}; + use crate::h3::qpack::table::Field; + + #[test] + fn test() { + let mut encoder = QpackEncoder::with_capacity(4096, &mut [0u8; 1024], 0); + } +} \ No newline at end of file diff --git a/ylong_http/src/h3/qpack/format/decoder.rs b/ylong_http/src/h3/qpack/format/decoder.rs new file mode 100644 index 0000000..5f1cc48 --- /dev/null +++ b/ylong_http/src/h3/qpack/format/decoder.rs @@ -0,0 +1,719 @@ +use std::cmp::Ordering; +use crate::h3::error::{ErrorCode, H3Error}; +use crate::h3::error::ErrorCode::QPACK_DECOMPRESSION_FAILED; +use crate::h3::qpack::{MidBit, Representation, ReprPrefixBit, RequireInsertCount, DeltaBase, PrefixMask, EncoderInstruction, EncoderInstPrefixBit}; +use crate::h3::qpack::integer::IntegerDecoder; +use crate::h3::qpack::format::decoder::DecResult::Error; +use crate::huffman::HuffmanDecoder; + +pub(crate) struct EncInstDecoder<'a>{ + buf: &'a [u8], + state: Option, +} + +impl<'a> EncInstDecoder<'a> { + pub(crate) fn new(buf: &'a [u8]) -> Self { + Self { buf, state: None } + } + pub(crate) fn load(&mut self, holder: &mut InstDecStateHolder) { + self.state = holder.state.take(); + } + pub(crate) fn decode(&mut self) -> Result, H3Error> { + if self.buf.is_empty() { + return Ok(None); + } + + match self + .state + .take() + .unwrap_or_else(|| InstDecodeState::EncInstIndex(EncInstIndex::new())) + .decode(&mut self.buf) + { + // If `buf` is not enough to continue decoding a complete + // `Representation`, `Ok(None)` will be returned. Users need to call + // `save` to save the current state to a `ReprDecStateHolder`. + DecResult::NeedMore(state) => { + println!("NeedMore"); + self.state = Some(state); + Ok(None) + } + DecResult::Decoded(repr) => { + Ok(Some(repr)) + } + + DecResult::Error(error) => Err(error), + } + } +} + +pub(crate) struct ReprDecoder<'a> { + /// `buf` represents the byte stream to be decoded. + buf: &'a [u8], + /// `state` represents the remaining state after the last call to `decode`. + state: Option, +} + +impl<'a> ReprDecoder<'a> { + /// Creates a new `ReprDecoder` whose `state` is `None`. + pub(crate) fn new(buf: &'a [u8]) -> Self { + Self { buf, state: None } + } + + /// Loads state from a holder. + pub(crate) fn load(&mut self, holder: &mut ReprDecStateHolder) { + self.state = holder.state.take(); + } + + /// Decodes `self.buf`. Every time users call `decode`, it will try to + /// decode a `Representation`. + pub(crate) fn decode(&mut self) -> Result, H3Error> { + // If buf is empty, leave the state unchanged. + if self.buf.is_empty() { + return Ok(None); + } + + match self + .state + .take() + .unwrap_or_else(|| ReprDecodeState::FiledSectionPrefix(FiledSectionPrefix::new())) + .decode(&mut self.buf) + { + // If `buf` is not enough to continue decoding a complete + // `Representation`, `Ok(None)` will be returned. Users need to call + // `save` to save the current state to a `ReprDecStateHolder`. + DecResult::NeedMore(state) => { + println!("NeedMore"); + self.state = Some(state); + Ok(None) + } + DecResult::Decoded(repr) => { + self.state = Some(ReprDecodeState::ReprIndex(ReprIndex::new())); + Ok(Some(repr)) + } + + DecResult::Error(error) => Err(error), + } + } +} +pub(crate) struct InstDecStateHolder { + state: Option, +} + +impl InstDecStateHolder { + pub(crate) fn new() -> Self { + Self { state: None } + } + + pub(crate) fn is_empty(&self) -> bool { + self.state.is_none() + } +} +pub(crate) struct ReprDecStateHolder { + state: Option, +} + +impl ReprDecStateHolder { + pub(crate) fn new() -> Self { + Self { state: None } + } + + pub(crate) fn is_empty(&self) -> bool { + self.state.is_none() + } +} + + + +macro_rules! state_def { + ($name: ident, $decoded: ty, $($state: ident),* $(,)?) => { + pub(crate) enum $name { + $( + $state($state), + )* + } + + impl $name { + fn decode(self, buf: &mut &[u8]) -> DecResult<$decoded, $name> { + match self { + $( + Self::$state(state) => state.decode(buf), + )* + } + } + } + + $( + impl From<$state> for $name { + fn from(s: $state) -> Self { + Self::$state(s) + } + } + )* + } +} +state_def!( + InstDecodeState, + EncoderInstruction, + EncInstIndex, + InstValueString, + InstNameAndValue, +); + +state_def!( + ReprDecodeState, + Representation, + FiledSectionPrefix, + ReprIndex, + ReprValueString, + ReprNameAndValue, +); +state_def!(InstIndexInner, (EncoderInstPrefixBit, MidBit, usize), InstFirstByte, InstTrailingBytes); +state_def!(ReprIndexInner, (ReprPrefixBit, MidBit, usize), ReprFirstByte, ReprTrailingBytes); +state_def!(FSPInner, (RequireInsertCount, bool, DeltaBase), FSPTwoIntergers); +state_def!( + LiteralString, + Vec, + LengthFirstByte, + LengthTrailingBytes, + AsciiStringBytes, + HuffmanStringBytes, +); + +pub(crate) struct FiledSectionPrefix { + inner: FSPInner, +} + +impl FiledSectionPrefix { + fn new() -> Self { + Self::from_inner(FSPTwoIntergers.into()) + } + fn from_inner(inner: FSPInner) -> Self { + Self { inner } + } + + fn decode(self, buf: &mut &[u8]) -> DecResult { + match self.inner.decode(buf) { + DecResult::Decoded((ric, signal, delta_base)) => { + DecResult::Decoded(Representation::FieldSectionPrefix { + require_insert_count: ric, + signal: signal, + delta_base: delta_base, + }) + } + DecResult::NeedMore(inner) => DecResult::NeedMore(FiledSectionPrefix::from_inner(inner).into()), + DecResult::Error(e) => e.into(), + } + } +} + +pub(crate) struct EncInstIndex { + inner: InstIndexInner +} + +impl EncInstIndex { + fn new() -> Self { + Self::from_inner(InstFirstByte.into()) + } + fn from_inner(inner: InstIndexInner) -> Self { + Self { inner } + } + fn decode(self, buf: &mut &[u8]) -> DecResult { + match self.inner.decode(buf) { + DecResult::Decoded((EncoderInstPrefixBit::SETCAP, _, index)) => { + DecResult::Decoded(EncoderInstruction::SetCap { capacity:index }) + } + DecResult::Decoded((EncoderInstPrefixBit::INSERTWITHINDEX, mid_bit, index)) => { + InstValueString::new(EncoderInstPrefixBit::INSERTWITHINDEX, mid_bit, Name::Index(index)).decode(buf) + } + DecResult::Decoded((EncoderInstPrefixBit::INSERTWITHLITERAL, mid_bit, namelen)) => { + InstNameAndValue::new(EncoderInstPrefixBit::INSERTWITHLITERAL, mid_bit, namelen).decode(buf) + } + DecResult::Decoded((EncoderInstPrefixBit::DUPLICATE, _, index)) => { + DecResult::Decoded(EncoderInstruction::Duplicate { index }) + } + DecResult::NeedMore(inner) => DecResult::NeedMore(EncInstIndex::from_inner(inner).into()), + DecResult::Error(e) => e.into(), + _ => DecResult::Error(H3Error::ConnectionError(ErrorCode::QPACK_DECOMPRESSION_FAILED)), + } + } +} + +pub(crate) struct ReprIndex { + inner: ReprIndexInner, +} + +impl ReprIndex { + fn new() -> Self { + Self::from_inner(ReprFirstByte.into()) + } + fn from_inner(inner: ReprIndexInner) -> Self { + Self { inner } + } + fn decode(self, buf: &mut &[u8]) -> DecResult { + match self.inner.decode(buf) { + DecResult::Decoded((ReprPrefixBit::INDEXED, mid_bit, index)) => { + DecResult::Decoded(Representation::Indexed { mid_bit, index }) + } + DecResult::Decoded((ReprPrefixBit::INDEXEDWITHPOSTINDEX, _, index)) => { + DecResult::Decoded(Representation::IndexedWithPostIndex { index }) + } + DecResult::Decoded((ReprPrefixBit::LITERALWITHINDEXING, mid_bit, index)) => { + ReprValueString::new(ReprPrefixBit::LITERALWITHINDEXING, mid_bit, Name::Index(index)).decode(buf) + } + DecResult::Decoded((ReprPrefixBit::LITERALWITHPOSTINDEXING, mid_bit, index)) => { + ReprValueString::new(ReprPrefixBit::LITERALWITHPOSTINDEXING, mid_bit, Name::Index(index)).decode(buf) + } + DecResult::Decoded((ReprPrefixBit::LITERALWITHLITERALNAME, mid_bit, namelen)) => { + ReprNameAndValue::new(ReprPrefixBit::LITERALWITHLITERALNAME, mid_bit, namelen).decode(buf) + } + DecResult::NeedMore(inner) => DecResult::NeedMore(ReprIndex::from_inner(inner).into()), + DecResult::Error(e) => e.into(), + _ => DecResult::Error(H3Error::ConnectionError(ErrorCode::QPACK_DECOMPRESSION_FAILED )), + } + } +} + +pub(crate) struct FSPTwoIntergers; + +impl FSPTwoIntergers { + fn decode(self, buf: &mut &[u8]) -> DecResult<(RequireInsertCount, bool, DeltaBase), FSPInner> { + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + let byte = buf[0]; + let mask = PrefixMask::REQUIREINSERTCOUNT; + *buf = &buf[1..]; + let ric = match IntegerDecoder::first_byte(byte, mask.0) { + Ok(ric) => ric, + Err(mut int) => { + let mut res: usize; + loop { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + // Updates trailing bytes until we get the index. + match int.next_byte(byte) { + Ok(None) => {} + Ok(Some(index)) => { + res = index; + break; + } + Err(e) => return e.into(), + } + }; + res + } + }; + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + let byte = buf[0]; + let signal = (byte & 0x80) != 0; + let mask = PrefixMask::DELTABASE; + *buf = &buf[1..]; + let delta_base = match IntegerDecoder::first_byte(byte, mask.0) { + Ok(delta_base) => delta_base, + Err(mut int) => { + let mut res: usize; + loop { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + // Updates trailing bytes until we get the index. + match int.next_byte(byte) { + Ok(None) => {} + Ok(Some(index)) => { + res = index; + break; + } + Err(e) => return e.into(), + } + }; + res + } + }; + DecResult::Decoded((RequireInsertCount(ric), signal, DeltaBase(delta_base))) + } +} +pub(crate) struct InstFirstByte; + +impl InstFirstByte { + fn decode(self, buf: &mut &[u8]) -> DecResult<(EncoderInstPrefixBit, MidBit, usize), InstIndexInner> { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + let byte = buf[0]; + let inst = EncoderInstPrefixBit::from_u8(byte); + let mid_bit = inst.prefix_midbit_value(byte); + let mask = inst.prefix_index_mask(); + + // Moves the pointer of `buf` backward. + *buf = &buf[1..]; + match IntegerDecoder::first_byte(byte, mask.0) { + // Return the ReprPrefixBit and index part value. + Ok(idx) => DecResult::Decoded((inst, mid_bit, idx)), + // Index part value is longer than index(i.e. use all 1 to represent), so it needs more bytes to decode. + Err(int) => InstTrailingBytes::new(inst, mid_bit, int).decode(buf), + } + } +} + +pub(crate) struct ReprFirstByte; + +impl ReprFirstByte { + fn decode(self, buf: &mut &[u8]) -> DecResult<(ReprPrefixBit, MidBit, usize), ReprIndexInner> { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + let byte = buf[0]; + let repr = ReprPrefixBit::from_u8(byte); + let mid_bit = repr.prefix_midbit_value(byte); + let mask = repr.prefix_index_mask(); + + // Moves the pointer of `buf` backward. + *buf = &buf[1..]; + match IntegerDecoder::first_byte(byte, mask.0) { + // Return the ReprPrefixBit and index part value. + Ok(idx) => DecResult::Decoded((repr, mid_bit, idx)), + // Index part value is longer than index(i.e. use all 1 to represent), so it needs more bytes to decode. + Err(int) => ReprTrailingBytes::new(repr, mid_bit, int).decode(buf), + } + } +} +pub(crate) struct InstTrailingBytes { + inst: EncoderInstPrefixBit, + mid_bit: MidBit, + index: IntegerDecoder, +} + +impl InstTrailingBytes { + fn new(inst: EncoderInstPrefixBit, mid_bit: MidBit, index: IntegerDecoder) -> Self { + Self { inst, mid_bit, index } + } + fn decode(mut self, buf: &mut &[u8]) -> DecResult<(EncoderInstPrefixBit, MidBit, usize), InstIndexInner> { + loop { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + // Updates trailing bytes until we get the index. + match self.index.next_byte(byte) { + Ok(None) => {} + Ok(Some(index)) => return DecResult::Decoded((self.inst, self.mid_bit, index)), + Err(e) => return e.into(), + } + } + } +} +pub(crate) struct ReprTrailingBytes { + repr: ReprPrefixBit, + mid_bit: MidBit, + index: IntegerDecoder, +} + +impl ReprTrailingBytes { + fn new(repr: ReprPrefixBit, mid_bit: MidBit, index: IntegerDecoder) -> Self { + Self { repr, mid_bit, index } + } + fn decode(mut self, buf: &mut &[u8]) -> DecResult<(ReprPrefixBit, MidBit, usize), ReprIndexInner> { + loop { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + // Updates trailing bytes until we get the index. + match self.index.next_byte(byte) { + Ok(None) => {} + Ok(Some(index)) => return DecResult::Decoded((self.repr, self.mid_bit, index)), + Err(e) => return e.into(), + } + } + } +} + +pub(crate) struct LengthTrailingBytes { + is_huffman: bool, + length: IntegerDecoder, +} + +impl LengthTrailingBytes { + fn new(is_huffman: bool, length: IntegerDecoder) -> Self { + Self { is_huffman, length } + } + + fn decode(mut self, buf: &mut &[u8]) -> DecResult, LiteralString> { + loop { + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + match (self.length.next_byte(byte), self.is_huffman) { + (Ok(None), _) => {} + (Err(e), _) => return e.into(), + (Ok(Some(length)), true) => return HuffmanStringBytes::new(length).decode(buf), + (Ok(Some(length)), false) => return AsciiStringBytes::new(length).decode(buf), + } + } + } +} + +pub(crate) struct AsciiStringBytes { + octets: Vec, + length: usize, +} + +impl AsciiStringBytes { + fn new(length: usize) -> Self { + Self { + octets: Vec::new(), + length, + } + } + + fn decode(mut self, buf: &mut &[u8]) -> DecResult, LiteralString> { + match (buf.len() + self.octets.len()).cmp(&self.length) { + Ordering::Greater | Ordering::Equal => { + let pos = self.length - self.octets.len(); + self.octets.extend_from_slice(&buf[..pos]); + *buf = &buf[pos..]; + DecResult::Decoded(self.octets) + } + Ordering::Less => { + self.octets.extend_from_slice(buf); + *buf = &buf[buf.len()..]; + DecResult::NeedMore(self.into()) + } + } + } +} +pub(crate) struct InstNameAndValue { + inst: EncoderInstPrefixBit, + mid_bit: MidBit, + inner: LiteralString, +} + +impl InstNameAndValue { + fn new(inst: EncoderInstPrefixBit, mid_bit: MidBit, namelen: usize) -> Self { + Self::from_inner(inst, mid_bit, AsciiStringBytes::new(namelen).into()) + } + fn from_inner(inst: EncoderInstPrefixBit, mid_bit: MidBit, inner: LiteralString) -> Self { + Self { inst, mid_bit, inner } + } + fn decode(self, buf: &mut &[u8]) -> DecResult { + match self.inner.decode(buf) { + DecResult::Decoded(octets) => { + InstValueString::new(self.inst, self.mid_bit, Name::Literal(octets)).decode(buf) + } + DecResult::NeedMore(inner) => { + DecResult::NeedMore(Self::from_inner(self.inst, self.mid_bit, inner).into()) + } + DecResult::Error(e) => e.into(), + } + } +} +pub(crate) struct ReprNameAndValue { + repr: ReprPrefixBit, + mid_bit: MidBit, + inner: LiteralString, +} + +impl ReprNameAndValue { + fn new(repr: ReprPrefixBit, mid_bit: MidBit, namelen: usize) -> Self { + Self::from_inner(repr, mid_bit, AsciiStringBytes::new(namelen).into()) + } + fn from_inner(repr: ReprPrefixBit, mid_bit: MidBit, inner: LiteralString) -> Self { + Self { repr, mid_bit, inner } + } + fn decode(self, buf: &mut &[u8]) -> DecResult { + match self.inner.decode(buf) { + DecResult::Decoded(octets) => { + ReprValueString::new(self.repr, self.mid_bit, Name::Literal(octets)).decode(buf) + } + DecResult::NeedMore(inner) => { + DecResult::NeedMore(Self::from_inner(self.repr, self.mid_bit, inner).into()) + } + DecResult::Error(e) => e.into(), + } + } +} + +pub(crate) struct LengthFirstByte; + +impl LengthFirstByte { + fn decode(self, buf: &mut &[u8]) -> DecResult, LiteralString> { + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + match (IntegerDecoder::first_byte(byte, 0x7f), (byte & 0x80) == 0x80) { + (Ok(len), true) => HuffmanStringBytes::new(len).decode(buf), + (Ok(len), false) => AsciiStringBytes::new(len).decode(buf), + (Err(int), huffman) => LengthTrailingBytes::new(huffman, int).decode(buf), + } + } +} + +pub(crate) struct HuffmanStringBytes { + huffman: HuffmanDecoder, + read: usize, + length: usize, +} + +impl HuffmanStringBytes { + fn new(length: usize) -> Self { + Self { + huffman: HuffmanDecoder::new(), + read: 0, + length, + } + } + + fn decode(mut self, buf: &mut &[u8]) -> DecResult, LiteralString> { + match (buf.len() + self.read).cmp(&self.length) { + Ordering::Greater | Ordering::Equal => { + let pos = self.length - self.read; + if self.huffman.decode(&buf[..pos]).is_err() { + return H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); + } + *buf = &buf[pos..]; + match self.huffman.finish() { + Ok(vec) => DecResult::Decoded(vec), + Err(_) => H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(), + } + } + Ordering::Less => { + if self.huffman.decode(buf).is_err() { + return H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); + } + self.read += buf.len(); + *buf = &buf[buf.len()..]; + DecResult::NeedMore(self.into()) + } + } + } +} +#[derive(Clone)] +pub(crate) enum Name { + Index(usize), + Literal(Vec), +} +pub(crate) struct InstValueString { + inst: EncoderInstPrefixBit, + mid_bit: MidBit, + name: Name, + inner: LiteralString, +} + +impl InstValueString { + fn new(inst: EncoderInstPrefixBit, mid_bit: MidBit, name: Name) -> Self { + Self::from_inner(inst, mid_bit, name, LengthFirstByte.into()) + } + + fn from_inner(inst: EncoderInstPrefixBit, mid_bit: MidBit, name: Name, inner: LiteralString) -> Self { + Self { inst, mid_bit, name, inner } + } + + fn decode(self, buf: &mut &[u8]) -> DecResult { + match (self.inst, self.inner.decode(buf)) { + (EncoderInstPrefixBit::INSERTWITHINDEX, DecResult::Decoded(value)) => { + DecResult::Decoded(EncoderInstruction::InsertWithIndex { + mid_bit: self.mid_bit, + name: self.name, + value, + }) + } + (EncoderInstPrefixBit::INSERTWITHLITERAL, DecResult::Decoded(value)) => { + DecResult::Decoded(EncoderInstruction::InsertWithLiteral { + mid_bit: self.mid_bit, + name: self.name, + value, + }) + } + (_, _) => Error(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED)) + } + } +} +pub(crate) struct ReprValueString { + repr: ReprPrefixBit, + mid_bit: MidBit, + name: Name, + inner: LiteralString, +} + +impl ReprValueString { + fn new(repr: ReprPrefixBit, mid_bit: MidBit, name: Name) -> Self { + Self::from_inner(repr, mid_bit, name, LengthFirstByte.into()) + } + + fn from_inner(repr: ReprPrefixBit, mid_bit: MidBit, name: Name, inner: LiteralString) -> Self { + Self { repr, mid_bit, name, inner } + } + + fn decode(self, buf: &mut &[u8]) -> DecResult { + match (self.repr, self.inner.decode(buf)) { + (ReprPrefixBit::LITERALWITHINDEXING, DecResult::Decoded(value)) => { + DecResult::Decoded(Representation::LiteralWithIndexing { + mid_bit: self.mid_bit, + name: self.name, + value, + }) + } + (ReprPrefixBit::LITERALWITHPOSTINDEXING, DecResult::Decoded(value)) => { + DecResult::Decoded(Representation::LiteralWithPostIndexing { + mid_bit: self.mid_bit, + name: self.name, + value, + }) + } + (ReprPrefixBit::LITERALWITHLITERALNAME, DecResult::Decoded(value)) => { + DecResult::Decoded(Representation::LiteralWithLiteralName { + mid_bit: self.mid_bit, + name: self.name, + value, + }) + } + (_, _) => Error(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED)) + } + } +} + + +/// Decoder's possible returns during the decoding process. +pub(crate) enum DecResult { + /// Decoder has got a `D`. Users can continue to call `encode` to try to + /// get the next `D`. + Decoded(D), + + /// Decoder needs more bytes to decode to get a `D`. Returns the current + /// decoding state `S`. + NeedMore(S), + + /// Errors that may occur when decoding. + Error(H3Error), +} + +impl From for DecResult { + fn from(e: H3Error) -> Self { + DecResult::Error(e) + } +} \ No newline at end of file diff --git a/ylong_http/src/h3/qpack/format/encoder.rs b/ylong_http/src/h3/qpack/format/encoder.rs new file mode 100644 index 0000000..6f9ee60 --- /dev/null +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -0,0 +1,836 @@ +use std::arch::asm; +use std::cmp::{max, Ordering}; +use std::collections::{HashMap, VecDeque}; +use std::result; +use crate::h3::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; +use crate::h3::error::H3Error; +use crate::h3::parts::Parts; +use crate::h3::pseudo::PseudoHeaders; +use crate::h3::qpack::integer::{Integer, IntegerDecoder, IntegerEncoder}; +use crate::h3::qpack::{DecoderInstPrefixBit, DecoderInstruction, EncoderInstruction, PrefixMask}; +use crate::h3::qpack::format::decoder::DecResult; +use crate::h3::qpack::table::{DynamicTable, Field, TableIndex, TableSearcher}; +use crate::headers::HeadersIntoIter; + +pub(crate) struct ReprEncoder<'a> { + table: &'a mut DynamicTable, + iter: Option, + state: Option, +} + + +impl<'a> ReprEncoder<'a> { + /// Creates a new, empty `ReprEncoder`. + pub(crate) fn new(table: &'a mut DynamicTable) -> Self { + Self { + table, + iter: None, + state: None, + + } + } + + /// Loads states from a holder. + pub(crate) fn load(&mut self, holder: &mut ReprEncStateHolder) { + self.iter = holder.iter.take(); + self.state = holder.state.take(); + } + + /// Saves current state to a holder. + pub(crate) fn save(self, holder: &mut ReprEncStateHolder) { + holder.iter = self.iter; + holder.state = self.state; + } + + /// Decodes the contents of `self.iter` and `self.state`. The result will be + /// written to `dst` and the length of the decoded content will be returned. + pub(crate) fn encode(&mut self, encoder_buffer: &mut [u8], stream_buffer: &mut [u8], stream_reference: &mut VecDeque>) -> (usize, usize) { + let mut cur_encoder = 0; + let mut cur_stream = 0; + if let Some(mut iter) = self.iter.take() { + while let Some((h, v)) = iter.next() { + let searcher = TableSearcher::new(self.table); + println!("h: {:?}, v: {:?}", h, v); + let mut stream_result: Result = Result::Err(ReprEncodeState::Indexed(Indexed::new(0, false))); + let mut encoder_result: Result = Result::Err(ReprEncodeState::Indexed(Indexed::new(0, false))); + let static_index = searcher.find_index_static(&h, &v); + if static_index != Some(TableIndex::None) { + if let Some(TableIndex::Field(index)) = static_index { + // Encode as index in static table + stream_result = Indexed::new(index, true).encode(&mut stream_buffer[cur_stream..]); + } + } else { + let dynamic_index = searcher.find_index_dynamic(&h, &v); + let static_name_index = searcher.find_index_name_static(&h, &v); + let mut dynamic_name_index = Some(TableIndex::None); + if dynamic_index == Some(TableIndex::None) { + if static_name_index == Some(TableIndex::None) { + dynamic_name_index = searcher.find_index_name_dynamic(&h, &v); + } + + if self.should_index(&h, &v) && self.table.have_enough_space(&h, &v) { + encoder_result = match (&static_name_index, &dynamic_name_index) { + // insert with name reference in static table + (Some(TableIndex::FieldName(index)), _) => { + InsertWithName::new(index.clone(), v.clone().into_bytes(), false, true).encode(&mut encoder_buffer[cur_encoder..]) + } + // insert with name reference in dynamic table + (_, Some(TableIndex::FieldName(index))) => { + // convert abs index to rel index + InsertWithName::new(self.table.insert_count - index.clone() - 1, v.clone().into_bytes(), false, false).encode(&mut encoder_buffer[cur_encoder..]) + } + // insert with literal name + (_, _) => { + InsertWithLiteral::new(h.clone().into_string().into_bytes(), v.clone().into_bytes(), false).encode(&mut encoder_buffer[cur_encoder..]) + } + }; + // update dynamic table + self.table.insert_count += 1; + self.table.update(h.clone(), v.clone()); + } + } + if dynamic_index == Some(TableIndex::None) { + if dynamic_name_index != Some(TableIndex::None) { + //Encode with name reference in dynamic table + if let Some(TableIndex::FieldName(index)) = dynamic_name_index { + stream_reference.push_back(Some(index)); + if let Some(count) = self.table.ref_count.get(&index) { + self.table.ref_count.insert(index, count + 1); + } + // use post-base index + if self.table.known_received_count <= index { + stream_result = IndexingWithPostName::new(index - self.table.known_received_count, v.clone().into_bytes(), false, false).encode(&mut stream_buffer[cur_stream..]); + } else { + stream_result = IndexingWithName::new(self.table.known_received_count - index - 1, v.clone().into_bytes(), false, false, false).encode(&mut stream_buffer[cur_stream..]); + } + } + + } else { + // Encode with name reference in static table + // or Encode as Literal + if static_name_index != Some(TableIndex::None) { + if let Some(TableIndex::FieldName(index)) = static_name_index { + stream_result = IndexingWithName::new(index, v.into_bytes(), false, true, false).encode(&mut stream_buffer[cur_stream..]); + } + } else { + stream_result = IndexingWithLiteral::new(h.into_string().into_bytes(), v.into_bytes(), false, false).encode(&mut stream_buffer[cur_stream..]); + } + } + } else { + assert!(dynamic_index != Some(TableIndex::None)); + // Encode with index in dynamic table + if let Some(TableIndex::FieldName(index)) = dynamic_name_index { + // use post-base index + stream_reference.push_back(Some(index)); + if let Some(count) = self.table.ref_count.get(&index) { + self.table.ref_count.insert(index, count + 1); + } + if self.table.known_received_count <= index{ + stream_result = IndexedWithPostName::new(index - self.table.known_received_count).encode(&mut stream_buffer[cur_stream..]); + } + else { + stream_result = Indexed::new(self.table.known_received_count - index - 1, false).encode(&mut stream_buffer[cur_stream..]); + } + } + } + } + + match (encoder_result, stream_result) { + (Ok(encoder_size), Ok(stream_size)) => { + cur_stream += stream_size; + cur_encoder += encoder_size; + } + (Err(state), Ok(stream_size)) => { + cur_stream += stream_size; + self.state = Some(state); + self.iter = Some(iter); + return (encoder_buffer.len(), stream_buffer.len()); + } + (Ok(encoder_size), Err(state)) => { + cur_encoder += encoder_size; + self.state = Some(state); + self.iter = Some(iter); + return (encoder_buffer.len(), stream_buffer.len()); + } + (Err(_), Err(state)) => { + self.state = Some(state); + self.iter = Some(iter); + return (encoder_buffer.len(), stream_buffer.len()); + } + } + } + } + (cur_encoder, cur_stream) + } + /// ## 2.1.1.1. Avoiding Prohibited Insertions + /// To ensure that the encoder is not prevented from adding new entries, the encoder can + /// avoid referencing entries that are close to eviction. Rather than reference such an + /// entry, the encoder can emit a Duplicate instruction (Section 4.3.4) and reference + /// the duplicate instead. + /// + /// Determining which entries are too close to eviction to reference is an encoder preference. + /// One heuristic is to target a fixed amount of available space in the dynamic table: + /// either unused space or space that can be reclaimed by evicting non-blocking entries. + /// To achieve this, the encoder can maintain a draining index, which is the smallest + /// absolute index (Section 3.2.4) in the dynamic table that it will emit a reference for. + /// As new entries are inserted, the encoder increases the draining index to maintain the + /// section of the table that it will not reference. If the encoder does not create new + /// references to entries with an absolute index lower than the draining index, the number + /// of unacknowledged references to those entries will eventually become zero, allowing + /// them to be evicted. + /// + /// <-- Newer Entries Older Entries --> + /// (Larger Indices) (Smaller Indices) + /// +--------+---------------------------------+----------+ + /// | Unused | Referenceable | Draining | + /// | Space | Entries | Entries | + /// +--------+---------------------------------+----------+ + /// ^ ^ ^ + /// | | | + /// Insertion Point Draining Index Dropping + /// Point + pub(crate) fn should_index(&self, header: &Field, value: &str) -> bool { + //todo: add condition to modify the algorithm + true + } +} + + + +pub(crate) struct ReprEncStateHolder { + iter: Option, + state: Option, +} + +impl ReprEncStateHolder { + /// Creates a new, empty `ReprEncStateHolder`. + pub(crate) fn new() -> Self { + Self { + iter: None, + state: None, + } + } + + /// Creates a state based on the `Parts` to be encoded. + pub(crate) fn set_parts(&mut self, parts: Parts) { + self.iter = Some(PartsIter::new(parts)) + } + + /// Determines whether `self.iter` and `self.state` are empty. if they are + /// empty, it means encoding is finished. + pub(crate) fn is_empty(&self) -> bool { + self.iter.is_none() && self.state.is_none() + } +} + +pub(crate) enum ReprEncodeState { + Indexed(Indexed), + InsertWithName(InsertWithName), + InsertWithLiteral(InsertWithLiteral), + IndexingWithName(IndexingWithName), + IndexingWithPostName(IndexingWithPostName), + IndexingWithLiteral(IndexingWithLiteral), + IndexedWithPostName(IndexedWithPostName), +} + + +pub(crate) struct Indexed { + index: Integer, +} + +impl Indexed { + fn from(index: Integer) -> Self { + Self { index } + } + + fn new(index: usize, is_static: bool) -> Self { + if is_static { + // in static table + Self { index: Integer::index(0xc0, index, PrefixMask::INDEXED.0) } + } else { + // in dynamic table + Self { index: Integer::index(0x80, index, PrefixMask::INDEXED.0) } + } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.index + .encode(dst) + .map_err(|e| ReprEncodeState::Indexed(Indexed::from(e))) + } +} + +pub(crate) struct IndexedWithPostName { + index: Integer, +} + +impl IndexedWithPostName { + fn from(index: Integer) -> Self { + Self { index } + } + + fn new(index: usize) -> Self { + Self { index: Integer::index(0x10, index, PrefixMask::INDEXINGWITHPOSTNAME.0) } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.index + .encode(dst) + .map_err(|e| ReprEncodeState::IndexedWithPostName(IndexedWithPostName::from(e))) + } +} + + +pub(crate) struct InsertWithName { + inner: IndexAndValue, +} + +impl InsertWithName { + fn from(inner: IndexAndValue) -> Self { + Self { inner } + } + + fn new(index: usize, value: Vec, is_huffman: bool, is_static: bool) -> Self { + if is_static { + Self { + inner: IndexAndValue::new() + .set_index(0xc0, index, PrefixMask::INSERTWITHINDEX.0) + .set_value(value, is_huffman), + } + } else { + Self { + inner: IndexAndValue::new() + .set_index(0x80, index, PrefixMask::INSERTWITHINDEX.0) + .set_value(value, is_huffman), + } + } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.inner + .encode(dst) + .map_err(|e| ReprEncodeState::InsertWithName(InsertWithName::from(e))) + } +} + + +pub(crate) struct IndexingWithName { + inner: IndexAndValue, +} + +impl IndexingWithName { + fn from(inner: IndexAndValue) -> Self { + Self { inner } + } + + fn new(index: usize, value: Vec, is_huffman: bool, is_static: bool, no_permit: bool) -> Self { + match (no_permit, is_static) { + (true, true) => { + Self { + inner: IndexAndValue::new() + .set_index(0x70, index, PrefixMask::INDEXINGWITHNAME.0) + .set_value(value, is_huffman), + } + } + (true, false) => { + Self { + inner: IndexAndValue::new() + .set_index(0x60, index, PrefixMask::INDEXINGWITHNAME.0) + .set_value(value, is_huffman), + } + } + (false, true) => { + Self { + inner: IndexAndValue::new() + .set_index(0x50, index, PrefixMask::INDEXINGWITHNAME.0) + .set_value(value, is_huffman), + } + } + (false, false) => { + Self { + inner: IndexAndValue::new() + .set_index(0x40, index, PrefixMask::INDEXINGWITHNAME.0) + .set_value(value, is_huffman), + } + } + } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.inner + .encode(dst) + .map_err(|e| ReprEncodeState::IndexingWithName(IndexingWithName::from(e))) + } +} + + +pub(crate) struct IndexingWithPostName { + inner: IndexAndValue, +} + +impl IndexingWithPostName { + fn from(inner: IndexAndValue) -> Self { + Self { inner } + } + + fn new(index: usize, value: Vec, is_huffman: bool, no_permit: bool) -> Self { + if no_permit { + Self { + inner: IndexAndValue::new() + .set_index(0x08, index, PrefixMask::INDEXINGWITHPOSTNAME.0) + .set_value(value, is_huffman), + } + } else { + Self { + inner: IndexAndValue::new() + .set_index(0x00, index, PrefixMask::INDEXINGWITHPOSTNAME.0) + .set_value(value, is_huffman), + } + } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.inner + .encode(dst) + .map_err(|e| ReprEncodeState::IndexingWithPostName(IndexingWithPostName::from(e))) + } +} + + +pub(crate) struct IndexingWithLiteral { + inner: NameAndValue, +} + +impl IndexingWithLiteral { + fn new(name: Vec, value: Vec, is_huffman: bool, no_permit: bool) -> Self { + match (no_permit, is_huffman) { + (true, true) => { + Self { + inner: NameAndValue::new() + .set_index(0x38, name.len(), PrefixMask::INDEXINGWITHLITERAL.0) + .set_name_and_value(name, value, is_huffman), + } + } + (true, false) => { + Self { + inner: NameAndValue::new() + .set_index(0x30, name.len(), PrefixMask::INDEXINGWITHLITERAL.0) + .set_name_and_value(name, value, is_huffman), + } + } + (false, true) => { + Self { + inner: NameAndValue::new() + .set_index(0x28, name.len(), PrefixMask::INDEXINGWITHLITERAL.0) + .set_name_and_value(name, value, is_huffman), + } + } + (false, false) => { + Self { + inner: NameAndValue::new() + .set_index(0x20, name.len(), PrefixMask::INDEXINGWITHLITERAL.0) + .set_name_and_value(name, value, is_huffman), + } + } + } + } + + fn from(inner: NameAndValue) -> Self { + Self { inner } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.inner + .encode(dst) + .map_err(|e| ReprEncodeState::InsertWithLiteral(InsertWithLiteral::from(e))) + } +} + + +pub(crate) struct InsertWithLiteral { + inner: NameAndValue, +} + +impl InsertWithLiteral { + fn new(name: Vec, value: Vec, is_huffman: bool) -> Self { + if is_huffman { + Self { + inner: NameAndValue::new() + .set_index(0x60, name.len(), PrefixMask::INSERTWITHLITERAL.0) + .set_name_and_value(name, value, is_huffman), + } + } else { + Self { + inner: NameAndValue::new() + .set_index(0x40, name.len(), PrefixMask::INSERTWITHLITERAL.0) + .set_name_and_value(name, value, is_huffman), + } + } + } + + fn from(inner: NameAndValue) -> Self { + Self { inner } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.inner + .encode(dst) + .map_err(|e| ReprEncodeState::InsertWithLiteral(InsertWithLiteral::from(e))) + } +} + + +pub(crate) struct IndexAndValue { + index: Option, + value_length: Option, + value_octets: Option, +} +macro_rules! check_and_encode { + ($item: expr, $dst: expr, $cur: expr, $self: expr) => {{ + if let Some(i) = $item.take() { + match i.encode($dst) { + Ok(len) => $cur += len, + Err(e) => { + $item = Some(e); + return Err($self); + } + }; + } + }}; +} +impl IndexAndValue { + fn new() -> Self { + Self { + index: None, + value_length: None, + value_octets: None, + } + } + + fn set_index(mut self, pre: u8, index: usize, mask: u8) -> Self { + self.index = Some(Integer::index(pre, index, mask)); + self + } + + fn set_value(mut self, value: Vec, is_huffman: bool) -> Self { + self.value_length = Some(Integer::length(value.len(), is_huffman)); + self.value_octets = Some(Octets::new(value)); + self + } + + fn encode(mut self, dst: &mut [u8]) -> Result { + let mut cur = 0; + check_and_encode!(self.index, &mut dst[cur..], cur, self); + check_and_encode!(self.value_length, &mut dst[cur..], cur, self); + check_and_encode!(self.value_octets, &mut dst[cur..], cur, self); + Ok(cur) + } +} + + +pub(crate) struct NameAndValue { + index: Option, + name_length: Option, + name_octets: Option, + value_length: Option, + value_octets: Option, +} + +impl NameAndValue { + fn new() -> Self { + Self { + index: None, + name_length: None, + name_octets: None, + value_length: None, + value_octets: None, + } + } + + fn set_index(mut self, pre: u8, index: usize, mask: u8) -> Self { + self.index = Some(Integer::index(pre, index, mask)); + self + } + + fn set_name_and_value(mut self, name: Vec, value: Vec, is_huffman: bool) -> Self { + self.name_length = Some(Integer::length(name.len(), is_huffman)); + self.name_octets = Some(Octets::new(name)); + self.value_length = Some(Integer::length(value.len(), is_huffman)); + self.value_octets = Some(Octets::new(value)); + self + } + + fn encode(mut self, dst: &mut [u8]) -> Result { + let mut cur = 0; + check_and_encode!(self.index, &mut dst[cur..], cur, self); + // check_and_encode!(self.name_length, &mut dst[cur..], cur, self); //no need for qpack cause it in index. + check_and_encode!(self.name_octets, &mut dst[cur..], cur, self); + check_and_encode!(self.value_length, &mut dst[cur..], cur, self); + check_and_encode!(self.value_octets, &mut dst[cur..], cur, self); + Ok(cur) + } +} + + + +macro_rules! state_def { + ($name: ident, $decoded: ty, $($state: ident),* $(,)?) => { + pub(crate) enum $name { + $( + $state($state), + )* + } + + impl $name { + fn decode(self, buf: &mut &[u8]) -> DecResult<$decoded, $name> { + match self { + $( + Self::$state(state) => state.decode(buf), + )* + } + } + } + + $( + impl From<$state> for $name { + fn from(s: $state) -> Self { + Self::$state(s) + } + } + )* + } +} + +state_def!( + InstDecodeState, + DecoderInstruction, + DecInstIndex +); +pub(crate) struct DecInstDecoder<'a>{ + buf: &'a [u8], + state: Option, +} +pub(crate) struct InstDecStateHolder { + state: Option, +} + +impl InstDecStateHolder { + pub(crate) fn new() -> Self { + Self { state: None } + } + + pub(crate) fn is_empty(&self) -> bool { + self.state.is_none() + } +} +impl<'a> DecInstDecoder<'a> { + pub(crate) fn new(buf: &'a [u8]) -> Self { + Self { buf, state: None } + } + pub(crate) fn load(&mut self, holder: &mut InstDecStateHolder) { + self.state = holder.state.take(); + } + pub(crate) fn decode(&mut self) -> Result, H3Error> { + if self.buf.is_empty() { + return Ok(None); + } + + match self + .state + .take() + .unwrap_or_else(|| InstDecodeState::DecInstIndex(DecInstIndex::new())) + .decode(&mut self.buf) + { + // If `buf` is not enough to continue decoding a complete + // `Representation`, `Ok(None)` will be returned. Users need to call + // `save` to save the current state to a `ReprDecStateHolder`. + DecResult::NeedMore(state) => { + println!("NeedMore"); + self.state = Some(state); + Ok(None) + } + DecResult::Decoded(repr) => { + Ok(Some(repr)) + } + + DecResult::Error(error) => Err(error), + } + } +} +state_def!(DecInstIndexInner, (DecoderInstPrefixBit, usize), InstFirstByte, InstTrailingBytes); + +pub(crate) struct DecInstIndex { + inner: DecInstIndexInner +} +impl DecInstIndex { + fn new() -> Self { + Self::from_inner(InstFirstByte.into()) + } + fn from_inner(inner: DecInstIndexInner) -> Self { + Self { inner } + } + fn decode(self, buf: &mut &[u8]) -> DecResult { + match self.inner.decode(buf) { + DecResult::Decoded((DecoderInstPrefixBit::ACK, index)) => { + DecResult::Decoded(DecoderInstruction::Ack { stream_id:index }) + } + DecResult::Decoded((DecoderInstPrefixBit::STREAMCANCEL, index)) => { + DecResult::Decoded(DecoderInstruction::StreamCancel { stream_id:index }) + } + DecResult::Decoded((DecoderInstPrefixBit::INSERTCOUNTINCREMENT, index)) => { + DecResult::Decoded(DecoderInstruction::InsertCountIncrement { increment: index }) + } + DecResult::Error(e) => e.into(), + _ => DecResult::Error(H3Error::ConnectionError(QPACK_DECODER_STREAM_ERROR)), + } + } +} + +pub(crate) struct InstFirstByte; + +impl InstFirstByte { + fn decode(self, buf: &mut &[u8]) -> DecResult<(DecoderInstPrefixBit, usize), DecInstIndexInner> { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + let byte = buf[0]; + let inst = DecoderInstPrefixBit::from_u8(byte); + let mask = inst.prefix_index_mask(); + + // Moves the pointer of `buf` backward. + *buf = &buf[1..]; + match IntegerDecoder::first_byte(byte, mask.0) { + // Return the ReprPrefixBit and index part value. + Ok(idx) => DecResult::Decoded((inst, idx)), + // Index part value is longer than index(i.e. use all 1 to represent), so it needs more bytes to decode. + Err(int) => InstTrailingBytes::new(inst, int).decode(buf), + } + } +} + +pub(crate) struct InstTrailingBytes { + inst: DecoderInstPrefixBit, + index: IntegerDecoder, +} + +impl InstTrailingBytes { + fn new(inst: DecoderInstPrefixBit, index: IntegerDecoder) -> Self { + Self { inst, index } + } + fn decode(mut self, buf: &mut &[u8]) -> DecResult<(DecoderInstPrefixBit, usize), DecInstIndexInner> { + loop { + // If `buf` has been completely decoded here, return the current state. + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let byte = buf[0]; + *buf = &buf[1..]; + // Updates trailing bytes until we get the index. + match self.index.next_byte(byte) { + Ok(None) => {} + Ok(Some(index)) => return DecResult::Decoded((self.inst, index)), + Err(e) => return e.into(), + } + } + } +} + +pub(crate) struct Octets { + src: Vec, + idx: usize, +} + +impl Octets { + fn new(src: Vec) -> Self { + Self { src, idx: 0 } + } + + fn encode(mut self, dst: &mut [u8]) -> Result { + let mut cur = 0; + + let input_len = self.src.len() - self.idx; + let output_len = dst.len(); + + if input_len == 0 { + return Ok(cur); + } + + match output_len.cmp(&input_len) { + Ordering::Greater | Ordering::Equal => { + dst[..input_len].copy_from_slice(&self.src[self.idx..]); + cur += input_len; + Ok(cur) + } + Ordering::Less => { + dst[..].copy_from_slice(&self.src[self.idx..self.idx + output_len]); + self.idx += output_len; + Err(self) + } + } + } +} + +struct PartsIter { + pseudo: PseudoHeaders, + map: HeadersIntoIter, + next_type: PartsIterDirection, +} + +/// `PartsIterDirection` is the `PartsIter`'s direction to get the next header. +enum PartsIterDirection { + Authority, + Method, + Path, + Scheme, + Status, + Other, +} + +impl PartsIter { + /// Creates a new `PartsIter` from the given `Parts`. + fn new(parts: Parts) -> Self { + Self { + pseudo: parts.pseudo, + map: parts.map.into_iter(), + next_type: PartsIterDirection::Method, + } + } + + /// Gets headers in the order of `Method`, `Status`, `Scheme`, `Path`, + /// `Authority` and `Other`. + fn next(&mut self) -> Option<(Field, String)> { + loop { + match self.next_type { + PartsIterDirection::Method => match self.pseudo.take_method() { + Some(value) => return Some((Field::Method, value)), + None => self.next_type = PartsIterDirection::Status, + }, + PartsIterDirection::Status => match self.pseudo.take_status() { + Some(value) => return Some((Field::Status, value)), + None => self.next_type = PartsIterDirection::Scheme, + }, + PartsIterDirection::Scheme => match self.pseudo.take_scheme() { + Some(value) => return Some((Field::Scheme, value)), + None => self.next_type = PartsIterDirection::Path, + }, + PartsIterDirection::Path => match self.pseudo.take_path() { + Some(value) => return Some((Field::Path, value)), + None => self.next_type = PartsIterDirection::Authority, + }, + PartsIterDirection::Authority => match self.pseudo.take_authority() { + Some(value) => return Some((Field::Authority, value)), + None => self.next_type = PartsIterDirection::Other, + }, + PartsIterDirection::Other => { + return self + .map + .next() + .map(|(h, v)| (Field::Other(h.to_string()), v.to_str().unwrap())); + } + } + } + } +} + diff --git a/ylong_http/src/h3/qpack/format/mod.rs b/ylong_http/src/h3/qpack/format/mod.rs new file mode 100644 index 0000000..f7ae841 --- /dev/null +++ b/ylong_http/src/h3/qpack/format/mod.rs @@ -0,0 +1,7 @@ +pub(crate) mod encoder; +pub(crate) mod decoder; + +pub(crate) use encoder::{ReprEncoder,ReprEncStateHolder}; + + + diff --git a/ylong_http/src/h3/qpack/integer.rs b/ylong_http/src/h3/qpack/integer.rs new file mode 100644 index 0000000..9551bb1 --- /dev/null +++ b/ylong_http/src/h3/qpack/integer.rs @@ -0,0 +1,132 @@ +use std::cmp::Ordering; +use crate::h3::error::{ErrorCode, H3Error}; + +pub(crate) struct Integer { + pub(crate) int: IntegerEncoder, +} + +impl Integer { + pub(crate) fn index(pre: u8, index: usize, mask: u8) -> Self { + Self { + int: IntegerEncoder::new(pre, index, mask), + } + } + pub(crate) fn length(length: usize, is_huffman: bool) -> Self { + Self { + int: IntegerEncoder::new(u8::from(is_huffman), length, 0x7f), + } + } + pub(crate) fn encode(mut self, dst: &mut [u8]) -> Result { + let mut cur = 0; + while !self.int.is_finish() { + let dst = &mut dst[cur..]; + if dst.is_empty() { + return Err(self); + } + dst[0] = self.int.next_byte().unwrap(); + cur += 1; + } + Ok(cur) + } +} +pub(crate) struct IntegerDecoder { + index: usize, + shift: u32, +} + +impl IntegerDecoder { + /// Calculates an integer based on the incoming first byte and mask. + /// If no subsequent bytes exist, return the result directly, otherwise + /// return the decoder itself. + pub(crate) fn first_byte(byte: u8, mask: u8) -> Result { + let index = byte & mask; + match index.cmp(&mask) { + Ordering::Less => Ok(index as usize), + _ => Err(Self { + index: index as usize, + shift: 1, + }), + } + } + + /// Continues computing the integer based on the next byte of the input. + /// Returns `Ok(Some(index))` if the result is obtained, otherwise returns + /// `Ok(None)`, and returns Err in case of overflow. + pub(crate) fn next_byte(&mut self, byte: u8) -> Result, H3Error> { + self.index = 1usize + .checked_shl(self.shift - 1) + .and_then(|res| res.checked_mul((byte & 0x7f) as usize)) + .and_then(|res| res.checked_add(self.index)) + .ok_or(H3Error::ConnectionError(ErrorCode::QPACK_DECOMPRESSION_FAILED))?;//todo: modify the error code + self.shift += 7; + match (byte & 0x80) == 0x00 { + true => Ok(Some(self.index)), + false => Ok(None), + } + } +} + +pub(crate) struct IntegerEncoder { + pre: u8, + i: usize, + mask: u8, + state: IntegerEncodeState, +} + +/// Enumeration of states that the `IntegerEncoder` needs to use. +enum IntegerEncodeState { + First, + Other, + Finish, +} + +impl IntegerEncoder { + /// Creates a new `IntegerEncoder`. + pub(crate) fn new(pre: u8, i: usize, mask: u8) -> Self { + Self { + pre, + i, + mask, + state: IntegerEncodeState::First, + } + } + + + /// return the value of the integer + pub(crate) fn get_index(&self) -> usize { + self.i + } + pub(crate) fn get_pre(&self) -> u8 { + self.pre + } + + /// Gets the next byte of the integer. If no remaining bytes are calculated, + /// return `None`. + pub(crate) fn next_byte(&mut self) -> Option { + match self.state { + IntegerEncodeState::First => { + if self.i < self.mask as usize { + self.state = IntegerEncodeState::Finish; + return Some(self.pre | (self.i as u8)); + } + self.i -= self.mask as usize; + self.state = IntegerEncodeState::Other; + Some(self.pre | self.mask) + } + IntegerEncodeState::Other => Some(if self.i >= 128 { + let res = (self.i & 0x7f) as u8; + self.i >>= 7; + res | 0x80 + } else { + self.state = IntegerEncodeState::Finish; + (self.i & 0x7f) as u8 + }), + IntegerEncodeState::Finish => None, + } + } + + /// Checks if calculation is over. + pub(crate) fn is_finish(&self) -> bool { + matches!(self.state, IntegerEncodeState::Finish) + } +} \ No newline at end of file diff --git a/ylong_http/src/h3/qpack/mod.rs b/ylong_http/src/h3/qpack/mod.rs new file mode 100644 index 0000000..82a2986 --- /dev/null +++ b/ylong_http/src/h3/qpack/mod.rs @@ -0,0 +1,221 @@ +pub(crate) mod table; +mod encoder; +mod format; +mod integer; +mod decoder; + +pub(crate) use decoder::QpackDecoder; +use crate::h3::qpack::format::decoder::Name; + + +pub(crate) struct RequireInsertCount(usize); + +pub(crate) struct DeltaBase(usize); + +#[derive(Copy, Clone, PartialEq, Eq)] +pub(crate) struct EncoderInstPrefixBit(u8); + +#[derive(Copy, Clone, PartialEq, Eq)] +pub(crate) struct DecoderInstPrefixBit(u8); + +#[derive(Copy, Clone, PartialEq, Eq)] +pub(crate) struct ReprPrefixBit(u8); + +/// # Prefix bit: +/// ## Encoder Instructions: +/// SETCAP: 0x20 +/// INSERTWITHINDEX: 0x80 +/// INSERTWITHLITERAL: 0x40 +/// DUPLICATE: 0x00 +/// +/// ## Decoder Instructions: +/// ACK: 0x80 +/// STREAMCANCEL: 0x40 +/// INSERTCOUNTINCREMENT: 0x00 +/// +/// ## Representation: +/// INDEXED: 0x80 +/// INDEXEDWITHPOSTINDEX: 0x10 +/// LITERALWITHINDEXING: 0x40 +/// LITERALWITHPOSTINDEXING: 0x00 +/// LITERALWITHLITERALNAME: 0x20 + +impl DecoderInstPrefixBit { + pub(crate) const ACK: Self = Self(0x80); + pub(crate) const STREAMCANCEL: Self = Self(0x40); + pub(crate) const INSERTCOUNTINCREMENT: Self = Self(0x00); + + pub(crate) fn from_u8(byte: u8) -> Self { + match byte { + x if x >= 0x80 => Self::ACK, + x if x >= 0x40 => Self::STREAMCANCEL, + _ => Self::INSERTCOUNTINCREMENT, + } + } + + pub(crate) fn prefix_index_mask(&self) -> PrefixMask { + match self.0 { + 0x80 => PrefixMask::ACK, + 0x40 => PrefixMask::STREAMCANCEL, + _ => PrefixMask::INSERTCOUNTINCREMENT, + } + } + + pub(crate) fn prefix_midbit_value(&self, byte: u8) -> MidBit { + match self.0 { + _ => MidBit { n: None, t: None, h: None }, + } + } +} + +impl EncoderInstPrefixBit { + pub(crate) const SETCAP: Self = Self(0x20); + pub(crate) const INSERTWITHINDEX: Self = Self(0x80); + pub(crate) const INSERTWITHLITERAL: Self = Self(0x40); + pub(crate) const DUPLICATE: Self = Self(0x00); + + pub(crate) fn from_u8(byte: u8) -> Self { + match byte { + x if x >= 0x80 => Self::INSERTWITHINDEX, + x if x >= 0x40 => Self::INSERTWITHLITERAL, + x if x >= 0x20 => Self::SETCAP, + _ => Self::DUPLICATE, + } + } + + pub(crate) fn prefix_index_mask(&self) -> PrefixMask { + match self.0 { + 0x80 => PrefixMask::INSERTWITHINDEX, + 0x40 => PrefixMask::INSERTWITHLITERAL, + 0x20 => PrefixMask::SETCAP, + _ => PrefixMask::DUPLICATE, + } + } + + pub(crate) fn prefix_midbit_value(&self, byte: u8) -> MidBit { + match self.0 { + 0x80 => MidBit { n: None, t: Some((byte & 0x40) != 0), h: None }, + 0x40 => MidBit { n: None, t: None, h: Some((byte & 0x20) != 0) }, + 0x20 => MidBit { n: None, t: None, h: None }, + _ => MidBit { n: None, t: None, h: None }, + } + } +} + +impl ReprPrefixBit { + pub(crate) const INDEXED: Self = Self(0x80); + pub(crate) const INDEXEDWITHPOSTINDEX: Self = Self(0x10); + pub(crate) const LITERALWITHINDEXING: Self = Self(0x40); + pub(crate) const LITERALWITHPOSTINDEXING: Self = Self(0x00); + pub(crate) const LITERALWITHLITERALNAME: Self = Self(0x20); + + /// Creates a `PrefixBit` from a byte. The interface will convert the + /// incoming byte to the most suitable prefix bit. + pub(crate) fn from_u8(byte: u8) -> Self { + match byte { + x if x >= 0x80 => Self::INDEXED, + x if x >= 0x40 => Self::LITERALWITHINDEXING, + x if x >= 0x20 => Self::LITERALWITHLITERALNAME, + x if x >= 0x10 => Self::INDEXEDWITHPOSTINDEX, + _ => Self::LITERALWITHPOSTINDEXING, + } + } + + /// Returns the corresponding `PrefixIndexMask` according to the current + /// prefix bit. + pub(crate) fn prefix_index_mask(&self) -> PrefixMask { + match self.0 { + 0x80 => PrefixMask::INDEXED, + 0x40 => PrefixMask::INDEXINGWITHNAME, + 0x20 => PrefixMask::INDEXINGWITHLITERAL, + 0x10 => PrefixMask::INDEXEDWITHPOSTNAME, + _ => PrefixMask::INDEXINGWITHPOSTNAME, + } + } + + /// Unlike Hpack, QPACK has some special value for the first byte of an integer. + /// Like T indicating whether the reference is into the static or dynamic table. + pub(crate) fn prefix_midbit_value(&self, byte: u8) -> MidBit { + match self.0 { + 0x80 => MidBit { n: None, t: Some((byte & 0x40) != 0), h: None }, + 0x40 => MidBit { n: Some((byte & 0x20) != 0), t: Some((byte & 0x10) != 0), h: None }, + 0x20 => MidBit { n: Some((byte & 0x10) != 0), t: None, h: Some((byte & 0x08) != 0) }, + 0x10 => MidBit { n: None, t: None, h: None }, + _ => MidBit { n: Some((byte & 0x08) != 0), t: None, h: None }, + } + } +} + +pub(crate) enum EncoderInstruction { + SetCap { capacity: usize }, + InsertWithIndex { mid_bit: MidBit, name: Name, value: Vec }, + InsertWithLiteral { mid_bit: MidBit, name: Name, value: Vec }, + Duplicate { index: usize }, + +} + +pub(crate) enum DecoderInstruction { + Ack { stream_id: usize }, + StreamCancel { stream_id: usize }, + InsertCountIncrement { increment: usize }, +} + +pub(crate) enum Representation { + /// An indexed field line format identifies an entry in the static table or an entry in + /// the dynamic table with an absolute index less than the value of the Base. + /// 0 1 2 3 4 5 6 7 + /// +---+---+---+---+---+---+---+---+ + /// | 1 | T | Index (6+) | + /// +---+---+-----------------------+ + /// This format starts with the '1' 1-bit pattern, followed by the 'T' bit, indicating + /// whether the reference is into the static or dynamic table. The 6-bit prefix integer + /// (Section 4.1.1) that follows is used to locate the table entry for the field line. When T=1, + /// the number represents the static table index; when T=0, the number is the relative index of + /// the entry in the dynamic table. + + FieldSectionPrefix { require_insert_count: RequireInsertCount, signal: bool, delta_base: DeltaBase }, + + Indexed { mid_bit: MidBit, index: usize }, + IndexedWithPostIndex { index: usize }, + LiteralWithIndexing { mid_bit: MidBit, name: Name, value: Vec }, + LiteralWithPostIndexing { mid_bit: MidBit, name: Name, value: Vec }, + LiteralWithLiteralName { mid_bit: MidBit, name: Name, value: Vec }, + +} + + +//impl debug for Representation + + +pub(crate) struct MidBit { + //'N', indicates whether an intermediary is permitted to add this field line to the dynamic + // table on subsequent hops. + n: Option, + //'T', indicating whether the reference is into the static or dynamic table. + t: Option, + //'H', indicating whether is represented as a Huffman-encoded. + h: Option, + +} + +pub(crate) struct PrefixMask(u8); + + +impl PrefixMask { + pub(crate) const REQUIREINSERTCOUNT: Self = Self(0xff); + pub(crate) const DELTABASE: Self = Self(0x7f); + pub(crate) const INDEXED: Self = Self(0x3f); + pub(crate) const SETCAP: Self = Self(0x1f); + pub(crate) const INSERTWITHINDEX: Self = Self(0x3f); + pub(crate) const INSERTWITHLITERAL: Self = Self(0x1f); + pub(crate) const DUPLICATE: Self = Self(0x1f); + + pub(crate) const ACK: Self = Self(0x7f); + pub(crate) const STREAMCANCEL: Self = Self(0x3f); + pub(crate) const INSERTCOUNTINCREMENT: Self = Self(0x3f); + + pub(crate) const INDEXINGWITHNAME: Self = Self(0x0f); + pub(crate) const INDEXINGWITHPOSTNAME: Self = Self(0x07); + pub(crate) const INDEXINGWITHLITERAL: Self = Self(0x07); + pub(crate) const INDEXEDWITHPOSTNAME: Self = Self(0x0f); +} \ No newline at end of file diff --git a/ylong_http/src/h3/qpack/table.rs b/ylong_http/src/h3/qpack/table.rs new file mode 100644 index 0000000..ae15872 --- /dev/null +++ b/ylong_http/src/h3/qpack/table.rs @@ -0,0 +1,507 @@ +use std::collections::{HashMap, VecDeque}; + +/// The [`Dynamic Table`][dynamic_table] implementation of [QPACK]. +/// +/// [dynamic_table]: https://www.rfc-editor.org/rfc/rfc9204.html#name-dynamic-table +/// [QPACK]: https://www.rfc-editor.org/rfc/rfc9204.html +/// # Introduction +/// The dynamic table consists of a list of field lines maintained in first-in, first-out order. +/// A QPACK encoder and decoder share a dynamic table that is initially empty. +/// The encoder adds entries to the dynamic table and sends them to the decoder via instructions on +/// the encoder stream +/// +/// The dynamic table can contain duplicate entries (i.e., entries with the same name and same value). +/// Therefore, duplicate entries MUST NOT be treated as an error by the decoder. +/// +/// Dynamic table entries can have empty values. + + +pub(crate) struct TableSearcher<'a> { + dynamic: &'a DynamicTable, +} + +impl<'a> TableSearcher<'a> { + pub(crate) fn new(dynamic: &'a DynamicTable) -> Self { + Self { dynamic } + } + + + /// Searches index in static and dynamic tables. + pub(crate) fn find_index_static(&self, header: &Field, value: &str) -> Option { + match StaticTable::index(header, value) { + x @ Some(TableIndex::Field(_)) => x, + _ => Some(TableIndex::None), + } + } + + pub(crate) fn find_index_name_static(&self, header: &Field, value: &str) -> Option { + match StaticTable::index(header, value) { + x @ Some(TableIndex::FieldName(_)) => x, + _ => Some(TableIndex::None), + } + } + + pub(crate) fn find_index_dynamic(&self, header: &Field, value: &str) -> Option { + match self.dynamic.index(header, value) { + x @ Some(TableIndex::Field(_)) => x, + _ => Some(TableIndex::None), + } + } + + pub(crate) fn find_index_name_dynamic(&self, header: &Field, value: &str) -> Option { + match self.dynamic.index(header, value) { + x @ Some(TableIndex::FieldName(_)) => x, + _ => Some(TableIndex::None), + } + } + + pub(crate) fn find_field_static(&self, index: usize) -> Option<(Field, String)> { + match StaticTable::field(index) { + x @ Some((_, _)) => x, + _ => None, + } + } + + pub(crate) fn find_field_name_static(&self, index: usize) -> Option { + StaticTable::field_name(index) + } + + pub(crate) fn find_field_dynamic(&self, index: usize) -> Option<(Field, String)> { + self.dynamic.field(index) + } + + pub(crate) fn find_field_name_dynamic(&self, index: usize) -> Option { + self.dynamic.field_name(index) + } + + pub(crate) fn can_index(&self, header: &Field, value: &str) -> bool { + //todo + true + } +} + + +pub(crate) struct DynamicTable { + queue: VecDeque<(Field, String)>, + // The size of the dynamic table is the sum of the size of its entries + size: usize, + capacity: usize, + pub(crate) insert_count: usize, + remove_count: usize, + pub(crate) known_received_count: usize, + pub(crate) ref_count: HashMap, +} + +impl DynamicTable { + pub(crate) fn with_capacity(capacity: usize) -> Self { + Self { + queue: VecDeque::new(), + size: 0, + capacity, + insert_count: 0, + remove_count: 0, + known_received_count: 0, + ref_count: HashMap::new(), + } + } + + pub(crate) fn size(&self) -> usize { + self.size + } + + pub(crate) fn capacity(&self) -> usize { + self.capacity + } + + pub(crate) fn max_entries(&self) -> usize { + self.capacity / 32 + } + /// Updates `DynamicTable` by a given `Header` and value pair. + pub(crate) fn update(&mut self, field: Field, value: String) { + self.size += field.len() + value.len() + 32; + self.queue.push_back((field, value)); + self.ref_count.insert(self.queue.len() + self.remove_count - 1, 0); + self.fit_size(); + } + + pub(crate) fn have_enough_space(&self, field: &Field, value: &String) -> bool { + if self.size + field.len() + value.len() + 32 <= self.capacity { + return true; + } else { + let mut eviction_space = 0; + for (i, (h, v)) in self.queue.iter().enumerate() { + if let Some(0) = self.ref_count.get(&(i + self.remove_count)){ + eviction_space += h.len() + v.len() + 32; + } + else { + if eviction_space >= field.len() + value.len() + 32 { + return true; + } + return false; + } + if eviction_space >= field.len() + value.len() + 32 { + return true; + } + } + } + false + } + + /// Updates `DynamicTable`'s size. + pub(crate) fn update_size(&mut self, max_size: usize) { + self.capacity = max_size; + self.fit_size(); + } + + /// Adjusts dynamic table content to fit its size. + fn fit_size(&mut self) { + while self.size > self.capacity && !self.queue.is_empty() { + let (key, string) = self.queue.pop_front().unwrap(); + self.remove_count += 1; + self.capacity -= key.len() + string.len() + 32; + } + } + + /// Tries get the index of a `Header`. + fn index(&self, header: &Field, value: &str) -> Option { + let mut index = None; + for (n, (h, v)) in self.queue.iter().enumerate() { + match (header == h, value == v, &index) { + (true, true, _) => return Some(TableIndex::Field(n + self.remove_count)), + (true, false, None) => index = Some(TableIndex::FieldName(n + self.remove_count)), + _ => {} + } + } + index + } + + pub(crate) fn field(&self, index: usize) -> Option<(Field, String)> { + self.queue.get(index - self.remove_count).cloned() + } + + pub(crate) fn field_name(&self, index: usize) -> Option { + self.queue.get(index - self.remove_count).map(|(field, _)| field.clone()) + } + +} + +#[derive(PartialEq)] +pub(crate) enum TableIndex { + Field(usize), + FieldName(usize), + None, +} + + +/// The [`Static Table`][static_table] implementation of [QPACK]. +/// +/// [static_table]: https://www.rfc-editor.org/rfc/rfc9204.html#static-table +/// [QPACK]: https://www.rfc-editor.org/rfc/rfc9204.html +/// +/// # Introduction +/// The static table consists of a predefined list of field lines, +/// each of which has a fixed index over time. +/// All entries in the static table have a name and a value. +/// However, values can be empty (that is, have a length of 0). Each entry is +/// identified by a unique index. +/// Note that the QPACK static table is indexed from 0, +/// whereas the HPACK static table is indexed from 1. +/// When the decoder encounters an invalid static table +/// index in a field line format, it MUST treat this +/// as a connection error of type QPACK_DECOMPRESSION_FAILED. +/// If this index is received on the encoder stream, +/// this MUST be treated as a connection error of type QPACK_ENCODER_STREAM_ERROR. +/// + +struct StaticTable; + +impl StaticTable { + /// Gets a `Field` by the given index. + fn field_name(index: usize) -> Option { + match index { + 0 => Some(Field::Authority), + 1 => Some(Field::Path), + 2 => Some(Field::Other(String::from("age"))), + 3 => Some(Field::Other(String::from("content-disposition"))), + 4 => Some(Field::Other(String::from("content-length"))), + 5 => Some(Field::Other(String::from("cookie"))), + 6 => Some(Field::Other(String::from("date"))), + 7 => Some(Field::Other(String::from("etag"))), + 8 => Some(Field::Other(String::from("if-modified-since"))), + 9 => Some(Field::Other(String::from("if-none-match"))), + 10 => Some(Field::Other(String::from("last-modified"))), + 11 => Some(Field::Other(String::from("link"))), + 12 => Some(Field::Other(String::from("location"))), + 13 => Some(Field::Other(String::from("referer"))), + 14 => Some(Field::Other(String::from("set-cookie"))), + 15..=21 => Some(Field::Method), + 22..=23 => Some(Field::Scheme), + 24..=28 => Some(Field::Status), + 29..=30 => Some(Field::Other(String::from("accept"))), + 31 => Some(Field::Other(String::from("accept-encoding"))), + 32 => Some(Field::Other(String::from("accept-ranges"))), + 33..=34 => Some(Field::Other(String::from("access-control-allow-headers"))), + 35 => Some(Field::Other(String::from("access-control-allow-origin"))), + 36..=41 => Some(Field::Other(String::from("cache-control"))), + 42..=43 => Some(Field::Other(String::from("content-encoding"))), + 44..=54 => Some(Field::Other(String::from("content-type"))), + 55 => Some(Field::Other(String::from("range"))), + 56..=58 => Some(Field::Other(String::from("strict-transport-security"))), + 59..=60 => Some(Field::Other(String::from("vary"))), + 61 => Some(Field::Other(String::from("x-content-type-options"))), + 62 => Some(Field::Other(String::from("x-xss-protection"))), + 63..=71 => Some(Field::Status), + 72 => Some(Field::Other(String::from("accept-language"))), + 73..=74 => Some(Field::Other(String::from("access-control-allow-credentials"))), + 75 => Some(Field::Other(String::from("access-control-allow-headers"))), + 76..=78 => Some(Field::Other(String::from("access-control-allow-methods"))), + 79 => Some(Field::Other(String::from("access-control-expose-headers"))), + 80 => Some(Field::Other(String::from("access-control-request-headers"))), + 81..=82 => Some(Field::Other(String::from("access-control-request-method"))), + 83 => Some(Field::Other(String::from("alt-svc"))), + 84 => Some(Field::Other(String::from("authorization"))), + 85 => Some(Field::Other(String::from("content-security-policy"))), + 86 => Some(Field::Other(String::from("early-data"))), + 87 => Some(Field::Other(String::from("expect-ct"))), + 88 => Some(Field::Other(String::from("forwarded"))), + 89 => Some(Field::Other(String::from("if-range"))), + 90 => Some(Field::Other(String::from("origin"))), + 91 => Some(Field::Other(String::from("purpose"))), + 92 => Some(Field::Other(String::from("server"))), + 93 => Some(Field::Other(String::from("timing-allow-origin"))), + 94 => Some(Field::Other(String::from("upgrade-insecure-requests"))), + 95 => Some(Field::Other(String::from("user-agent"))), + 96 => Some(Field::Other(String::from("x-forwarded-for"))), + 97..=98 => Some(Field::Other(String::from("x-frame-options"))), + _ => None, + } + } + + /// Tries to get a `Field` and a value by the given index. + fn field(index: usize) -> Option<(Field, String)> { + match index { + 1 => Some((Field::Path, String::from("/"))), + 2 => Some((Field::Other(String::from("age")), String::from("0"))), + 4 => Some((Field::Other(String::from("content-length")), String::from("0"))), + 15 => Some((Field::Method, String::from("CONNECT"))), + 16 => Some((Field::Method, String::from("DELETE"))), + 17 => Some((Field::Method, String::from("GET"))), + 18 => Some((Field::Method, String::from("HEAD"))), + 19 => Some((Field::Method, String::from("OPTIONS"))), + 20 => Some((Field::Method, String::from("POST"))), + 21 => Some((Field::Method, String::from("PUT"))), + 22 => Some((Field::Scheme, String::from("http"))), + 23 => Some((Field::Scheme, String::from("https"))), + 24 => Some((Field::Status, String::from("103"))), + 25 => Some((Field::Status, String::from("200"))), + 26 => Some((Field::Status, String::from("304"))), + 27 => Some((Field::Status, String::from("404"))), + 28 => Some((Field::Status, String::from("503"))), + 29 => Some((Field::Other(String::from("accept")), String::from("*/*"))), + 30 => Some((Field::Other(String::from("accept")), String::from("application/dns-message"))), + 31 => Some((Field::Other(String::from("accept-encoding")), String::from("gzip, deflate, br"))), + 32 => Some((Field::Other(String::from("accept-ranges")), String::from("bytes"))), + 33 => Some((Field::Other(String::from("access-control-allow-headers")), String::from("cache-control"))), + 34 => Some((Field::Other(String::from("access-control-allow-headers")), String::from("content-type"))), + 35 => Some((Field::Other(String::from("access-control-allow-origin")), String::from("*"))), + 36 => Some((Field::Other(String::from("cache-control")), String::from("max-age=0"))), + 37 => Some((Field::Other(String::from("cache-control")), String::from("max-age=2592000"))), + 38 => Some((Field::Other(String::from("cache-control")), String::from("max-age=604800"))), + 39 => Some((Field::Other(String::from("cache-control")), String::from("no-cache"))), + 40 => Some((Field::Other(String::from("cache-control")), String::from("no-store"))), + 41 => Some((Field::Other(String::from("cache-control")), String::from("public, max-age=31536000"))), + 42 => Some((Field::Other(String::from("content-encoding")), String::from("br"))), + 43 => Some((Field::Other(String::from("content-encoding")), String::from("gzip"))), + 44 => Some((Field::Other(String::from("content-type")), String::from("application/dns-message"))), + 45 => Some((Field::Other(String::from("content-type")), String::from("application/javascript"))), + 46 => Some((Field::Other(String::from("content-type")), String::from("application/json"))), + 47 => Some((Field::Other(String::from("content-type")), String::from("application/x-www-form-urlencoded"))), + 48 => Some((Field::Other(String::from("content-type")), String::from("image/gif"))), + 49 => Some((Field::Other(String::from("content-type")), String::from("image/jpeg"))), + 50 => Some((Field::Other(String::from("content-type")), String::from("image/png"))), + 51 => Some((Field::Other(String::from("content-type")), String::from("text/css"))), + 52 => Some((Field::Other(String::from("content-type")), String::from("text/html; charset=utf-8"))), + 53 => Some((Field::Other(String::from("content-type")), String::from("text/plain"))), + 54 => Some((Field::Other(String::from("content-type")), String::from("text/plain;charset=utf-8"))), + 55 => Some((Field::Other(String::from("range")), String::from("bytes=0-"))), + 56 => Some((Field::Other(String::from("strict-transport-security")), String::from("max-age=31536000"))), + 57 => Some((Field::Other(String::from("strict-transport-security")), String::from("max-age=31536000; includesubdomains"))), + 58 => Some((Field::Other(String::from("strict-transport-security")), String::from("max-age=31536000; includesubdomains; preload"))), + 59 => Some((Field::Other(String::from("vary")), String::from("accept-encoding"))), + 60 => Some((Field::Other(String::from("vary")), String::from("origin"))), + 61 => Some((Field::Other(String::from("x-content-type-options")), String::from("nosniff"))), + 62 => Some((Field::Other(String::from("x-xss-protection")), String::from("1; mode=block"))), + 63 => Some((Field::Status, String::from("100"))), + 64 => Some((Field::Status, String::from("204"))), + 65 => Some((Field::Status, String::from("206"))), + 66 => Some((Field::Status, String::from("302"))), + 67 => Some((Field::Status, String::from("400"))), + 68 => Some((Field::Status, String::from("403"))), + 69 => Some((Field::Status, String::from("421"))), + 70 => Some((Field::Status, String::from("425"))), + 71 => Some((Field::Status, String::from("500"))), + 73 => Some((Field::Other(String::from("access-control-allow-credentials")), String::from("FALSE"))), + 74 => Some((Field::Other(String::from("access-control-allow-credentials")), String::from("TRUE"))), + 75 => Some((Field::Other(String::from("access-control-allow-headers")), String::from("*"))), + 76 => Some((Field::Other(String::from("access-control-allow-methods")), String::from("get"))), + 77 => Some((Field::Other(String::from("access-control-allow-methods")), String::from("get, post, options"))), + 78 => Some((Field::Other(String::from("access-control-allow-methods")), String::from("options"))), + 79 => Some((Field::Other(String::from("access-control-expose-headers")), String::from("content-length"))), + 80 => Some((Field::Other(String::from("access-control-request-headers")), String::from("content-type"))), + 81 => Some((Field::Other(String::from("access-control-request-method")), String::from("get"))), + 82 => Some((Field::Other(String::from("access-control-request-method")), String::from("post"))), + 83 => Some((Field::Other(String::from("alt-svc")), String::from("clear"))), + 85 => Some((Field::Other(String::from("content-security-policy")), String::from("script-src 'none'; object-src 'none'; base-uri 'none'"))), + 86 => Some((Field::Other(String::from("early-data")), String::from("1"))), + 91 => Some((Field::Other(String::from("purpose")), String::from("prefetch"))), + 93 => Some((Field::Other(String::from("timing-allow-origin")), String::from("*"))), + 94 => Some((Field::Other(String::from("upgrade-insecure-requests")), String::from("1"))), + 97 => Some((Field::Other(String::from("x-frame-options")), String::from("deny"))), + 98 => Some((Field::Other(String::from("x-frame-options")), String::from("sameorigin"))), + _ => None, + } + } + + /// Tries to get a `Index` by the given field and value. + fn index(field: &Field, value: &str) -> Option { + match (field, value) { + (Field::Authority, _) => Some(TableIndex::FieldName(0)), + (Field::Path, "/") => Some(TableIndex::Field(1)), + (Field::Method, "CONNECT") => Some(TableIndex::Field(15)), + (Field::Method, "DELETE") => Some(TableIndex::Field(16)), + (Field::Method, "GET") => Some(TableIndex::Field(17)), + (Field::Method, "HEAD") => Some(TableIndex::Field(18)), + (Field::Method, "OPTIONS") => Some(TableIndex::Field(19)), + (Field::Method, "POST") => Some(TableIndex::Field(20)), + (Field::Method, "PUT") => Some(TableIndex::Field(21)), + (Field::Scheme, "http") => Some(TableIndex::Field(22)), + (Field::Scheme, "https") => Some(TableIndex::Field(23)), + (Field::Status, "103") => Some(TableIndex::Field(24)), + (Field::Status, "200") => Some(TableIndex::Field(25)), + (Field::Status, "304") => Some(TableIndex::Field(26)), + (Field::Status, "404") => Some(TableIndex::Field(27)), + (Field::Status, "503") => Some(TableIndex::Field(28)), + (Field::Status, "100") => Some(TableIndex::Field(63)), + (Field::Status, "204") => Some(TableIndex::Field(64)), + (Field::Status, "206") => Some(TableIndex::Field(65)), + (Field::Status, "302") => Some(TableIndex::Field(66)), + (Field::Status, "400") => Some(TableIndex::Field(67)), + (Field::Status, "403") => Some(TableIndex::Field(68)), + (Field::Status, "421") => Some(TableIndex::Field(69)), + (Field::Status, "425") => Some(TableIndex::Field(70)), + (Field::Status, "500") => Some(TableIndex::Field(71)), + (Field::Other(s), v) => match (s.as_str(), v) { + ("age", "0") => Some(TableIndex::Field(2)), + ("content-disposition", _) => Some(TableIndex::FieldName(3)), + ("content-length", "0") => Some(TableIndex::Field(4)), + ("cookie", _) => Some(TableIndex::FieldName(5)), + ("date", _) => Some(TableIndex::FieldName(6)), + ("etag", _) => Some(TableIndex::FieldName(7)), + ("if-modified-since", _) => Some(TableIndex::FieldName(8)), + ("if-none-match", _) => Some(TableIndex::FieldName(9)), + ("last-modified", _) => Some(TableIndex::FieldName(10)), + ("link", _) => Some(TableIndex::FieldName(11)), + ("location", _) => Some(TableIndex::FieldName(12)), + ("referer", _) => Some(TableIndex::FieldName(13)), + ("set-cookie", _) => Some(TableIndex::FieldName(14)), + ("accept", "*/*") => Some(TableIndex::Field(29)), + ("accept", "application/dns-message") => Some(TableIndex::Field(30)), + ("accept-encoding", "gzip, deflate, br") => Some(TableIndex::Field(31)), + ("accept-ranges", "bytes") => Some(TableIndex::Field(32)), + ("access-control-allow-headers", "cache-control") => Some(TableIndex::Field(33)), + ("access-control-allow-headers", "content-type") => Some(TableIndex::Field(34)), + ("access-control-allow-origin", "*") => Some(TableIndex::Field(35)), + ("cache-control", "max-age=0") => Some(TableIndex::Field(36)), + ("cache-control", "max-age=2592000") => Some(TableIndex::Field(37)), + ("cache-control", "max-age=604800") => Some(TableIndex::Field(38)), + ("cache-control", "no-cache") => Some(TableIndex::Field(39)), + ("cache-control", "no-store") => Some(TableIndex::Field(40)), + ("cache-control", "public, max-age=31536000") => Some(TableIndex::Field(41)), + ("content-encoding", "br") => Some(TableIndex::Field(42)), + ("content-encoding", "gzip") => Some(TableIndex::Field(43)), + ("content-type", "application/dns-message") => Some(TableIndex::Field(44)), + ("content-type", "application/javascript") => Some(TableIndex::Field(45)), + ("content-type", "application/json") => Some(TableIndex::Field(46)), + ("content-type", "application/x-www-form-urlencoded") => Some(TableIndex::Field(47)), + ("content-type", "image/gif") => Some(TableIndex::Field(48)), + ("content-type", "image/jpeg") => Some(TableIndex::Field(49)), + ("content-type", "image/png") => Some(TableIndex::Field(50)), + ("content-type", "text/css") => Some(TableIndex::Field(51)), + ("content-type", "text/html; charset=utf-8") => Some(TableIndex::Field(52)), + ("content-type", "text/plain") => Some(TableIndex::Field(53)), + ("content-type", "text/plain;charset=utf-8") => Some(TableIndex::Field(54)), + ("range", "bytes=0-") => Some(TableIndex::Field(55)), + ("strict-transport-security", "max-age=31536000") => Some(TableIndex::Field(56)), + ("strict-transport-security", "max-age=31536000; includesubdomains") => Some(TableIndex::Field(57)), + ("strict-transport-security", "max-age=31536000; includesubdomains; preload") => Some(TableIndex::Field(58)), + ("vary", "accept-encoding") => Some(TableIndex::Field(59)), + ("vary", "origin") => Some(TableIndex::Field(60)), + ("x-content-type-options", "nosniff") => Some(TableIndex::Field(61)), + ("x-xss-protection", "1; mode=block") => Some(TableIndex::Field(62)), + ("accept-language", _) => Some(TableIndex::FieldName(72)), + ("access-control-allow-credentials", "FALSE") => Some(TableIndex::Field(73)), + ("access-control-allow-credentials", "TRUE") => Some(TableIndex::Field(74)), + ("access-control-allow-headers", "*") => Some(TableIndex::Field(75)), + ("access-control-allow-methods", "get") => Some(TableIndex::Field(76)), + ("access-control-allow-methods", "get, post, options") => Some(TableIndex::Field(77)), + ("access-control-allow-methods", "options") => Some(TableIndex::Field(78)), + ("access-control-expose-headers", "content-length") => Some(TableIndex::Field(79)), + ("access-control-request-headers", "content-type") => Some(TableIndex::Field(80)), + ("access-control-request-method", "get") => Some(TableIndex::Field(81)), + ("access-control-request-method", "post") => Some(TableIndex::Field(82)), + ("alt-svc", "clear") => Some(TableIndex::Field(83)), + ("authorization", _) => Some(TableIndex::FieldName(84)), + ("content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'") => Some(TableIndex::Field(85)), + ("early-data", "1") => Some(TableIndex::Field(86)), + ("expect-ct", _) => Some(TableIndex::FieldName(87)), + ("forwarded", _) => Some(TableIndex::FieldName(88)), + ("if-range", _) => Some(TableIndex::FieldName(89)), + ("origin", _) => Some(TableIndex::FieldName(90)), + ("purpose", "prefetch") => Some(TableIndex::Field(91)), + ("server", _) => Some(TableIndex::FieldName(92)), + ("timing-allow-origin", "*") => Some(TableIndex::Field(93)), + ("upgrade-insecure-requests", "1") => Some(TableIndex::Field(94)), + ("user-agent", _) => Some(TableIndex::FieldName(95)), + ("x-forwarded-for", _) => Some(TableIndex::FieldName(96)), + ("x-frame-options", "deny") => Some(TableIndex::Field(97)), + ("x-frame-options", "sameorigin") => Some(TableIndex::Field(98)), + _ => None, + }, + _ => None, + } + } +} + +#[derive(Clone, PartialEq, Eq, Debug)] +pub(crate) enum Field { + Authority, + Method, + Path, + Scheme, + Status, + Other(String), +} + +impl Field { + pub(crate) fn len(&self) -> usize { + match self { + Field::Authority => 10, // 10 is the length of ":authority". + Field::Method => 7, // 7 is the length of ":method". + Field::Path => 5, // 5 is the length of ":path". + Field::Scheme => 7, // 7 is the length of "scheme". + Field::Status => 7, // 7 is the length of "status". + Field::Other(s) => s.len(), + } + } + + pub(crate) fn into_string(self) -> String { + match self { + Field::Authority => String::from(":authority"), + Field::Method => String::from(":method"), + Field::Path => String::from(":path"), + Field::Scheme => String::from(":scheme"), + Field::Status => String::from(":status"), + Field::Other(s) => s, + } + } +} \ No newline at end of file -- Gitee