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 1/8] 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 From 2a152b2a4ceee1f18045f73f846a2f9a09e41224 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Tue, 22 Aug 2023 20:41:02 +0800 Subject: [PATCH 2/8] qpack Signed-off-by: Weng Shihao --- ylong_http/src/h3/qpack/decoder.rs | 142 +++++++++++--- ylong_http/src/h3/qpack/encoder.rs | 223 ++++++++++++++++++++-- ylong_http/src/h3/qpack/format/encoder.rs | 144 ++++++++++---- ylong_http/src/h3/qpack/mod.rs | 1 + ylong_http/src/h3/qpack/table.rs | 62 +++++- 5 files changed, 483 insertions(+), 89 deletions(-) diff --git a/ylong_http/src/h3/qpack/decoder.rs b/ylong_http/src/h3/qpack/decoder.rs index a3b6fa3..a015f0d 100644 --- a/ylong_http/src/h3/qpack/decoder.rs +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -55,15 +55,16 @@ impl<'a> QpackDecoder<'a> { } EncoderInstruction::InsertWithIndex { mid_bit, name, value } => { let value_str = String::from_utf8(value.clone()).unwrap(); - println!("value: {}", value_str); + println!("InsertWithIndex 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); + println!("InsertWithLiteral value: {}", value_str); updater.update_table(mid_bit, name, value)?; } EncoderInstruction::Duplicate { index } => { + println!("Duplicate index: {}", index); updater.duplicate(index)?; } } @@ -93,29 +94,28 @@ impl<'a> QpackDecoder<'a> { Some(repr) => { match repr { Representation::FieldSectionPrefix { require_insert_count, signal, delta_base } => { - if require_insert_count.0 == 0{ + if require_insert_count.0 == 0 { self.require_insert_count = 0; - } - else { + } 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{ + println!("self.require_insert_count: {}", self.require_insert_count); + 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!("require_insert_count: {}", self.require_insert_count); println!("signal: {}", signal); println!("delta_base: {}", delta_base.0); if signal { - self.base = require_insert_count.0 - delta_base.0 - 1; + self.base = self.require_insert_count - delta_base.0 - 1; } else { - self.base = require_insert_count.0 + delta_base.0; + self.base = self.require_insert_count + delta_base.0; } + println!("base: {}", self.base); searcher.base = self.base; //todo:block } @@ -226,7 +226,7 @@ impl<'a> Updater<'a> { 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) + .find_field_dynamic(self.table.insert_count - index -1) .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; self.table.update(f, v); Ok(()) @@ -248,7 +248,7 @@ impl<'a> Updater<'a> { .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? } else { searcher - .find_field_name_dynamic(insert_count - index) + .find_field_name_dynamic(insert_count - index - 1) .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? } } @@ -296,27 +296,30 @@ impl<'a> Searcher<'a> { } fn search_indexed(&mut self, mid_bit: MidBit, index: usize) -> Result<(), H3Error> { - let table_searcher = TableSearcher::new(self.table); + let table_searcher = TableSearcher::new(&mut 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) + .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 table_searcher = TableSearcher::new(&mut self.table); let (f, v) = table_searcher .find_field_dynamic(self.base + index) .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + print!("search_res: {:#?}", v); self.check_field_list_size(&f, &v)?; self.lines.parts.update(f, v); return Ok(()); @@ -354,7 +357,7 @@ impl<'a> Searcher<'a> { let h = match name { Name::Index(index) => { if repr == ReprPrefixBit::LITERALWITHINDEXING { - let searcher = TableSearcher::new(self.table); + let searcher = TableSearcher::new(&self.table); if let Some(true) = mid_bit.t { searcher .find_field_name_static(index) @@ -365,7 +368,7 @@ impl<'a> Searcher<'a> { .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? } } else { - let searcher = TableSearcher::new(self.table); + let searcher = TableSearcher::new(&self.table); searcher .find_field_name_dynamic(self.base + index) .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? @@ -409,13 +412,14 @@ mod ut_qpack_decoder { #[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(); + rfc9204_test_cases(); + 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 { ( @@ -483,6 +487,86 @@ mod ut_qpack_decoder { }; } + + fn rfc9204_test_cases() { + literal_field_line_with_name_reference(); + dynamic_table(); + speculative_insert(); + duplicate_instruction_stream_cancellation(); + dynamic_table_insert_eviction(); + fn literal_field_line_with_name_reference() { + let mut dynamic_table = DynamicTable::with_capacity(4096); + + qpack_test_case!( + QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + "0000510b2f696e6465782e68746d6c", + { None, None, Some("/index.html"), None, None }, + { 0 } + ); + } + fn dynamic_table() { + let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + decoder.decode_ins(decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468").unwrap().as_slice()); + qpack_test_case!( + decoder, + "03811011", + { Some("www.example.com"), None, Some("/sample/path"), None, None }, + { 0 } + ); + } + fn speculative_insert() { + let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + decoder.decode_ins(decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565").unwrap().as_slice()); + qpack_test_case!( + decoder, + "028010", + { "custom-key"=>"custom-value" }, + { 0 } + ); + } + fn duplicate_instruction_stream_cancellation() { + println!("duplicate_instruction_stream_cancellation"); + let mut dynamic_table = DynamicTable::with_capacity(4096); + dynamic_table.update(Field::Authority,String::from("www.example.com")); + dynamic_table.update(Field::Path,String::from("/sample/path")); + dynamic_table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); + dynamic_table.ref_count.insert(0, 0); //Acked + dynamic_table.ref_count.insert(1, 0); //Acked + dynamic_table.ref_count.insert(2, 0); //Acked + dynamic_table.known_received_count = 3; + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + decoder.decode_ins(decode("02").unwrap().as_slice()); + qpack_test_case!( + decoder, + "058010c180", + { Some("www.example.com"), None, Some("/"), None, None }, + { "custom-key"=>"custom-value" }, + { 0 } + ); + } + fn dynamic_table_insert_eviction(){ + let mut dynamic_table = DynamicTable::with_capacity(4096); + dynamic_table.update(Field::Authority,String::from("www.example.com")); + dynamic_table.update(Field::Path,String::from("/sample/path")); + dynamic_table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); + dynamic_table.update(Field::Authority,String::from("www.example.com")); + dynamic_table.ref_count.insert(0, 0); //Acked + dynamic_table.ref_count.insert(1, 0); //Acked + dynamic_table.ref_count.insert(2, 0); //Acked + dynamic_table.known_received_count = 3; + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + decoder.decode_ins(decode("810d637573746f6d2d76616c756532").unwrap().as_slice()); + qpack_test_case!( + decoder, + "068111", + { "custom-key"=>"custom-value2" }, + { 0 } + ); + } + } + fn test_indexed_static() { let mut dynamic_table = DynamicTable::with_capacity(4096); @@ -507,7 +591,7 @@ mod ut_qpack_decoder { //require_insert_count=2, signal=false, delta_base=0 //so base=2 //rel_index=1 (abs=2(base)-1-1=0) - "020081", + "030081", {"custom-field"=>"custom-value"}, { 0 } ); @@ -527,7 +611,7 @@ mod ut_qpack_decoder { //require_insert_count=3, signal=true, delta_base=2 //so base = 3-2-1 = 0 //rel_index=1 (abs=0(base)+1=1) - "038211", + "048211", {"custom2-field"=>"custom2-value"}, { 0 } ); @@ -555,7 +639,7 @@ mod ut_qpack_decoder { //require_insert_count=2, signal=false, delta_base=0 //so base=2 //rel_index=1 (abs=2(base)-1-1=0) - "0200610d637573746f6d312d76616c7565", + "0300610d637573746f6d312d76616c7565", {"custom-field"=>"custom1-value"}, { 0 } ); @@ -576,7 +660,7 @@ mod ut_qpack_decoder { //require_insert_count=3, signal=true, delta_base=2 //so base = 3-2-1 = 0 //rel_index=1 (abs=0(base)+1=1) - "0382010d637573746f6d312d76616c7565", + "0482010d637573746f6d312d76616c7565", {"custom2-field"=>"custom1-value"}, { 0 } ); diff --git a/ylong_http/src/h3/qpack/encoder.rs b/ylong_http/src/h3/qpack/encoder.rs index c994d77..337fedc 100644 --- a/ylong_http/src/h3/qpack/encoder.rs +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -14,16 +14,24 @@ pub(crate) struct QpackEncoder { inst_holder: InstDecStateHolder, stream_reference: VecDeque>, stream_id: usize, + is_insert: bool, + // if not insert to dynamic table, the required insert count will be 0. + allow_post: bool, + // allow reference to the inserting field default is false. + draining_index: usize, // RFC9204-2.1.1.1. if index (QpackEncoder, usize) { + pub(crate) fn with_capacity(max_size: usize, encoder_buf: &mut [u8], stream_id: usize, allow_post: bool, draining_index: 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, + is_insert: false, + allow_post: allow_post, + draining_index: draining_index, }; let cur = EncoderInst::SetCap(SetCap::new(max_size)).encode(&mut encoder_buf[..]); (s, cur) @@ -52,12 +60,11 @@ impl QpackEncoder { break;// end of field section } if let Some(ind) = index { - if let Some(count) = self.table.ref_count.get(&ind){ + if let Some(count) = self.table.ref_count.get(&ind) { self.table.ref_count.insert(ind, count - 1); } } - } - else { + } else { return Err(H3Error::ConnectionError(QPACK_DECODER_STREAM_ERROR)); } } @@ -80,26 +87,31 @@ impl QpackEncoder { } /// 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); + pub(crate) fn encode(&mut self, encoder_buf: &mut [u8], stream_buf: &mut [u8]) -> (usize, usize, Option<([u8; 1024], usize)>) { let mut cur_prefix = 0; + let mut cur_encoder = 0; + let mut cur_stream = 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 wire_ric = 0; + if self.is_insert { + wire_ric = 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); + cur_prefix += Integer::index(0x00, wire_ric, 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); + 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); + 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, Some((prefix_buf, cur_prefix))) + } else { + let mut encoder = ReprEncoder::new(&mut self.table, self.draining_index); + encoder.load(&mut self.holder); + (cur_encoder, cur_stream) = encoder.encode(&mut encoder_buf[0..], &mut stream_buf[0..], &mut self.stream_reference, &mut self.is_insert, self.allow_post); + (cur_encoder, cur_stream, None) } - (cur_encoder, cur_stream + cur_prefix) } /// Check the previously set `Parts` if encoding is complete. @@ -157,11 +169,188 @@ impl SetCap { #[cfg(test)] mod ut_qpack_encoder { use crate::h3::parts::Parts; + use crate::h3::qpack::encoder; use crate::h3::qpack::encoder::{QpackEncoder}; use crate::h3::qpack::table::Field; + use crate::test_util::decode; #[test] - fn test() { - let mut encoder = QpackEncoder::with_capacity(4096, &mut [0u8; 1024], 0); + fn ut_qpack_encoder() { + rfc9204_test_cases(); + macro_rules! qpack_test_cases { + ($enc: expr,$encoder_buf:expr,$encoder_cur:expr, $len: expr, $res: literal,$encoder_res: literal, $size: expr, { $($h: expr, $v: expr $(,)?)*} $(,)?) => { + let mut _encoder = $enc; + let mut stream_buf = [0u8; $len]; + let mut stream_cur = 0; + println!("size: {}", _encoder.table.size()); + $( + let mut parts = Parts::new(); + parts.update($h, $v); + _encoder.set_parts(parts); + let (mut cur1,mut cur2,_) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]); + $encoder_cur += cur1; + stream_cur += cur2; + )* + let (mut cur1,mut cur2,mut prefix) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]); + $encoder_cur += cur1; + stream_cur += cur2; + if let Some((prefix_buf,cur_prefix)) = prefix{ + stream_buf.copy_within(0..stream_cur,cur_prefix); + stream_buf[..cur_prefix].copy_from_slice(&prefix_buf[..cur_prefix]); + stream_cur += cur_prefix; + } + let result = decode($res).unwrap(); + println!("stream_cur: {:#?}", stream_cur); + println!("stream buf: {:#?}", stream_buf); + println!("stream result: {:#?}", result); + println!("encoder buf: {:#?}", $encoder_buf[..$encoder_cur].to_vec().as_slice()); + if let Some(res) = decode($encoder_res){ + println!("encoder result: {:#?}", res); + assert_eq!($encoder_buf[..$encoder_cur].to_vec().as_slice(), res.as_slice()); + } + assert_eq!(stream_cur, $len); + assert_eq!(stream_buf.as_slice(), result.as_slice()); + assert_eq!(_encoder.table.size(), $size); + } + } + + /// The following test cases are from RFC9204. + fn rfc9204_test_cases() { + literal_field_line_with_name_reference(); + dynamic_table(); + speculative_insert(); + duplicate_instruction_stream_cancellation(); + dynamic_table_insert_eviction(); + + /// The encoder sends an encoded field section containing a literal representation of a field with a static name reference. + fn literal_field_line_with_name_reference() { + let mut encoder_buf = [0u8; 1024]; + let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(0, &mut encoder_buf[..], 0, false,0); + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 15, "0000510b2f696e6465782e68746d6c", + "20", + 0, + { + Field::Path, + String::from("/index.html"), + }, + ); + } + + ///The encoder sets the dynamic table capacity, inserts a header with a dynamic name + /// reference, then sends a potentially blocking, encoded field section referencing + /// this new entry. The decoder acknowledges processing the encoded field section, + /// which implicitly acknowledges all dynamic table insertions up to the Required + /// Insert Count. + fn dynamic_table() { + let mut encoder_buf = [0u8; 1024]; + let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true,0); + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 4, "03811011", + "3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468", + 106, + { + Field::Authority, + String::from("www.example.com"), + Field::Path, + String::from("/sample/path"), + }, + ); + } + + ///The encoder inserts a header into the dynamic table with a literal name. + /// The decoder acknowledges receipt of the entry. The encoder does not send any + /// encoded field sections. + fn speculative_insert() { + let mut encoder_buf = [0u8; 1024]; + let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true,0); + encoder_cur = 0; + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 3, "028010", + "4a637573746f6d2d6b65790c637573746f6d2d76616c7565", + 54, + { + Field::Other(String::from("custom-key")), + String::from("custom-value"), + }, + ); + } + + /// ## About the setting of Base in RFC 9204 + /// (1). From RFC: If the encoder inserted entries in the dynamic table while encoding the field + /// section and is referencing them, Required Insert Count will be greater than the Base. + /// (2). From RFC: An encoder that produces table updates before encoding a field section might + /// set Base to the value of Required Insert Count. In such a case, both the Sign bit + /// and the Delta Base will be set to zero. + /// ## My implementation + /// I utilize the above condition (1), and the base is set to the count of decoder known entries(known receive count). + /// Just As the above test: `dynamic_table()` is same as RFC 9204. + /// But, the following test utilized the (2), So, it is something different from RFC 9204. because the above reason. + + fn duplicate_instruction_stream_cancellation(){ + let mut encoder_buf = [0u8; 1024]; + let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true,1); + encoder.table.update(Field::Authority,String::from("www.example.com")); + encoder.table.update(Field::Path,String::from("/sample/path")); + encoder.table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); + encoder.table.ref_count.insert(0, 0); //Acked + encoder.table.ref_count.insert(1, 0); //Acked + encoder.table.ref_count.insert(2, 0); //Acked + encoder.table.known_received_count = 3; + encoder_cur = 0; + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 5, "058010c180", + "02", + 217, + { + Field::Authority, + String::from("www.example.com"), + Field::Path, + String::from("/"), + Field::Other(String::from("custom-key")), + String::from("custom-value") + }, + ); + } + + fn dynamic_table_insert_eviction(){ + let mut encoder_buf = [0u8; 1024]; + let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true,1); + encoder.table.update(Field::Authority,String::from("www.example.com")); + encoder.table.update(Field::Path,String::from("/sample/path")); + encoder.table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); + encoder.table.update(Field::Authority,String::from("www.example.com")); + encoder.table.ref_count.insert(0, 0); //Acked + encoder.table.ref_count.insert(1, 0); //Acked + encoder.table.ref_count.insert(2, 0); //Acked + encoder.table.known_received_count = 3; + encoder_cur = 0; + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 3, "068111", + "810d637573746f6d2d76616c756532", + 272, + { + Field::Other(String::from("custom-key")), + String::from("custom-value2") + }, + ); + } + + } } } \ 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 index 6f9ee60..4a17ec1 100644 --- a/ylong_http/src/h3/qpack/format/encoder.rs +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -2,6 +2,7 @@ use std::arch::asm; use std::cmp::{max, Ordering}; use std::collections::{HashMap, VecDeque}; use std::result; +use std::sync::Arc; use crate::h3::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; use crate::h3::error::H3Error; use crate::h3::parts::Parts; @@ -16,17 +17,18 @@ pub(crate) struct ReprEncoder<'a> { table: &'a mut DynamicTable, iter: Option, state: Option, + draining_index: usize, } impl<'a> ReprEncoder<'a> { /// Creates a new, empty `ReprEncoder`. - pub(crate) fn new(table: &'a mut DynamicTable) -> Self { + pub(crate) fn new(table: &'a mut DynamicTable, draining_index: usize) -> Self { Self { table, iter: None, state: None, - + draining_index, } } @@ -44,15 +46,20 @@ impl<'a> ReprEncoder<'a> { /// 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) { + pub(crate) fn encode(&mut self, encoder_buffer: &mut [u8], + stream_buffer: &mut [u8], + stream_reference: &mut VecDeque>, + is_insert: &mut bool, + allow_post: bool, + ) -> (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); + 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 mut stream_result: Result = Result::Ok(0); + let mut encoder_result: Result = Result::Ok(0); let static_index = searcher.find_index_static(&h, &v); if static_index != Some(TableIndex::None) { if let Some(TableIndex::Field(index)) = static_index { @@ -60,35 +67,61 @@ impl<'a> ReprEncoder<'a> { stream_result = Indexed::new(index, true).encode(&mut stream_buffer[cur_stream..]); } } else { - let dynamic_index = searcher.find_index_dynamic(&h, &v); + let mut 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 dynamic_index == Some(TableIndex::None) || !self.should_index(&dynamic_index) { + // if index is close to eviction, drop it and use duplicate + let dyn_index = dynamic_index.clone(); + 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..]) + if self.table.have_enough_space(&h, &v) { + *is_insert = true; + println!("should_index: {}", self.should_index(&dyn_index)); + if !self.should_index(&dyn_index) { + if let Some(TableIndex::Field(index)) = dyn_index { + encoder_result = Duplicate::new(self.table.insert_count - index.clone() - 1).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..]) + } else { + encoder_result = match (&static_name_index, &dynamic_name_index, self.should_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)), true) => { + // 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..]) + } + // Duplicate + (_, Some(TableIndex::FieldName(index)), false) => { + Duplicate::new(index.clone()).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 self.table.size() + h.len() + v.len() + 32 >= self.table.capacity() { + self.draining_index += 1; + } + let index = self.table.update(h.clone(), v.clone()); + if allow_post { + if let Some(TableIndex::Field(x)) = index { + dynamic_index = Some(TableIndex::Field(x)); + } + if let Some(TableIndex::FieldName(index)) = index { + dynamic_name_index = Some(TableIndex::FieldName(index)); + } + } } } + if dynamic_index == Some(TableIndex::None) { if dynamic_name_index != Some(TableIndex::None) { //Encode with name reference in dynamic table @@ -104,7 +137,6 @@ impl<'a> ReprEncoder<'a> { 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 @@ -119,16 +151,15 @@ impl<'a> ReprEncoder<'a> { } else { assert!(dynamic_index != Some(TableIndex::None)); // Encode with index in dynamic table - if let Some(TableIndex::FieldName(index)) = dynamic_name_index { + if let Some(TableIndex::Field(index)) = dynamic_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{ + if self.table.known_received_count <= index { stream_result = IndexedWithPostName::new(index - self.table.known_received_count).encode(&mut stream_buffer[cur_stream..]); - } - else { + } else { stream_result = Indexed::new(self.table.known_received_count - index - 1, false).encode(&mut stream_buffer[cur_stream..]); } } @@ -160,6 +191,7 @@ impl<'a> ReprEncoder<'a> { } } } + (cur_encoder, cur_stream) } /// ## 2.1.1.1. Avoiding Prohibited Insertions @@ -189,14 +221,28 @@ impl<'a> ReprEncoder<'a> { /// | | | /// 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) fn should_index(&self, index: &Option) -> bool { + match index { + Some(TableIndex::Field(x)) => { + if *x < self.draining_index { + return false; + } + return true; + } + Some(TableIndex::FieldName(x)) => { + if *x < self.draining_index { + return false; + } + return true; + } + _ => { + return true; + } + } } } - pub(crate) struct ReprEncStateHolder { iter: Option, state: Option, @@ -231,8 +277,28 @@ pub(crate) enum ReprEncodeState { IndexingWithPostName(IndexingWithPostName), IndexingWithLiteral(IndexingWithLiteral), IndexedWithPostName(IndexedWithPostName), + Duplicate(Duplicate), } +pub(crate) struct Duplicate { + index: Integer, +} + +impl Duplicate { + fn from(index: Integer) -> Self { + Self { index } + } + + fn new(index: usize) -> Self { + Self { index: Integer::index(0x00, index, PrefixMask::DUPLICATE.0) } + } + + fn encode(self, dst: &mut [u8]) -> Result { + self.index + .encode(dst) + .map_err(|e| ReprEncodeState::Duplicate(Duplicate::from(e))) + } +} pub(crate) struct Indexed { index: Integer, @@ -260,6 +326,7 @@ impl Indexed { } } + pub(crate) struct IndexedWithPostName { index: Integer, } @@ -606,10 +673,11 @@ state_def!( DecoderInstruction, DecInstIndex ); -pub(crate) struct DecInstDecoder<'a>{ +pub(crate) struct DecInstDecoder<'a> { buf: &'a [u8], state: Option, } + pub(crate) struct InstDecStateHolder { state: Option, } @@ -623,6 +691,7 @@ impl InstDecStateHolder { self.state.is_none() } } + impl<'a> DecInstDecoder<'a> { pub(crate) fn new(buf: &'a [u8]) -> Self { Self { buf, state: None } @@ -660,8 +729,9 @@ impl<'a> DecInstDecoder<'a> { state_def!(DecInstIndexInner, (DecoderInstPrefixBit, usize), InstFirstByte, InstTrailingBytes); pub(crate) struct DecInstIndex { - inner: DecInstIndexInner + inner: DecInstIndexInner, } + impl DecInstIndex { fn new() -> Self { Self::from_inner(InstFirstByte.into()) @@ -672,10 +742,10 @@ impl DecInstIndex { 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(DecoderInstruction::Ack { stream_id: index }) } DecResult::Decoded((DecoderInstPrefixBit::STREAMCANCEL, index)) => { - DecResult::Decoded(DecoderInstruction::StreamCancel { stream_id:index }) + DecResult::Decoded(DecoderInstruction::StreamCancel { stream_id: index }) } DecResult::Decoded((DecoderInstPrefixBit::INSERTCOUNTINCREMENT, index)) => { DecResult::Decoded(DecoderInstruction::InsertCountIncrement { increment: index }) diff --git a/ylong_http/src/h3/qpack/mod.rs b/ylong_http/src/h3/qpack/mod.rs index 82a2986..d25cf52 100644 --- a/ylong_http/src/h3/qpack/mod.rs +++ b/ylong_http/src/h3/qpack/mod.rs @@ -136,6 +136,7 @@ impl ReprPrefixBit { /// 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 { + println!("process mid: {:b}", byte); 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 }, diff --git a/ylong_http/src/h3/qpack/table.rs b/ylong_http/src/h3/qpack/table.rs index ae15872..4488ac1 100644 --- a/ylong_http/src/h3/qpack/table.rs +++ b/ylong_http/src/h3/qpack/table.rs @@ -49,7 +49,7 @@ impl<'a> TableSearcher<'a> { } pub(crate) fn find_index_name_dynamic(&self, header: &Field, value: &str) -> Option { - match self.dynamic.index(header, value) { + match self.dynamic.index_name(header, value) { x @ Some(TableIndex::FieldName(_)) => x, _ => Some(TableIndex::None), } @@ -117,11 +117,16 @@ impl DynamicTable { self.capacity / 32 } /// Updates `DynamicTable` by a given `Header` and value pair. - pub(crate) fn update(&mut self, field: Field, value: String) { + pub(crate) fn update(&mut self, field: Field, value: String)-> Option { + self.insert_count += 1; self.size += field.len() + value.len() + 32; - self.queue.push_back((field, value)); + self.queue.push_back((field.clone(), value.clone())); self.ref_count.insert(self.queue.len() + self.remove_count - 1, 0); self.fit_size(); + match self.index(&field, &value) { + x => x, + _ => Some(TableIndex::None), + } } pub(crate) fn have_enough_space(&self, field: &Field, value: &String) -> bool { @@ -164,11 +169,24 @@ impl DynamicTable { /// Tries get the index of a `Header`. fn index(&self, header: &Field, value: &str) -> Option { + // find latest + let mut index = None; + for (n, (h, v)) in self.queue.iter().enumerate() { + match (header == h, value == v, &index) { + (true, true, _) => index = Some(TableIndex::Field(n + self.remove_count)), + _ => {} + } + } + index + } + + + fn index_name(&self, header: &Field, value: &str) -> Option { + // find latest 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)), + (true, _, _) => index = Some(TableIndex::FieldName(n + self.remove_count)), _ => {} } } @@ -185,7 +203,7 @@ impl DynamicTable { } -#[derive(PartialEq)] +#[derive(PartialEq, Clone)] pub(crate) enum TableIndex { Field(usize), FieldName(usize), @@ -367,6 +385,7 @@ impl StaticTable { match (field, value) { (Field::Authority, _) => Some(TableIndex::FieldName(0)), (Field::Path, "/") => Some(TableIndex::Field(1)), + (Field::Path, _) => Some(TableIndex::FieldName(1)), (Field::Method, "CONNECT") => Some(TableIndex::Field(15)), (Field::Method, "DELETE") => Some(TableIndex::Field(16)), (Field::Method, "GET") => Some(TableIndex::Field(17)), @@ -374,8 +393,10 @@ impl StaticTable { (Field::Method, "OPTIONS") => Some(TableIndex::Field(19)), (Field::Method, "POST") => Some(TableIndex::Field(20)), (Field::Method, "PUT") => Some(TableIndex::Field(21)), + (Field::Method, _) => Some(TableIndex::FieldName(15)), (Field::Scheme, "http") => Some(TableIndex::Field(22)), (Field::Scheme, "https") => Some(TableIndex::Field(23)), + (Field::Scheme, _) => Some(TableIndex::FieldName(22)), (Field::Status, "103") => Some(TableIndex::Field(24)), (Field::Status, "200") => Some(TableIndex::Field(25)), (Field::Status, "304") => Some(TableIndex::Field(26)), @@ -390,10 +411,13 @@ impl StaticTable { (Field::Status, "421") => Some(TableIndex::Field(69)), (Field::Status, "425") => Some(TableIndex::Field(70)), (Field::Status, "500") => Some(TableIndex::Field(71)), + (Field::Status, _) => Some(TableIndex::FieldName(24)), (Field::Other(s), v) => match (s.as_str(), v) { ("age", "0") => Some(TableIndex::Field(2)), + ("age", _) => Some(TableIndex::FieldName(2)), ("content-disposition", _) => Some(TableIndex::FieldName(3)), ("content-length", "0") => Some(TableIndex::Field(4)), + ("content-length", _) => Some(TableIndex::FieldName(4)), ("cookie", _) => Some(TableIndex::FieldName(5)), ("date", _) => Some(TableIndex::FieldName(6)), ("etag", _) => Some(TableIndex::FieldName(7)), @@ -406,19 +430,26 @@ impl StaticTable { ("set-cookie", _) => Some(TableIndex::FieldName(14)), ("accept", "*/*") => Some(TableIndex::Field(29)), ("accept", "application/dns-message") => Some(TableIndex::Field(30)), + ("accept", _) => Some(TableIndex::FieldName(29)), ("accept-encoding", "gzip, deflate, br") => Some(TableIndex::Field(31)), + ("accept-encoding", _) => Some(TableIndex::FieldName(31)), ("accept-ranges", "bytes") => Some(TableIndex::Field(32)), + ("accept-ranges", _) => Some(TableIndex::FieldName(32)), ("access-control-allow-headers", "cache-control") => Some(TableIndex::Field(33)), ("access-control-allow-headers", "content-type") => Some(TableIndex::Field(34)), + ("access-control-allow-headers", _) => Some(TableIndex::FieldName(33)), ("access-control-allow-origin", "*") => Some(TableIndex::Field(35)), + ("access-control-allow-origin", _) => Some(TableIndex::FieldName(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)), + ("cache-control", _) => Some(TableIndex::FieldName(36)), ("content-encoding", "br") => Some(TableIndex::Field(42)), ("content-encoding", "gzip") => Some(TableIndex::Field(43)), + ("content-encoding", _) => Some(TableIndex::FieldName(42)), ("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)), @@ -430,41 +461,60 @@ impl StaticTable { ("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)), + ("content-type", _) => Some(TableIndex::FieldName(44)), ("range", "bytes=0-") => Some(TableIndex::Field(55)), + ("range", _) => Some(TableIndex::FieldName(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)), + ("strict-transport-security", _) => Some(TableIndex::FieldName(56)), ("vary", "accept-encoding") => Some(TableIndex::Field(59)), ("vary", "origin") => Some(TableIndex::Field(60)), + ("vary", _) => Some(TableIndex::FieldName(59)), ("x-content-type-options", "nosniff") => Some(TableIndex::Field(61)), + ("x-content-type-options", _) => Some(TableIndex::FieldName(61)), ("x-xss-protection", "1; mode=block") => Some(TableIndex::Field(62)), + ("x-xss-protection", _) => Some(TableIndex::FieldName(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-credentials", _) => Some(TableIndex::FieldName(73)), ("access-control-allow-headers", "*") => Some(TableIndex::Field(75)), + ("access-control-allow-headers", _) => Some(TableIndex::FieldName(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-allow-methods", _) => Some(TableIndex::FieldName(76)), ("access-control-expose-headers", "content-length") => Some(TableIndex::Field(79)), + ("access-control-expose-headers", _) => Some(TableIndex::FieldName(79)), ("access-control-request-headers", "content-type") => Some(TableIndex::Field(80)), + ("access-control-request-headers", _) => Some(TableIndex::FieldName(80)), ("access-control-request-method", "get") => Some(TableIndex::Field(81)), ("access-control-request-method", "post") => Some(TableIndex::Field(82)), + ("access-control-request-method", _) => Some(TableIndex::FieldName(81)), ("alt-svc", "clear") => Some(TableIndex::Field(83)), + ("alt-svc", _) => Some(TableIndex::FieldName(83)), ("authorization", _) => Some(TableIndex::FieldName(84)), ("content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'") => Some(TableIndex::Field(85)), + ("content-security-policy", _) => Some(TableIndex::FieldName(85)), ("early-data", "1") => Some(TableIndex::Field(86)), + ("early-data", _) => Some(TableIndex::FieldName(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)), + ("purpose", _) => Some(TableIndex::FieldName(91)), ("server", _) => Some(TableIndex::FieldName(92)), ("timing-allow-origin", "*") => Some(TableIndex::Field(93)), + ("timing-allow-origin", _) => Some(TableIndex::FieldName(93)), ("upgrade-insecure-requests", "1") => Some(TableIndex::Field(94)), + ("upgrade-insecure-requests", _) => Some(TableIndex::FieldName(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)), + ("x-frame-options", _) => Some(TableIndex::FieldName(97)), _ => None, }, _ => None, -- Gitee From 2c37eb731083a99ee793d1e80c807787669271b3 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Wed, 23 Aug 2023 09:57:49 +0800 Subject: [PATCH 3/8] qpack Signed-off-by: Weng Shihao --- ylong_http/src/h3/error.rs | 12 ++++++ ylong_http/src/h3/parts.rs | 13 ++++++- ylong_http/src/h3/qpack/decoder.rs | 47 +++++++---------------- ylong_http/src/h3/qpack/encoder.rs | 21 +++++----- ylong_http/src/h3/qpack/format/decoder.rs | 14 ++++++- ylong_http/src/h3/qpack/format/encoder.rs | 15 ++++++-- ylong_http/src/h3/qpack/format/mod.rs | 12 ++++++ ylong_http/src/h3/qpack/integer.rs | 12 ++++++ ylong_http/src/h3/qpack/mod.rs | 15 +++++++- ylong_http/src/h3/qpack/table.rs | 13 +++++++ 10 files changed, 124 insertions(+), 50 deletions(-) diff --git a/ylong_http/src/h3/error.rs b/ylong_http/src/h3/error.rs index 11de8bd..d63ebe1 100644 --- a/ylong_http/src/h3/error.rs +++ b/ylong_http/src/h3/error.rs @@ -1,3 +1,15 @@ +// 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. pub enum H3Error { //todo: add more ConnectionError(ErrorCode), diff --git a/ylong_http/src/h3/parts.rs b/ylong_http/src/h3/parts.rs index 7bd4979..3a293c1 100644 --- a/ylong_http/src/h3/parts.rs +++ b/ylong_http/src/h3/parts.rs @@ -1,4 +1,15 @@ - +// 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. use crate::h3::pseudo::PseudoHeaders; use crate::headers::Headers; diff --git a/ylong_http/src/h3/qpack/decoder.rs b/ylong_http/src/h3/qpack/decoder.rs index a015f0d..4329f55 100644 --- a/ylong_http/src/h3/qpack/decoder.rs +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -1,3 +1,16 @@ +// 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. + use std::mem::take; use crate::h3::error::ErrorCode::{QPACK_DECOMPRESSION_FAILED, QPACK_ENCODER_STREAM_ERROR}; use crate::h3::error::H3Error; @@ -50,21 +63,15 @@ impl<'a> QpackDecoder<'a> { 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!("InsertWithIndex 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!("InsertWithLiteral value: {}", value_str); updater.update_table(mid_bit, name, value)?; } EncoderInstruction::Duplicate { index } => { - println!("Duplicate index: {}", index); updater.duplicate(index)?; } } @@ -102,54 +109,31 @@ impl<'a> QpackDecoder<'a> { 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; - println!("self.require_insert_count: {}", self.require_insert_count); if self.require_insert_count > max_value { self.require_insert_count -= full_range; } } - println!("require_insert_count: {}", self.require_insert_count); - println!("signal: {}", signal); - println!("delta_base: {}", delta_base.0); if signal { self.base = self.require_insert_count - delta_base.0 - 1; } else { self.base = self.require_insert_count + delta_base.0; } - println!("base: {}", self.base); 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)?; } } @@ -319,7 +303,6 @@ impl<'a> Searcher<'a> { let (f, v) = table_searcher .find_field_dynamic(self.base + index) .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; - print!("search_res: {:#?}", v); self.check_field_list_size(&f, &v)?; self.lines.parts.update(f, v); return Ok(()); @@ -438,7 +421,6 @@ mod ut_qpack_decoder { ($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]; @@ -527,7 +509,6 @@ mod ut_qpack_decoder { ); } fn duplicate_instruction_stream_cancellation() { - println!("duplicate_instruction_stream_cancellation"); let mut dynamic_table = DynamicTable::with_capacity(4096); dynamic_table.update(Field::Authority,String::from("www.example.com")); dynamic_table.update(Field::Path,String::from("/sample/path")); @@ -682,9 +663,7 @@ mod ut_qpack_decoder { 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 index 337fedc..7039f72 100644 --- a/ylong_http/src/h3/qpack/encoder.rs +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -1,3 +1,15 @@ +// 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. use std::collections::{HashMap, VecDeque}; use crate::h3::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; use crate::h3::error::H3Error; @@ -51,7 +63,6 @@ impl QpackEncoder { 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(); @@ -71,12 +82,10 @@ impl QpackEncoder { 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; } } @@ -182,7 +191,6 @@ mod ut_qpack_encoder { let mut _encoder = $enc; let mut stream_buf = [0u8; $len]; let mut stream_cur = 0; - println!("size: {}", _encoder.table.size()); $( let mut parts = Parts::new(); parts.update($h, $v); @@ -200,12 +208,7 @@ mod ut_qpack_encoder { stream_cur += cur_prefix; } let result = decode($res).unwrap(); - println!("stream_cur: {:#?}", stream_cur); - println!("stream buf: {:#?}", stream_buf); - println!("stream result: {:#?}", result); - println!("encoder buf: {:#?}", $encoder_buf[..$encoder_cur].to_vec().as_slice()); if let Some(res) = decode($encoder_res){ - println!("encoder result: {:#?}", res); assert_eq!($encoder_buf[..$encoder_cur].to_vec().as_slice(), res.as_slice()); } assert_eq!(stream_cur, $len); diff --git a/ylong_http/src/h3/qpack/format/decoder.rs b/ylong_http/src/h3/qpack/format/decoder.rs index 5f1cc48..1c65ba2 100644 --- a/ylong_http/src/h3/qpack/format/decoder.rs +++ b/ylong_http/src/h3/qpack/format/decoder.rs @@ -1,3 +1,15 @@ +// 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. use std::cmp::Ordering; use crate::h3::error::{ErrorCode, H3Error}; use crate::h3::error::ErrorCode::QPACK_DECOMPRESSION_FAILED; @@ -33,7 +45,6 @@ impl<'a> EncInstDecoder<'a> { // `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) } @@ -82,7 +93,6 @@ impl<'a> ReprDecoder<'a> { // `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) } diff --git a/ylong_http/src/h3/qpack/format/encoder.rs b/ylong_http/src/h3/qpack/format/encoder.rs index 4a17ec1..c6f874f 100644 --- a/ylong_http/src/h3/qpack/format/encoder.rs +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -1,3 +1,15 @@ +// 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. use std::arch::asm; use std::cmp::{max, Ordering}; use std::collections::{HashMap, VecDeque}; @@ -57,7 +69,6 @@ impl<'a> ReprEncoder<'a> { 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::Ok(0); let mut encoder_result: Result = Result::Ok(0); let static_index = searcher.find_index_static(&h, &v); @@ -81,7 +92,6 @@ impl<'a> ReprEncoder<'a> { if self.table.have_enough_space(&h, &v) { *is_insert = true; - println!("should_index: {}", self.should_index(&dyn_index)); if !self.should_index(&dyn_index) { if let Some(TableIndex::Field(index)) = dyn_index { encoder_result = Duplicate::new(self.table.insert_count - index.clone() - 1).encode(&mut encoder_buffer[cur_encoder..]); @@ -714,7 +724,6 @@ impl<'a> DecInstDecoder<'a> { // `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) } diff --git a/ylong_http/src/h3/qpack/format/mod.rs b/ylong_http/src/h3/qpack/format/mod.rs index f7ae841..6a59097 100644 --- a/ylong_http/src/h3/qpack/format/mod.rs +++ b/ylong_http/src/h3/qpack/format/mod.rs @@ -1,3 +1,15 @@ +// 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. pub(crate) mod encoder; pub(crate) mod decoder; diff --git a/ylong_http/src/h3/qpack/integer.rs b/ylong_http/src/h3/qpack/integer.rs index 9551bb1..70fc014 100644 --- a/ylong_http/src/h3/qpack/integer.rs +++ b/ylong_http/src/h3/qpack/integer.rs @@ -1,3 +1,15 @@ +// 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. use std::cmp::Ordering; use crate::h3::error::{ErrorCode, H3Error}; diff --git a/ylong_http/src/h3/qpack/mod.rs b/ylong_http/src/h3/qpack/mod.rs index d25cf52..0a997fd 100644 --- a/ylong_http/src/h3/qpack/mod.rs +++ b/ylong_http/src/h3/qpack/mod.rs @@ -1,3 +1,17 @@ +// 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. + + pub(crate) mod table; mod encoder; mod format; @@ -136,7 +150,6 @@ impl ReprPrefixBit { /// 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 { - println!("process mid: {:b}", byte); 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 }, diff --git a/ylong_http/src/h3/qpack/table.rs b/ylong_http/src/h3/qpack/table.rs index 4488ac1..f3c212c 100644 --- a/ylong_http/src/h3/qpack/table.rs +++ b/ylong_http/src/h3/qpack/table.rs @@ -1,3 +1,16 @@ +// 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. + use std::collections::{HashMap, VecDeque}; /// The [`Dynamic Table`][dynamic_table] implementation of [QPACK]. -- Gitee From 2166211fcd0e491de4f08099af84e37500cdeaf4 Mon Sep 17 00:00:00 2001 From: Weng Shihao Date: Wed, 30 Aug 2023 09:42:37 +0800 Subject: [PATCH 4/8] qpack Signed-off-by: Weng Shihao --- ylong_http/Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ylong_http/Cargo.toml b/ylong_http/Cargo.toml index 195f1b6..703f904 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","huffman","http3"] +default = ["http1_1", "tokio_base", "huffman", "http3"] full = [ "http1_1", "http2", -- Gitee From 67507226db218b0b5bb1eff846b32edb2bd951f8 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Wed, 13 Sep 2023 01:34:49 +0800 Subject: [PATCH 5/8] Extract pseudo and modify Signed-off-by: Weng Shihao --- ylong_http/Cargo.toml | 4 +- ylong_http/src/h2/decoder.rs | 20 +- ylong_http/src/h2/encoder.rs | 30 +- ylong_http/src/h2/hpack/decoder.rs | 42 +- ylong_http/src/h2/mod.rs | 3 +- ylong_http/src/h2/parts.rs | 12 +- ylong_http/src/h3/mod.rs | 4 +- ylong_http/src/h3/parts.rs | 18 +- ylong_http/src/h3/pseudo.rs | 506 -------------- ylong_http/src/h3/qpack/decoder.rs | 543 ++++++++++----- ylong_http/src/h3/qpack/encoder.rs | 281 ++++---- ylong_http/src/h3/{ => qpack}/error.rs | 5 +- ylong_http/src/h3/qpack/format/decoder.rs | 801 +++++++++++++--------- ylong_http/src/h3/qpack/format/encoder.rs | 397 +++++------ ylong_http/src/h3/qpack/format/mod.rs | 7 +- ylong_http/src/h3/qpack/integer.rs | 11 +- ylong_http/src/h3/qpack/mod.rs | 134 +++- ylong_http/src/h3/qpack/table.rs | 300 ++++++-- ylong_http/src/lib.rs | 1 + ylong_http/src/{h2 => }/pseudo.rs | 231 +------ 20 files changed, 1595 insertions(+), 1755 deletions(-) delete mode 100644 ylong_http/src/h3/pseudo.rs rename ylong_http/src/h3/{ => qpack}/error.rs (95%) rename ylong_http/src/{h2 => }/pseudo.rs (57%) diff --git a/ylong_http/Cargo.toml b/ylong_http/Cargo.toml index 195f1b6..4f512e7 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","huffman","http3"] +default = ["http1_1", "http2", "tokio_base","huffman","http3"] full = [ "http1_1", "http2", @@ -27,7 +27,7 @@ ylong_base = [] # Uses asynchronous components of `ylong` [dependencies] tokio = { version = "1.20.1", features = ["io-util"], optional = true } -# ylong_runtime = { path = "../runtime/ylong_runtime", optional = true } +ylong_runtime = { git = "https://gitee.com/openharmony-sig/commonlibrary_rust_ylong_runtime.git", optional = true } [dev-dependencies] tokio = { version = "1.20.1", features = ["io-util", "rt-multi-thread", "macros"] } diff --git a/ylong_http/src/h2/decoder.rs b/ylong_http/src/h2/decoder.rs index fdde469..f887333 100644 --- a/ylong_http/src/h2/decoder.rs +++ b/ylong_http/src/h2/decoder.rs @@ -915,33 +915,43 @@ mod ut_frame_decoder { match *key { ":method" => { assert_eq!( - pseudo.method().expect("pseudo.method get failed !"), + pseudo + .method + .clone() + .expect("pseudo.method get failed !"), *value ); } ":scheme" => { assert_eq!( - pseudo.scheme().expect("pseudo.scheme get failed !"), + pseudo + .scheme + .clone() + .expect("pseudo.scheme get failed !"), *value ); } ":authority" => { assert_eq!( pseudo - .authority() + .authority + .clone() .expect("pseudo.authority get failed !"), *value ); } ":path" => { assert_eq!( - pseudo.path().expect("pseudo.path get failed !"), + pseudo.path.clone().expect("pseudo.path get failed !"), *value ); } ":status" => { assert_eq!( - pseudo.status().expect("pseudo.status get failed !"), + pseudo + .status + .clone() + .expect("pseudo.status get failed !"), *value ); } diff --git a/ylong_http/src/h2/encoder.rs b/ylong_http/src/h2/encoder.rs index b6fde06..94aa3a1 100644 --- a/ylong_http/src/h2/encoder.rs +++ b/ylong_http/src/h2/encoder.rs @@ -1240,12 +1240,10 @@ mod ut_frame_encoder { let mut frame_encoder = FrameEncoder::new(4096, 8190); let mut new_parts = Parts::new(); - new_parts.pseudo.set_method(Some("GET".to_string())); - new_parts.pseudo.set_scheme(Some("https".to_string())); - new_parts.pseudo.set_path(Some("/code".to_string())); - new_parts - .pseudo - .set_authority(Some("example.com".to_string())); + new_parts.pseudo.method = Some("GET".to_string()); + new_parts.pseudo.scheme = Some("https".to_string()); + new_parts.pseudo.path = Some("/code".to_string()); + new_parts.pseudo.authority = Some("example.com".to_string()); let mut frame_flag = FrameFlags::empty(); frame_flag.set_end_headers(true); frame_flag.set_end_stream(true); @@ -1398,12 +1396,10 @@ mod ut_frame_encoder { let mut encoder = FrameEncoder::new(4096, 8190); let mut new_parts = Parts::new(); - new_parts.pseudo.set_method(Some("GET".to_string())); - new_parts.pseudo.set_scheme(Some("https".to_string())); - new_parts.pseudo.set_path(Some("/code".to_string())); - new_parts - .pseudo - .set_authority(Some("example.com".to_string())); + new_parts.pseudo.method = Some("GET".to_string()); + new_parts.pseudo.scheme = Some("https".to_string()); + new_parts.pseudo.path = Some("/code".to_string()); + new_parts.pseudo.authority = Some("example.com".to_string()); let mut frame_flag = FrameFlags::empty(); frame_flag.set_end_headers(true); frame_flag.set_end_stream(false); @@ -1711,12 +1707,10 @@ mod ut_frame_encoder { let mut frame_encoder = FrameEncoder::new(4096, 8190); let mut new_parts = Parts::new(); assert!(new_parts.is_empty()); - new_parts.pseudo.set_method(Some("GET".to_string())); - new_parts.pseudo.set_scheme(Some("https".to_string())); - new_parts.pseudo.set_path(Some("/code".to_string())); - new_parts - .pseudo - .set_authority(Some("example.com".to_string())); + new_parts.pseudo.method = Some("GET".to_string()); + new_parts.pseudo.scheme = Some("https".to_string()); + new_parts.pseudo.path = Some("/code".to_string()); + new_parts.pseudo.authority = Some("example.com".to_string()); let mut frame_flag = FrameFlags::empty(); frame_flag.set_end_headers(false); diff --git a/ylong_http/src/h2/hpack/decoder.rs b/ylong_http/src/h2/hpack/decoder.rs index 8022c9b..a90ec59 100644 --- a/ylong_http/src/h2/hpack/decoder.rs +++ b/ylong_http/src/h2/hpack/decoder.rs @@ -229,11 +229,11 @@ mod ut_hpack_decoder { $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); + 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); }; } @@ -335,7 +335,7 @@ mod ut_hpack_decoder { hpack_test_case!( HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE), "040c2f73616d706c652f70617468", - { None, None, Some("/sample/path"), None, None }, + { None, None, Some(String::from("/sample/path")), None, None }, { 0 } ); @@ -351,7 +351,7 @@ mod ut_hpack_decoder { hpack_test_case!( HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE), "82", - { None, Some("GET"), None, None, None }, + { None, Some(String::from("GET")), None, None, None }, { 0 } ); @@ -362,7 +362,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684410f7777772e6578616d706c652e636f6d", - { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, + { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, { 57, Authority => "www.example.com" } ); @@ -370,7 +370,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684be58086e6f2d6361636865", - { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, + { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, { "cache-control" => "no-cache" }, { 110, "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -379,7 +379,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565", - { Some("www.example.com"), Some("GET"), Some("/index.html"), Some("https"), None }, + { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/index.html")), Some(String::from("https")), None }, { "custom-key" => "custom-value" }, { 164, "custom-key" => "custom-value", "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -392,7 +392,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684418cf1e3c2e5f23a6ba0ab90f4ff", - { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, + { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, { 57, Authority => "www.example.com" } ); @@ -400,7 +400,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684be5886a8eb10649cbf", - { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, + { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, { "cache-control" => "no-cache" }, { 110, "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -409,7 +409,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf", - { Some("www.example.com"), Some("GET"), Some("/index.html"), Some("https"), None }, + { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/index.html")), Some(String::from("https")), None }, { "custom-key" => "custom-value" }, { 164, "custom-key" => "custom-value", "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -426,7 +426,7 @@ mod ut_hpack_decoder { 2032303a31333a323120474d546e1768\ 747470733a2f2f7777772e6578616d70\ 6c652e636f6d", - { None, None, None, None, Some("302") }, + { None, None, None, None, Some(String::from("302")) }, { "location" => "https://www.example.com", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -445,7 +445,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "4803333037c1c0bf", - { None, None, None, None, Some("307") }, + { None, None, None, None, Some(String::from("307")) }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -470,7 +470,7 @@ mod ut_hpack_decoder { 5541585157454f49553b206d61782d61\ 67653d333630303b2076657273696f6e\ 3d31", - { None, None, None, None, Some("200") }, + { None, None, None, None, Some(String::from("200")) }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:22 GMT", @@ -497,7 +497,7 @@ mod ut_hpack_decoder { 941054d444a8200595040b8166e082a6\ 2d1bff6e919d29ad171863c78f0b97c8\ e9ae82ae43d3", - { None, None, None, None, Some("302") }, + { None, None, None, None, Some(String::from("302")) }, { "location" => "https://www.example.com", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -516,7 +516,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "4883640effc1c0bf", - { None, None, None, None, Some("307") }, + { None, None, None, None, Some(String::from("307")) }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -539,7 +539,7 @@ mod ut_hpack_decoder { 77ad94e7821dd7f2e6c7b335dfdfcd5b\ 3960d5af27087f3672c1ab270fb5291f\ 9587316065c003ed4ee5b1063d5007", - { None, None, None, None, Some("200") }, + { None, None, None, None, Some(String::from("200")) }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:22 GMT", @@ -562,7 +562,7 @@ mod ut_hpack_decoder { hpack_test_case!( HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE), "04", "0c", "2f", "73", "61", "6d", "70", "6c", "65", "2f", "70", "61", "74", "68", - { None, None, Some("/sample/path"), None, None }, + { None, None, Some(String::from("/sample/path")), None, None }, { 0 } ); @@ -573,7 +573,7 @@ mod ut_hpack_decoder { "941054d444a8200595040b8166e082a6", "2d1bff6e919d29ad171863c78f0b97c8", "e9ae82ae43d3", - { None, None, None, None, Some("302") }, + { None, None, None, None, Some(String::from("302")) }, { "location" => "https://www.example.com", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", diff --git a/ylong_http/src/h2/mod.rs b/ylong_http/src/h2/mod.rs index 9bdadd7..4c352f6 100644 --- a/ylong_http/src/h2/mod.rs +++ b/ylong_http/src/h2/mod.rs @@ -56,8 +56,8 @@ mod error; mod frame; mod hpack; mod parts; -mod pseudo; +pub use crate::pseudo::PseudoHeaders; pub use decoder::{FrameDecoder, FrameKind, Frames, FramesIntoIter}; pub use encoder::FrameEncoder; pub use error::{ErrorCode, H2Error}; @@ -67,4 +67,3 @@ pub use frame::{ }; pub(crate) use hpack::{HpackDecoder, HpackEncoder}; pub use parts::Parts; -pub use pseudo::PseudoHeaders; diff --git a/ylong_http/src/h2/parts.rs b/ylong_http/src/h2/parts.rs index 8122ee7..af57477 100644 --- a/ylong_http/src/h2/parts.rs +++ b/ylong_http/src/h2/parts.rs @@ -12,8 +12,8 @@ // limitations under the License. use crate::h2::hpack::table::Header; -use crate::h2::pseudo::PseudoHeaders; use crate::headers::Headers; +use crate::pseudo::PseudoHeaders; /// HTTP2 HEADERS frame payload implementation. #[derive(PartialEq, Eq, Clone)] @@ -47,11 +47,11 @@ impl Parts { pub(crate) fn update(&mut self, headers: Header, value: String) { match headers { - Header::Authority => self.pseudo.set_authority(Some(value)), - Header::Method => self.pseudo.set_method(Some(value)), - Header::Path => self.pseudo.set_path(Some(value)), - Header::Scheme => self.pseudo.set_scheme(Some(value)), - Header::Status => self.pseudo.set_status(Some(value)), + Header::Authority => self.pseudo.authority = Some(value), + Header::Method => self.pseudo.method = Some(value), + Header::Path => self.pseudo.path = Some(value), + Header::Scheme => self.pseudo.scheme = Some(value), + Header::Status => self.pseudo.status = Some(value), Header::Other(header) => self.map.append(header.as_str(), value.as_str()).unwrap(), } } diff --git a/ylong_http/src/h3/mod.rs b/ylong_http/src/h3/mod.rs index 22272cd..61d62e5 100644 --- a/ylong_http/src/h3/mod.rs +++ b/ylong_http/src/h3/mod.rs @@ -13,7 +13,5 @@ // TODO: `HTTP/3` Module. -mod qpack; mod parts; -mod pseudo; -mod error; \ No newline at end of file +mod qpack; diff --git a/ylong_http/src/h3/parts.rs b/ylong_http/src/h3/parts.rs index 3a293c1..b263643 100644 --- a/ylong_http/src/h3/parts.rs +++ b/ylong_http/src/h3/parts.rs @@ -11,9 +11,9 @@ // See the License for the specific language governing permissions and // limitations under the License. -use crate::h3::pseudo::PseudoHeaders; -use crate::headers::Headers; use crate::h3::qpack::table::Field; +use crate::headers::Headers; +use crate::pseudo::PseudoHeaders; #[derive(PartialEq, Eq, Clone)] pub struct Parts { pub(crate) pseudo: PseudoHeaders, @@ -45,11 +45,11 @@ impl Parts { 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::Authority => self.pseudo.authority = Some(value), + Field::Method => self.pseudo.method = Some(value), + Field::Path => self.pseudo.path = Some(value), + Field::Scheme => self.pseudo.scheme = Some(value), + Field::Status => self.pseudo.status = Some(value), Field::Other(header) => self.map.append(header.as_str(), value.as_str()).unwrap(), } } @@ -63,10 +63,8 @@ impl Parts { } } - - 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 deleted file mode 100644 index b80ca75..0000000 --- a/ylong_http/src/h3/pseudo.rs +++ /dev/null @@ -1,506 +0,0 @@ -// 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 index 4329f55..0c97c11 100644 --- a/ylong_http/src/h3/qpack/decoder.rs +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -11,17 +11,22 @@ // See the License for the specific language governing permissions and // limitations under the License. -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::error::ErrorCode::{QPACK_DECOMPRESSION_FAILED, QPACK_ENCODER_STREAM_ERROR}; +use crate::h3::qpack::error::H3Error_QPACK; +use crate::h3::qpack::{ + DeltaBase, EncoderInstPrefixBit, EncoderInstruction, MidBit, ReprPrefixBit, Representation, + RequireInsertCount, +}; +use std::mem::take; -use crate::h3::qpack::format::decoder::{EncInstDecoder, InstDecStateHolder, Name, ReprDecoder, ReprDecStateHolder}; +use crate::h3::qpack::format::decoder::{ + EncInstDecoder, InstDecodeState, Name, ReprDecodeState, ReprDecoder, +}; use crate::h3::qpack::integer::Integer; +use crate::h3::qpack::table::Field::Path; use crate::h3::qpack::table::{DynamicTable, Field, TableSearcher}; - struct FiledLines { parts: Parts, header_size: usize, @@ -30,8 +35,8 @@ struct FiledLines { pub(crate) struct QpackDecoder<'a> { field_list_size: usize, table: &'a mut DynamicTable, - repr_holder: ReprDecStateHolder, - inst_holder: InstDecStateHolder, + repr_state: Option, + inst_state: Option, lines: FiledLines, base: usize, require_insert_count: usize, @@ -42,8 +47,8 @@ impl<'a> QpackDecoder<'a> { Self { field_list_size, table, - repr_holder: ReprDecStateHolder::new(), - inst_holder: InstDecStateHolder::new(), + repr_state: None, + inst_state: None, lines: FiledLines { parts: Parts::new(), header_size: 0, @@ -54,34 +59,50 @@ impl<'a> QpackDecoder<'a> { } /// 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); + pub(crate) fn decode_ins(&mut self, buf: &mut [u8]) -> Result<(), H3Error_QPACK> { + let mut decoder = EncInstDecoder::new(); let mut updater = Updater::new(&mut self.table); + let mut cnt = 0; loop { - match decoder.decode()? { - Some(inst) => { - match inst { - EncoderInstruction::SetCap { capacity } => { - updater.update_capacity(capacity)?; - } - EncoderInstruction::InsertWithIndex { mid_bit, name, value } => { - updater.update_table(mid_bit, name, value)?; - } - EncoderInstruction::InsertWithLiteral { mid_bit, name, value } => { - updater.update_table(mid_bit, name, value)?; - } - EncoderInstruction::Duplicate { index } => { - updater.duplicate(index)?; - } + match decoder.decode(&mut buf[cnt..], &mut self.inst_state)? { + Some(inst) => match inst { + (offset, EncoderInstruction::SetCap { capacity }) => { + println!("set cap"); + cnt += offset; + updater.update_capacity(capacity)?; } - } - None => return Result::Ok(()) + ( + offset, + EncoderInstruction::InsertWithIndex { + mid_bit, + name, + value, + }, + ) => { + cnt += offset; + updater.update_table(mid_bit, name, value)?; + } + ( + offset, + EncoderInstruction::InsertWithLiteral { + mid_bit, + name, + value, + }, + ) => { + cnt += offset; + updater.update_table(mid_bit, name, value)?; + } + (offset, EncoderInstruction::Duplicate { index }) => { + cnt += offset; + 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 /// +---+---+---+---+---+---+---+---+ @@ -91,56 +112,89 @@ impl<'a> QpackDecoder<'a> { /// +---+---------------------------+ /// | 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); - + pub(crate) fn decode_repr(&mut self, buf: &mut [u8]) -> Result<(), H3Error_QPACK> { + let mut decoder = ReprDecoder::new(); let mut searcher = Searcher::new(self.field_list_size, &self.table, &mut self.lines); + let mut cnt = 0; 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; - } - } - if signal { - self.base = self.require_insert_count - delta_base.0 - 1; - } else { - self.base = self.require_insert_count + delta_base.0; - } - searcher.base = self.base; - //todo:block - } - Representation::Indexed { mid_bit, index } => { - searcher.search(Representation::Indexed { mid_bit, index })?; - } - Representation::IndexedWithPostIndex { index } => { - searcher.search(Representation::IndexedWithPostIndex { index })?; - } - Representation::LiteralWithIndexing { mid_bit, name, value } => { - searcher.search_literal_with_indexing(mid_bit, name, value)?; - } - Representation::LiteralWithPostIndexing { mid_bit, name, value } => { - searcher.search_literal_with_post_indexing(mid_bit, name, value)?; - } - Representation::LiteralWithLiteralName { mid_bit, name, value } => { - searcher.search_listeral_with_literal(mid_bit, name, value)?; + match decoder.decode(&mut buf[cnt..], &mut self.repr_state)? { + Some(( + offset, + Representation::FieldSectionPrefix { + require_insert_count, + signal, + delta_base, + }, + )) => { + cnt += offset; + 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; } } + if signal { + self.base = self.require_insert_count - delta_base.0 - 1; + } else { + self.base = self.require_insert_count + delta_base.0; + } + searcher.base = self.base; + //todo:block + } + Some((offset, Representation::Indexed { mid_bit, index })) => { + cnt += offset; + searcher.search(Representation::Indexed { mid_bit, index })?; + } + Some((offset, Representation::IndexedWithPostIndex { index })) => { + cnt += offset; + searcher.search(Representation::IndexedWithPostIndex { index })?; + } + Some(( + offset, + Representation::LiteralWithIndexing { + mid_bit, + name, + value, + }, + )) => { + println!("offset:{}", offset); + cnt += offset; + searcher.search_literal_with_indexing(mid_bit, name, value)?; + } + Some(( + offset, + Representation::LiteralWithPostIndexing { + mid_bit, + name, + value, + }, + )) => { + cnt += offset; + searcher.search_literal_with_post_indexing(mid_bit, name, value)?; + } + Some(( + offset, + Representation::LiteralWithLiteralName { + mid_bit, + name, + value, + }, + )) => { + cnt += offset; + searcher.search_listeral_with_literal(mid_bit, name, value)?; + } + + None => { + return Result::Ok(()); } - None => return Result::Ok(()) } - }; + } } /// Users call `finish` to stop decoding a field section. And send an `Section Acknowledgment` to encoder: @@ -152,9 +206,13 @@ impl<'a> QpackDecoder<'a> { /// +---+---+---+---+---+---+---+---+ /// | 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)); + pub(crate) fn finish( + &mut self, + stream_id: usize, + buf: &mut [u8], + ) -> Result<(Parts, Option), H3Error_QPACK> { + if !self.repr_state.is_none() { + return Err(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)); } self.lines.header_size = 0; if self.require_insert_count > 0 { @@ -175,13 +233,17 @@ impl<'a> QpackDecoder<'a> { /// +---+---+---+---+---+---+---+---+ /// | 0 | 1 | Stream ID (6+) | /// +---+---+-----------------------+ - pub(crate) fn stream_cancel(&mut self, stream_id: usize, buf: &mut [u8]) -> Result { + 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)) + Err(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)) } } @@ -191,27 +253,31 @@ struct Updater<'a> { impl<'a> Updater<'a> { fn new(table: &'a mut DynamicTable) -> Self { - Self { - table, - } + Self { table } } - fn update_capacity(&mut self, capacity: usize) -> Result<(), H3Error> { + fn update_capacity(&mut self, capacity: usize) -> Result<(), H3Error_QPACK> { 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)?; + fn update_table( + &mut self, + mid_bit: MidBit, + name: Name, + value: Vec, + ) -> Result<(), H3Error_QPACK> { + 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> { + fn duplicate(&mut self, index: usize) -> Result<(), H3Error_QPACK> { let table_searcher = TableSearcher::new(self.table); let (f, v) = table_searcher - .find_field_dynamic(self.table.insert_count - index -1) - .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; + .find_field_dynamic(self.table.insert_count - index - 1) + .ok_or(H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; self.table.update(f, v); Ok(()) } @@ -222,32 +288,31 @@ impl<'a> Updater<'a> { name: Name, value: Vec, insert_count: usize, - ) -> Result<(Field, String), H3Error> { + ) -> Result<(Field, String), H3Error_QPACK> { 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))? + .ok_or(H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? } else { searcher .find_field_name_dynamic(insert_count - index - 1) - .ok_or(H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? + .ok_or(H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? } } Name::Literal(octets) => Field::Other( String::from_utf8(octets) - .map_err(|_| H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?, + .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?, ), }; let v = String::from_utf8(value) - .map_err(|_| H3Error::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; + .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; Ok((h, v)) } } - struct Searcher<'a> { field_list_size: usize, table: &'a DynamicTable, @@ -265,78 +330,101 @@ impl<'a> Searcher<'a> { } } - fn search(&mut self, repr: Representation) -> Result<(), H3Error> { + fn search(&mut self, repr: Representation) -> Result<(), H3Error_QPACK> { match repr { - Representation::Indexed { mid_bit, index } => { - self.search_indexed(mid_bit, index) - } - Representation::IndexedWithPostIndex { index } => { - self.search_post_indexed(index) - } - _ => { - Ok(()) - } + 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> { + fn search_indexed(&mut self, mid_bit: MidBit, index: usize) -> Result<(), H3Error_QPACK> { let table_searcher = TableSearcher::new(&mut 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))?; + .ok_or(H3Error_QPACK::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))?; + .find_field_dynamic(self.base - index - 1) + .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; self.lines.parts.update(f, v); return Ok(()); } } - fn search_post_indexed(&mut self, index: usize) -> Result<(), H3Error> { + fn search_post_indexed(&mut self, index: usize) -> Result<(), H3Error_QPACK> { let table_searcher = TableSearcher::new(&mut self.table); let (f, v) = table_searcher .find_field_dynamic(self.base + index) - .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + .ok_or(H3Error_QPACK::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)?; + fn search_literal_with_indexing( + &mut self, + mid_bit: MidBit, + name: Name, + value: Vec, + ) -> Result<(), H3Error_QPACK> { + 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)?; + fn search_literal_with_post_indexing( + &mut self, + mid_bit: MidBit, + name: Name, + value: Vec, + ) -> Result<(), H3Error_QPACK> { + 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)?; + fn search_listeral_with_literal( + &mut self, + mid_bit: MidBit, + name: Name, + value: Vec, + ) -> Result<(), H3Error_QPACK> { + 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> { + ) -> Result<(Field, String), H3Error_QPACK> { let h = match name { Name::Index(index) => { if repr == ReprPrefixBit::LITERALWITHINDEXING { @@ -344,36 +432,36 @@ impl<'a> Searcher<'a> { if let Some(true) = mid_bit.t { searcher .find_field_name_static(index) - .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))? } else { searcher .find_field_name_dynamic(self.base - index - 1) - .ok_or(H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + .ok_or(H3Error_QPACK::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))? + .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))? } } Name::Literal(octets) => Field::Other( String::from_utf8(octets) - .map_err(|_| H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?, + .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?, ), }; let v = String::from_utf8(value) - .map_err(|_| H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + .map_err(|_| H3Error_QPACK::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> { + fn check_field_list_size(&mut self, key: &Field, value: &String) -> Result<(), H3Error_QPACK> { 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)) + Err(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)) } else { Ok(()) } @@ -386,16 +474,17 @@ fn field_line_length(key_size: usize, value_size: usize) -> usize { #[cfg(test)] mod ut_qpack_decoder { + use crate::h3::qpack::format::decoder::ReprDecodeState; 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() { rfc9204_test_cases(); + test_need_more(); test_indexed_static(); test_indexed_dynamic(); test_post_indexed_dynamic(); @@ -404,24 +493,44 @@ mod ut_qpack_decoder { test_literal_post_indexing_dynamic(); test_literal_with_literal_name(); test_setcap(); + + fn get_state(state: &Option) { + match state { + Some(x @ ReprDecodeState::FiledSectionPrefix(_)) => { + println!("FiledSectionPrefix"); + } + Some(x @ ReprDecodeState::ReprIndex(_)) => { + println!("Indexed"); + } + Some(x @ ReprDecodeState::ReprValueString(_)) => { + println!("ReprValueString"); + } + Some(x @ ReprDecodeState::ReprNameAndValue(_)) => { + println!("ReprNameAndValue"); + } + None => { + println!("None"); + } + } + } 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); + 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(); - assert!($qpack.decode_repr(text.as_slice()).is_ok()); + let mut text = decode($input).unwrap().as_slice().to_vec(); + assert!($qpack.decode_repr(&mut text).is_ok()); )* let mut ack = [0u8; 20]; match $qpack.finish(1,&mut ack) { @@ -469,7 +578,6 @@ mod ut_qpack_decoder { }; } - fn rfc9204_test_cases() { literal_field_line_with_name_reference(); dynamic_table(); @@ -477,30 +585,43 @@ mod ut_qpack_decoder { duplicate_instruction_stream_cancellation(); dynamic_table_insert_eviction(); fn literal_field_line_with_name_reference() { + println!("run literal_field_line_with_name_reference"); let mut dynamic_table = DynamicTable::with_capacity(4096); - + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); qpack_test_case!( - QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), + decoder, "0000510b2f696e6465782e68746d6c", - { None, None, Some("/index.html"), None, None }, + { None, None, Some(String::from("/index.html")), None, None }, { 0 } ); + println!("passed"); } fn dynamic_table() { + println!("dynamic_table"); let mut dynamic_table = DynamicTable::with_capacity(4096); let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); - decoder.decode_ins(decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468").unwrap().as_slice()); + let mut ins = + decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468") + .unwrap() + .as_slice() + .to_vec(); + decoder.decode_ins(&mut ins); + get_state(&decoder.repr_state); qpack_test_case!( decoder, "03811011", - { Some("www.example.com"), None, Some("/sample/path"), None, None }, + { Some(String::from("www.example.com")), None, Some(String::from("/sample/path")), None, None }, { 0 } ); } fn speculative_insert() { let mut dynamic_table = DynamicTable::with_capacity(4096); let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); - decoder.decode_ins(decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565").unwrap().as_slice()); + let mut ins = decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565") + .unwrap() + .as_slice() + .to_vec(); + decoder.decode_ins(&mut ins); qpack_test_case!( decoder, "028010", @@ -510,35 +631,46 @@ mod ut_qpack_decoder { } fn duplicate_instruction_stream_cancellation() { let mut dynamic_table = DynamicTable::with_capacity(4096); - dynamic_table.update(Field::Authority,String::from("www.example.com")); - dynamic_table.update(Field::Path,String::from("/sample/path")); - dynamic_table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); + dynamic_table.update(Field::Authority, String::from("www.example.com")); + dynamic_table.update(Field::Path, String::from("/sample/path")); + dynamic_table.update( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ); dynamic_table.ref_count.insert(0, 0); //Acked dynamic_table.ref_count.insert(1, 0); //Acked dynamic_table.ref_count.insert(2, 0); //Acked dynamic_table.known_received_count = 3; let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); - decoder.decode_ins(decode("02").unwrap().as_slice()); + let mut ins = decode("02").unwrap().as_slice().to_vec(); + decoder.decode_ins(&mut ins); qpack_test_case!( decoder, "058010c180", - { Some("www.example.com"), None, Some("/"), None, None }, + { Some(String::from("www.example.com")), None, Some(String::from("/")), None, None }, { "custom-key"=>"custom-value" }, { 0 } ); } - fn dynamic_table_insert_eviction(){ + fn dynamic_table_insert_eviction() { let mut dynamic_table = DynamicTable::with_capacity(4096); - dynamic_table.update(Field::Authority,String::from("www.example.com")); - dynamic_table.update(Field::Path,String::from("/sample/path")); - dynamic_table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); - dynamic_table.update(Field::Authority,String::from("www.example.com")); + dynamic_table.update(Field::Authority, String::from("www.example.com")); + dynamic_table.update(Field::Path, String::from("/sample/path")); + dynamic_table.update( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ); + dynamic_table.update(Field::Authority, String::from("www.example.com")); dynamic_table.ref_count.insert(0, 0); //Acked dynamic_table.ref_count.insert(1, 0); //Acked dynamic_table.ref_count.insert(2, 0); //Acked dynamic_table.known_received_count = 3; let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); - decoder.decode_ins(decode("810d637573746f6d2d76616c756532").unwrap().as_slice()); + let mut ins = decode("810d637573746f6d2d76616c756532") + .unwrap() + .as_slice() + .to_vec(); + decoder.decode_ins(&mut ins); qpack_test_case!( decoder, "068111", @@ -548,25 +680,45 @@ mod ut_qpack_decoder { } } - fn test_indexed_static() - { + fn test_need_more() { + println!("test_need_more"); + let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + let mut text = decode("00").unwrap().as_slice().to_vec(); //510b2f696e6465782e68746d6c + println!("text={:?}", text); + decoder.decode_repr(&mut text); + get_state(&decoder.repr_state); + let mut text2 = decode("00510b2f696e6465782e68746d6c") + .unwrap() + .as_slice() + .to_vec(); + println!("text2={:?}", text2); + decoder.decode_repr(&mut text2); + } + + 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 }, + { None, Some(String::from("GET")), None, None, None }, { 0 } ); } - fn test_indexed_dynamic() - { + 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")); + 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")); + 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 @@ -577,16 +729,24 @@ mod ut_qpack_decoder { { 0 } ); } - fn test_post_indexed_dynamic() - { + 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")); + 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")); + 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")); + 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 @@ -597,24 +757,28 @@ mod ut_qpack_decoder { { 0 } ); } - fn test_literal_indexing_static() - { + 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 }, + { None, Some(String::from("custom1-value")), None, None, None }, { 0 } ); } - fn test_literal_indexing_dynamic() - { + 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")); + 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")); + 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 @@ -626,16 +790,24 @@ mod ut_qpack_decoder { ); } - fn test_literal_post_indexing_dynamic() - { + 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")); + 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")); + 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")); + 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 @@ -647,8 +819,7 @@ mod ut_qpack_decoder { ); } - fn test_literal_with_literal_name() - { + 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), @@ -658,20 +829,12 @@ mod ut_qpack_decoder { ); } - fn test_setcap() - { + 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(); - decoder.decode_ins(text.as_slice()); - assert_eq!(dynamic_table.capacity(), 158); + let mut ins = decode("3fbd01").unwrap().as_slice().to_vec(); + decoder.decode_ins(&mut ins); + assert_eq!(decoder.table.capacity(), 220); } } } - - - - - - - diff --git a/ylong_http/src/h3/qpack/encoder.rs b/ylong_http/src/h3/qpack/encoder.rs index 7039f72..fd14bcc 100644 --- a/ylong_http/src/h3/qpack/encoder.rs +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -10,176 +10,182 @@ // 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. -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::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; +use crate::h3::qpack::error::H3Error_QPACK; +use crate::h3::qpack::format::encoder::{ + DecInstDecoder, InstDecodeState, PartsIter, ReprEncodeState, SetCap, +}; +use crate::h3::qpack::format::ReprEncoder; +use crate::h3::qpack::integer::{Integer, IntegerEncoder}; 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}; +use std::collections::{HashMap, VecDeque}; pub(crate) struct QpackEncoder { table: DynamicTable, - holder: ReprEncStateHolder, - inst_holder: InstDecStateHolder, + field_iter: Option, + field_state: Option, + inst_state: Option, stream_reference: VecDeque>, stream_id: usize, - is_insert: bool, // if not insert to dynamic table, the required insert count will be 0. - allow_post: bool, + is_insert: bool, // allow reference to the inserting field default is false. - draining_index: usize, // RFC9204-2.1.1.1. if index (QpackEncoder, usize) { + pub(crate) fn with_capacity( + max_size: usize, + encoder_buf: &mut [u8], + stream_id: usize, + allow_post: bool, + draining_index: usize, + ) -> (QpackEncoder, usize) { let mut s = Self { table: DynamicTable::with_capacity(max_size), - holder: ReprEncStateHolder::new(), - inst_holder: InstDecStateHolder::new(), + field_iter: None, + field_state: None, + inst_state: None, stream_reference: VecDeque::new(), stream_id, is_insert: false, - allow_post: allow_post, - draining_index: draining_index, + allow_post, + draining_index, }; - let cur = EncoderInst::SetCap(SetCap::new(max_size)).encode(&mut encoder_buf[..]); - (s, cur) + if let Ok(cur) = SetCap::new(max_size).encode(&mut encoder_buf[..]) { + return (s, cur); + } + (s, 0) } - pub(crate) fn set_parts(&mut self, parts: Parts) { - self.holder.set_parts(parts) + self.field_iter = Some(PartsIter::new(parts)); + } + + fn ack(&mut self, stream_id: usize) -> Result, H3Error_QPACK> { + 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); + } + self.table.known_received_count += 1; + } + } else { + return Err(H3Error_QPACK::ConnectionError(QPACK_DECODER_STREAM_ERROR)); + } + } + Ok(Some(DecoderInst::Ack)) } /// Users can call `decode_ins` multiple times to decode decoder instructions. - pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result, H3Error> { + pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result, H3Error_QPACK> { let mut decoder = DecInstDecoder::new(buf); - decoder.load(&mut self.inst_holder); loop { - match decoder.decode()? { - Some(inst) => { - match inst { - DecoderInstruction::Ack { 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 } => { - assert_eq!(stream_id, self.stream_id); - return Ok(Some(DecoderInst::StreamCancel)); - } - DecoderInstruction::InsertCountIncrement { increment } => { - self.table.known_received_count += increment; - } - } + match decoder.decode(&mut self.inst_state)? { + Some(DecoderInstruction::Ack { stream_id }) => { + return self.ack(stream_id); + } + Some(DecoderInstruction::StreamCancel { stream_id }) => { + assert_eq!(stream_id, self.stream_id); + return Ok(Some(DecoderInst::StreamCancel)); + } + Some(DecoderInstruction::InsertCountIncrement { increment }) => { + self.table.known_received_count += increment; + return Ok(Some(DecoderInst::InsertCountIncrement)); + } + None => { + return Ok(None); } - 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, Option<([u8; 1024], usize)>) { + fn get_prefix(&self, prefix_buf: &mut [u8]) -> usize { let mut cur_prefix = 0; - let mut cur_encoder = 0; - let mut cur_stream = 0; + let mut wire_ric = 0; + if self.is_insert { + wire_ric = self.table.insert_count % (2 * self.table.max_entries()) + 1; + } + + cur_prefix += Integer::index(0x00, wire_ric, 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); + } + cur_prefix + } + /// 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, Option<([u8; 1024], usize)>) { + let (mut cur_prefix, mut cur_encoder, mut cur_stream) = (0, 0, 0); if self.is_finished() { // denote an end of field section self.stream_reference.push_back(None); - let mut wire_ric = 0; - if self.is_insert { - wire_ric = self.table.insert_count % (2 * self.table.max_entries()) + 1; - } let mut prefix_buf = [0u8; 1024]; - cur_prefix += Integer::index(0x00, wire_ric, 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); - } + cur_prefix = self.get_prefix(&mut prefix_buf[0..]); (cur_encoder, cur_stream, Some((prefix_buf, cur_prefix))) } else { let mut encoder = ReprEncoder::new(&mut self.table, self.draining_index); - encoder.load(&mut self.holder); - (cur_encoder, cur_stream) = encoder.encode(&mut encoder_buf[0..], &mut stream_buf[0..], &mut self.stream_reference, &mut self.is_insert, self.allow_post); + (cur_encoder, cur_stream) = encoder.encode( + &mut self.field_iter, + &mut self.field_state, + &mut encoder_buf[0..], + &mut stream_buf[0..], + &mut self.stream_reference, + &mut self.is_insert, + self.allow_post, + ); (cur_encoder, cur_stream, None) } } /// Check the previously set `Parts` if encoding is complete. pub(crate) fn is_finished(&self) -> bool { - self.holder.is_empty() + self.field_iter.is_none() && self.field_state.is_none() } } - 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; - use crate::h3::qpack::encoder::{QpackEncoder}; + use crate::h3::qpack::encoder::QpackEncoder; use crate::h3::qpack::table::Field; use crate::test_util::decode; @@ -211,6 +217,7 @@ mod ut_qpack_encoder { if let Some(res) = decode($encoder_res){ assert_eq!($encoder_buf[..$encoder_cur].to_vec().as_slice(), res.as_slice()); } + println!("stream_buf: {:#?}",stream_buf); assert_eq!(stream_cur, $len); assert_eq!(stream_buf.as_slice(), result.as_slice()); assert_eq!(_encoder.table.size(), $size); @@ -228,7 +235,8 @@ mod ut_qpack_encoder { /// The encoder sends an encoded field section containing a literal representation of a field with a static name reference. fn literal_field_line_with_name_reference() { let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(0, &mut encoder_buf[..], 0, false,0); + let (mut encoder, mut encoder_cur) = + QpackEncoder::with_capacity(0, &mut encoder_buf[..], 0, false, 0); qpack_test_cases!( encoder, encoder_buf, @@ -250,7 +258,8 @@ mod ut_qpack_encoder { /// Insert Count. fn dynamic_table() { let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true,0); + let (mut encoder, mut encoder_cur) = + QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true, 0); qpack_test_cases!( encoder, encoder_buf, @@ -272,7 +281,8 @@ mod ut_qpack_encoder { /// encoded field sections. fn speculative_insert() { let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true,0); + let (mut encoder, mut encoder_cur) = + QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true, 0); encoder_cur = 0; qpack_test_cases!( encoder, @@ -299,12 +309,20 @@ mod ut_qpack_encoder { /// Just As the above test: `dynamic_table()` is same as RFC 9204. /// But, the following test utilized the (2), So, it is something different from RFC 9204. because the above reason. - fn duplicate_instruction_stream_cancellation(){ + fn duplicate_instruction_stream_cancellation() { let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true,1); - encoder.table.update(Field::Authority,String::from("www.example.com")); - encoder.table.update(Field::Path,String::from("/sample/path")); - encoder.table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); + let (mut encoder, mut encoder_cur) = + QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true, 1); + encoder + .table + .update(Field::Authority, String::from("www.example.com")); + encoder + .table + .update(Field::Path, String::from("/sample/path")); + encoder.table.update( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ); encoder.table.ref_count.insert(0, 0); //Acked encoder.table.ref_count.insert(1, 0); //Acked encoder.table.ref_count.insert(2, 0); //Acked @@ -328,13 +346,23 @@ mod ut_qpack_encoder { ); } - fn dynamic_table_insert_eviction(){ + fn dynamic_table_insert_eviction() { let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true,1); - encoder.table.update(Field::Authority,String::from("www.example.com")); - encoder.table.update(Field::Path,String::from("/sample/path")); - encoder.table.update(Field::Other(String::from("custom-key")),String::from("custom-value")); - encoder.table.update(Field::Authority,String::from("www.example.com")); + let (mut encoder, mut encoder_cur) = + QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true, 1); + encoder + .table + .update(Field::Authority, String::from("www.example.com")); + encoder + .table + .update(Field::Path, String::from("/sample/path")); + encoder.table.update( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ); + encoder + .table + .update(Field::Authority, String::from("www.example.com")); encoder.table.ref_count.insert(0, 0); //Acked encoder.table.ref_count.insert(1, 0); //Acked encoder.table.ref_count.insert(2, 0); //Acked @@ -353,7 +381,6 @@ mod ut_qpack_encoder { }, ); } - } } -} \ No newline at end of file +} diff --git a/ylong_http/src/h3/error.rs b/ylong_http/src/h3/qpack/error.rs similarity index 95% rename from ylong_http/src/h3/error.rs rename to ylong_http/src/h3/qpack/error.rs index d63ebe1..3df4992 100644 --- a/ylong_http/src/h3/error.rs +++ b/ylong_http/src/h3/qpack/error.rs @@ -10,8 +10,7 @@ // 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. -pub enum H3Error { - //todo: add more +pub enum H3Error_QPACK { ConnectionError(ErrorCode), } @@ -22,4 +21,4 @@ pub enum ErrorCode { QPACK_ENCODER_STREAM_ERROR = 0x0201, QPACK_DECODER_STREAM_ERROR = 0x0202, -} \ 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 index 1c65ba2..81d2940 100644 --- a/ylong_http/src/h3/qpack/format/decoder.rs +++ b/ylong_http/src/h3/qpack/format/decoder.rs @@ -10,130 +10,109 @@ // 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. -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::error::ErrorCode::QPACK_DECOMPRESSION_FAILED; +use crate::h3::qpack::error::{ErrorCode, H3Error_QPACK}; use crate::h3::qpack::format::decoder::DecResult::Error; +use crate::h3::qpack::integer::IntegerDecoder; +use crate::h3::qpack::{ + DeltaBase, EncoderInstPrefixBit, EncoderInstruction, MidBit, PrefixMask, ReprPrefixBit, + Representation, RequireInsertCount, +}; use crate::huffman::HuffmanDecoder; +use std::cmp::Ordering; +use std::marker::PhantomData; -pub(crate) struct EncInstDecoder<'a>{ - buf: &'a [u8], - state: Option, -} +pub(crate) struct EncInstDecoder; -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(); +impl EncInstDecoder { + pub(crate) fn new() -> Self { + Self {} } - pub(crate) fn decode(&mut self) -> Result, H3Error> { - if self.buf.is_empty() { + + pub(crate) fn decode( + &mut self, + buf: &mut [u8], + inst_state: &mut Option, + ) -> Result, H3Error_QPACK> { + if buf.is_empty() { return Ok(None); } - match self - .state + match inst_state .take() .unwrap_or_else(|| InstDecodeState::EncInstIndex(EncInstIndex::new())) - .decode(&mut self.buf) + .decode(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) => { - self.state = Some(state); + println!("need more"); + *inst_state = Some(state); Ok(None) } - DecResult::Decoded(repr) => { - Ok(Some(repr)) - } + DecResult::Decoded((buf_index, repr)) => Ok(Some((buf_index, 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, -} +pub(crate) struct ReprDecoder; -impl<'a> ReprDecoder<'a> { +impl ReprDecoder { /// 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(); + pub(crate) fn new() -> Self { + Self {} } /// Decodes `self.buf`. Every time users call `decode`, it will try to /// decode a `Representation`. - pub(crate) fn decode(&mut self) -> Result, H3Error> { + pub(crate) fn decode( + &mut self, + buf: &mut [u8], + repr_state: &mut Option, + ) -> Result, H3Error_QPACK> { // If buf is empty, leave the state unchanged. - if self.buf.is_empty() { + let buf_len = buf.len(); + if buf.is_empty() { return Ok(None); } - - match self - .state + match repr_state .take() .unwrap_or_else(|| ReprDecodeState::FiledSectionPrefix(FiledSectionPrefix::new())) - .decode(&mut self.buf) + .decode(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) => { - self.state = Some(state); + println!("need more"); + *repr_state = Some(state); Ok(None) } - DecResult::Decoded(repr) => { - self.state = Some(ReprDecodeState::ReprIndex(ReprIndex::new())); - Ok(Some(repr)) + DecResult::Decoded((buf_index, repr)) => { + if buf_index >= buf_len { + return Ok(Some((buf_index, repr))); + } + *repr_state = Some(ReprDecodeState::ReprIndex(ReprIndex::new())); + Ok(Some((buf_index, 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! return_res { + ($res: expr ,$buf_index: expr) => { + if let DecResult::Decoded((cnt, repr)) = $res { + return DecResult::Decoded((cnt + $buf_index, repr)); + } else { + $res + } + }; } - - macro_rules! state_def { ($name: ident, $decoded: ty, $($state: ident),* $(,)?) => { pub(crate) enum $name { @@ -143,7 +122,7 @@ macro_rules! state_def { } impl $name { - fn decode(self, buf: &mut &[u8]) -> DecResult<$decoded, $name> { + fn decode(self, buf: & mut [u8]) -> DecResult<$decoded, $name> { match self { $( Self::$state(state) => state.decode(buf), @@ -161,9 +140,15 @@ macro_rules! state_def { )* } } + +state_def!( + FSPInner, + (usize, RequireInsertCount, bool, DeltaBase), + FSPTwoIntergers, +); state_def!( InstDecodeState, - EncoderInstruction, + (usize, EncoderInstruction), EncInstIndex, InstValueString, InstNameAndValue, @@ -171,18 +156,28 @@ state_def!( state_def!( ReprDecodeState, - Representation, + (usize, 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!( + InstIndexInner, + (usize, EncoderInstPrefixBit, MidBit, usize), + InstFirstByte, + InstTrailingBytes +); +state_def!( + ReprIndexInner, + (usize, ReprPrefixBit, MidBit, usize), + ReprFirstByte, + ReprTrailingBytes +); + state_def!( LiteralString, - Vec, + (usize, Vec), LengthFirstByte, LengthTrailingBytes, AsciiStringBytes, @@ -201,23 +196,26 @@ impl FiledSectionPrefix { Self { inner } } - fn decode(self, buf: &mut &[u8]) -> DecResult { + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Representation), ReprDecodeState> { match self.inner.decode(buf) { - DecResult::Decoded((ric, signal, delta_base)) => { - DecResult::Decoded(Representation::FieldSectionPrefix { + DecResult::Decoded((buf_index, ric, signal, delta_base)) => DecResult::Decoded(( + buf_index, + Representation::FieldSectionPrefix { require_insert_count: ric, signal: signal, delta_base: delta_base, - }) + }, + )), + DecResult::NeedMore(inner) => { + DecResult::NeedMore(FiledSectionPrefix::from_inner(inner).into()) } - DecResult::NeedMore(inner) => DecResult::NeedMore(FiledSectionPrefix::from_inner(inner).into()), DecResult::Error(e) => e.into(), } } } pub(crate) struct EncInstIndex { - inner: InstIndexInner + inner: InstIndexInner, } impl EncInstIndex { @@ -227,23 +225,49 @@ impl EncInstIndex { fn from_inner(inner: InstIndexInner) -> Self { Self { inner } } - fn decode(self, buf: &mut &[u8]) -> DecResult { + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, EncoderInstruction), InstDecodeState> { 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((buf_index, EncoderInstPrefixBit::SETCAP, _, index)) => { + DecResult::Decoded((buf_index, EncoderInstruction::SetCap { capacity: index })) + } + DecResult::Decoded(( + buf_index, + EncoderInstPrefixBit::INSERTWITHINDEX, + mid_bit, + index, + )) => { + let res = InstValueString::new( + EncoderInstPrefixBit::INSERTWITHINDEX, + mid_bit, + Name::Index(index), + ) + .decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + DecResult::Decoded(( + buf_index, + EncoderInstPrefixBit::INSERTWITHLITERAL, + mid_bit, + namelen, + )) => { + let res = InstNameAndValue::new( + EncoderInstPrefixBit::INSERTWITHLITERAL, + mid_bit, + namelen, + ) + .decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + DecResult::Decoded((remain_buf, EncoderInstPrefixBit::DUPLICATE, _, index)) => { + DecResult::Decoded((remain_buf, EncoderInstruction::Duplicate { index })) } - DecResult::Decoded((EncoderInstPrefixBit::DUPLICATE, _, index)) => { - DecResult::Decoded(EncoderInstruction::Duplicate { index }) + DecResult::NeedMore(inner) => { + DecResult::NeedMore(EncInstIndex::from_inner(inner).into()) } - DecResult::NeedMore(inner) => DecResult::NeedMore(EncInstIndex::from_inner(inner).into()), DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3Error::ConnectionError(ErrorCode::QPACK_DECOMPRESSION_FAILED)), + _ => DecResult::Error(H3Error_QPACK::ConnectionError( + ErrorCode::QPACK_DECOMPRESSION_FAILED, + )), } } } @@ -259,26 +283,53 @@ impl ReprIndex { fn from_inner(inner: ReprIndexInner) -> Self { Self { inner } } - fn decode(self, buf: &mut &[u8]) -> DecResult { + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Representation), ReprDecodeState> { 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::Decoded((buf_index, ReprPrefixBit::INDEXED, mid_bit, index)) => { + DecResult::Decoded((buf_index, Representation::Indexed { mid_bit, index })) + } + DecResult::Decoded((buf_index, ReprPrefixBit::INDEXEDWITHPOSTINDEX, _, index)) => { + DecResult::Decoded((buf_index, Representation::IndexedWithPostIndex { index })) + } + DecResult::Decoded((buf_index, ReprPrefixBit::LITERALWITHINDEXING, mid_bit, index)) => { + let res = ReprValueString::new( + ReprPrefixBit::LITERALWITHINDEXING, + mid_bit, + Name::Index(index), + ) + .decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + DecResult::Decoded(( + buf_index, + ReprPrefixBit::LITERALWITHPOSTINDEXING, + mid_bit, + index, + )) => { + let res = ReprValueString::new( + ReprPrefixBit::LITERALWITHPOSTINDEXING, + mid_bit, + Name::Index(index), + ) + .decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + DecResult::Decoded(( + buf_index, + ReprPrefixBit::LITERALWITHLITERALNAME, + mid_bit, + namelen, + )) => { + let res = + ReprNameAndValue::new(ReprPrefixBit::LITERALWITHLITERALNAME, mid_bit, namelen) + .decode(&mut buf[buf_index..]); + return_res!(res, buf_index) } DecResult::NeedMore(inner) => DecResult::NeedMore(ReprIndex::from_inner(inner).into()), DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3Error::ConnectionError(ErrorCode::QPACK_DECOMPRESSION_FAILED )), + _ => DecResult::Error(H3Error_QPACK::ConnectionError( + ErrorCode::QPACK_DECOMPRESSION_FAILED, + )), } } } @@ -286,27 +337,29 @@ impl ReprIndex { pub(crate) struct FSPTwoIntergers; impl FSPTwoIntergers { - fn decode(self, buf: &mut &[u8]) -> DecResult<(RequireInsertCount, bool, DeltaBase), FSPInner> { + fn decode( + self, + buf: &mut [u8], + ) -> DecResult<(usize, RequireInsertCount, bool, DeltaBase), FSPInner> { + let mut buf_index = 1; if buf.is_empty() { return DecResult::NeedMore(self.into()); } - let byte = buf[0]; + let buf_len = buf.len(); let mask = PrefixMask::REQUIREINSERTCOUNT; - *buf = &buf[1..]; - let ric = match IntegerDecoder::first_byte(byte, mask.0) { + let ric = match IntegerDecoder::first_byte(buf[buf_index - 1], 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() { + buf_index += 1; + if buf_index >= buf_len { 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) { + match int.next_byte(buf[buf_index - 1]) { Ok(None) => {} Ok(Some(index)) => { res = index; @@ -314,31 +367,30 @@ impl FSPTwoIntergers { } Err(e) => return e.into(), } - }; + } res } }; - if buf.is_empty() { + buf_index += 1; + if buf_index >= buf_len { return DecResult::NeedMore(self.into()); } - let byte = buf[0]; + let byte = buf[buf_index - 1]; 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() { + buf_index += 1; + if buf_index >= buf_len { 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) { + match int.next_byte(buf[buf_index - 1]) { Ok(None) => {} Ok(Some(index)) => { res = index; @@ -346,117 +398,123 @@ impl FSPTwoIntergers { } 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), - } + DecResult::Decoded(( + buf_index, + RequireInsertCount(ric), + signal, + DeltaBase(delta_base), + )) } } -pub(crate) struct ReprFirstByte; +macro_rules! decode_first_byte { + ($struct_name:ident, $prefix_type:ty, $inner_type:ty,$trailing_bytes:ty) => { + pub(crate) struct $struct_name; -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), + impl $struct_name { + fn decode( + self, + buf: &mut [u8], + ) -> DecResult<(usize, $prefix_type, MidBit, usize), $inner_type> { + // If `buf` has been completely decoded here, return the current state. + let mut buf_index = 1; + if buf.is_empty() { + return DecResult::NeedMore(self.into()); + } + + let prefix = <$prefix_type>::from_u8(buf[buf_index - 1]); + let mid_bit = prefix.prefix_midbit_value(buf[buf_index - 1]); + let mask = prefix.prefix_index_mask(); + + match IntegerDecoder::first_byte(buf[buf_index - 1], mask.0) { + // Return the PrefixBit and index part value. + Ok(idx) => DecResult::Decoded((buf_index, prefix, 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) => { + let res = <$trailing_bytes>::new(prefix, mid_bit, int) + .decode(&mut buf[buf_index..]); + if let DecResult::Decoded((cnt, prefix, mid_bit, int)) = res { + return DecResult::Decoded((cnt + buf_index, prefix, mid_bit, int)); + } else { + return res; + } + } + } + } } - } -} -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()); - } +decode_first_byte!( + InstFirstByte, + EncoderInstPrefixBit, + InstIndexInner, + InstTrailingBytes +); +decode_first_byte!( + ReprFirstByte, + ReprPrefixBit, + ReprIndexInner, + ReprTrailingBytes +); - 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(), - } +macro_rules! trailing_bytes_decoder { + ($struct_name:ident, $prefix_type:ty, $inner_type:ty) => { + pub(crate) struct $struct_name { + prefix: $prefix_type, + mid_bit: MidBit, + index: IntegerDecoder, } - } -} -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()); + impl $struct_name { + fn new(prefix: $prefix_type, mid_bit: MidBit, index: IntegerDecoder) -> Self { + Self { + prefix, + mid_bit, + index, + } } - 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(), + fn decode( + mut self, + buf: &mut [u8], + ) -> DecResult<(usize, $prefix_type, MidBit, usize), $inner_type> { + let mut buf_index = 1; + let buf_len = buf.len(); + loop { + // If `buf` has been completely decoded here, return the current state. + if buf_index > buf_len { + return DecResult::NeedMore(self.into()); + } + + // Updates trailing bytes until we get the index. + match self.index.next_byte(buf[buf_index - 1]) { + Ok(None) => {} + Ok(Some(index)) => { + return DecResult::Decoded(( + buf_index, + self.prefix, + self.mid_bit, + index, + )); + } + Err(e) => return e.into(), + } + buf_index += 1; + } } } - } + }; } +trailing_bytes_decoder!(InstTrailingBytes, EncoderInstPrefixBit, InstIndexInner); +trailing_bytes_decoder!(ReprTrailingBytes, ReprPrefixBit, ReprIndexInner); + pub(crate) struct LengthTrailingBytes { is_huffman: bool, length: IntegerDecoder, @@ -467,20 +525,35 @@ impl LengthTrailingBytes { Self { is_huffman, length } } - fn decode(mut self, buf: &mut &[u8]) -> DecResult, LiteralString> { + fn decode(mut self, buf: &mut [u8]) -> DecResult<(usize, Vec), LiteralString> { + let mut buf_index = 1; + let buf_len = buf.len(); loop { - if buf.is_empty() { + if buf_index >= buf_len { return DecResult::NeedMore(self.into()); } - let byte = buf[0]; - *buf = &buf[1..]; - match (self.length.next_byte(byte), self.is_huffman) { + match (self.length.next_byte(buf[buf_index - 1]), 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), + (Ok(Some(length)), true) => { + let res = HuffmanStringBytes::new(length).decode(&mut buf[buf_index..]); + if let DecResult::Decoded((cnt, vec)) = res { + return DecResult::Decoded((cnt + buf_index, vec)); + } else { + return res; + } + } + (Ok(Some(length)), false) => { + let res = AsciiStringBytes::new(length).decode(&mut buf[buf_index..]); + if let DecResult::Decoded((cnt, vec)) = res { + return DecResult::Decoded((cnt + buf_index, vec)); + } else { + return res; + } + } } + buf_index += 1; } } } @@ -498,87 +571,103 @@ impl AsciiStringBytes { } } - fn decode(mut self, buf: &mut &[u8]) -> DecResult, LiteralString> { + fn decode(mut self, buf: &mut [u8]) -> DecResult<(usize, Vec), 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) + DecResult::Decoded((pos, self.octets)) } Ordering::Less => { self.octets.extend_from_slice(buf); - *buf = &buf[buf.len()..]; + // let (_, mut remain_buf) = buf.split_at_mut(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(), +macro_rules! name_and_value_decoder { + ($struct_name:ident, $prefix_type:ty, $inner_type:ty, $output_type:ty, $state_type:ty,$value_string:ty) => { + pub(crate) struct $struct_name { + prefix: $prefix_type, + mid_bit: MidBit, + inner: $inner_type, } - } -} -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) + impl $struct_name { + fn new(prefix: $prefix_type, mid_bit: MidBit, namelen: usize) -> Self { + Self::from_inner(prefix, mid_bit, AsciiStringBytes::new(namelen).into()) } - DecResult::NeedMore(inner) => { - DecResult::NeedMore(Self::from_inner(self.repr, self.mid_bit, inner).into()) + + fn from_inner(prefix: $prefix_type, mid_bit: MidBit, inner: $inner_type) -> Self { + Self { + prefix, + mid_bit, + inner, + } + } + + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, $output_type), $state_type> { + match self.inner.decode(buf) { + DecResult::Decoded((buf_index, octets)) => { + let res = + <$value_string>::new(self.prefix, self.mid_bit, Name::Literal(octets)) + .decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + DecResult::NeedMore(inner) => DecResult::NeedMore( + Self::from_inner(self.prefix, self.mid_bit, inner).into(), + ), + DecResult::Error(e) => e.into(), + } } - DecResult::Error(e) => e.into(), } - } + }; } +name_and_value_decoder!( + InstNameAndValue, + EncoderInstPrefixBit, + LiteralString, + EncoderInstruction, + InstDecodeState, + InstValueString +); +name_and_value_decoder!( + ReprNameAndValue, + ReprPrefixBit, + LiteralString, + Representation, + ReprDecodeState, + ReprValueString +); + pub(crate) struct LengthFirstByte; impl LengthFirstByte { - fn decode(self, buf: &mut &[u8]) -> DecResult, LiteralString> { + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Vec), LiteralString> { + let mut buf_index = 1; 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), + match ( + IntegerDecoder::first_byte(buf[buf_index - 1], 0x7f), + (buf[buf_index - 1] & 0x80) == 0x80, + ) { + (Ok(len), true) => { + let res = HuffmanStringBytes::new(len).decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + (Ok(len), false) => { + let res = AsciiStringBytes::new(len).decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } + (Err(int), huffman) => { + let res = LengthTrailingBytes::new(huffman, int).decode(&mut buf[buf_index..]); + return_res!(res, buf_index) + } } } } @@ -598,35 +687,37 @@ impl HuffmanStringBytes { } } - fn decode(mut self, buf: &mut &[u8]) -> DecResult, LiteralString> { + fn decode(mut self, buf: &mut [u8]) -> DecResult<(usize, Vec), 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(); + return H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); } - *buf = &buf[pos..]; + // let (_, mut remain_buf) = buf.split_at_mut(pos); match self.huffman.finish() { - Ok(vec) => DecResult::Decoded(vec), - Err(_) => H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(), + Ok(vec) => DecResult::Decoded((pos, vec)), + Err(_) => H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(), } } Ordering::Less => { if self.huffman.decode(buf).is_err() { - return H3Error::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); + return H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); } self.read += buf.len(); - *buf = &buf[buf.len()..]; + // let (_, mut remain_buf) = buf.split_at_mut(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, @@ -639,30 +730,47 @@ impl InstValueString { 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 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 { + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, EncoderInstruction), InstDecodeState> { 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)) + (EncoderInstPrefixBit::INSERTWITHINDEX, DecResult::Decoded((buf_index, value))) => { + DecResult::Decoded(( + buf_index, + EncoderInstruction::InsertWithIndex { + mid_bit: self.mid_bit, + name: self.name, + value, + }, + )) + } + (EncoderInstPrefixBit::INSERTWITHLITERAL, DecResult::Decoded((buf_index, value))) => { + DecResult::Decoded(( + buf_index, + EncoderInstruction::InsertWithLiteral { + mid_bit: self.mid_bit, + name: self.name, + value, + }, + )) + } + (_, _) => Error(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)), } } } + pub(crate) struct ReprValueString { repr: ReprPrefixBit, mid_bit: MidBit, @@ -676,38 +784,51 @@ impl ReprValueString { } fn from_inner(repr: ReprPrefixBit, mid_bit: MidBit, name: Name, inner: LiteralString) -> Self { - Self { repr, mid_bit, name, inner } + Self { + repr, + mid_bit, + name, + inner, + } } - fn decode(self, buf: &mut &[u8]) -> DecResult { + fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Representation), ReprDecodeState> { 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)) + (ReprPrefixBit::LITERALWITHINDEXING, DecResult::Decoded((buf_index, value))) => { + DecResult::Decoded(( + buf_index, + Representation::LiteralWithIndexing { + mid_bit: self.mid_bit, + name: self.name, + value, + }, + )) + } + (ReprPrefixBit::LITERALWITHPOSTINDEXING, DecResult::Decoded((buf_index, value))) => { + DecResult::Decoded(( + buf_index, + Representation::LiteralWithPostIndexing { + mid_bit: self.mid_bit, + name: self.name, + value, + }, + )) + } + (ReprPrefixBit::LITERALWITHLITERALNAME, DecResult::Decoded((buf_index, value))) => { + DecResult::Decoded(( + buf_index, + Representation::LiteralWithLiteralName { + mid_bit: self.mid_bit, + name: self.name, + value, + }, + )) + } + (_, _) => Error(H3Error_QPACK::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 @@ -719,11 +840,11 @@ pub(crate) enum DecResult { NeedMore(S), /// Errors that may occur when decoding. - Error(H3Error), + Error(H3Error_QPACK), } -impl From for DecResult { - fn from(e: H3Error) -> Self { +impl From for DecResult { + fn from(e: H3Error_QPACK) -> 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 index c6f874f..97ad56b 100644 --- a/ylong_http/src/h3/qpack/format/encoder.rs +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -10,63 +10,49 @@ // 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. +use crate::h3::parts::Parts; +use crate::h3::qpack::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; +use crate::h3::qpack::error::H3Error_QPACK; +use crate::h3::qpack::format::decoder::DecResult; +use crate::h3::qpack::integer::{Integer, IntegerDecoder, IntegerEncoder}; +use crate::h3::qpack::table::{DynamicTable, Field, TableIndex, TableSearcher}; +use crate::h3::qpack::{DecoderInstPrefixBit, DecoderInstruction, EncoderInstruction, PrefixMask}; +use crate::headers::HeadersIntoIter; +use crate::pseudo::PseudoHeaders; use std::arch::asm; use std::cmp::{max, Ordering}; use std::collections::{HashMap, VecDeque}; use std::result; use std::sync::Arc; -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, draining_index: usize, } - impl<'a> ReprEncoder<'a> { /// Creates a new, empty `ReprEncoder`. pub(crate) fn new(table: &'a mut DynamicTable, draining_index: usize) -> Self { Self { table, - iter: None, - state: None, draining_index, } } - /// 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>, - is_insert: &mut bool, - allow_post: bool, + pub(crate) fn encode( + &mut self, + field_iter: &mut Option, + field_state: &mut Option, + encoder_buffer: &mut [u8], + stream_buffer: &mut [u8], + stream_reference: &mut VecDeque>, + is_insert: &mut bool, + allow_post: bool, ) -> (usize, usize) { let mut cur_encoder = 0; let mut cur_stream = 0; - if let Some(mut iter) = self.iter.take() { + if let Some(mut iter) = field_iter.take() { while let Some((h, v)) = iter.next() { let searcher = TableSearcher::new(&self.table); let mut stream_result: Result = Result::Ok(0); @@ -75,13 +61,15 @@ impl<'a> ReprEncoder<'a> { 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..]); + stream_result = + Indexed::new(index, true).encode(&mut stream_buffer[cur_stream..]); } } else { let mut 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) || !self.should_index(&dynamic_index) { + if dynamic_index == Some(TableIndex::None) || !self.should_index(&dynamic_index) + { // if index is close to eviction, drop it and use duplicate let dyn_index = dynamic_index.clone(); dynamic_index = Some(TableIndex::None); @@ -94,27 +82,49 @@ impl<'a> ReprEncoder<'a> { *is_insert = true; if !self.should_index(&dyn_index) { if let Some(TableIndex::Field(index)) = dyn_index { - encoder_result = Duplicate::new(self.table.insert_count - index.clone() - 1).encode(&mut encoder_buffer[cur_encoder..]); + encoder_result = + Duplicate::new(self.table.insert_count - index.clone() - 1) + .encode(&mut encoder_buffer[cur_encoder..]); } } else { - encoder_result = match (&static_name_index, &dynamic_name_index, self.should_index(&dynamic_name_index)) { + encoder_result = match ( + &static_name_index, + &dynamic_name_index, + self.should_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..]) + 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)), true) => { // 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..]) + InsertWithName::new( + self.table.insert_count - index.clone() - 1, + v.clone().into_bytes(), + false, + false, + ) + .encode(&mut encoder_buffer[cur_encoder..]) } // Duplicate (_, Some(TableIndex::FieldName(index)), false) => { - Duplicate::new(index.clone()).encode(&mut encoder_buffer[cur_encoder..]) + Duplicate::new(index.clone()) + .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..]) - } + (_, _, _) => InsertWithLiteral::new( + h.clone().into_string().into_bytes(), + v.clone().into_bytes(), + false, + ) + .encode(&mut encoder_buffer[cur_encoder..]), } }; if self.table.size() + h.len() + v.len() + 32 >= self.table.capacity() { @@ -142,9 +152,22 @@ impl<'a> ReprEncoder<'a> { } // 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..]); + 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..]); + 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 { @@ -152,10 +175,23 @@ impl<'a> ReprEncoder<'a> { // 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..]); + 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..]); + stream_result = IndexingWithLiteral::new( + h.into_string().into_bytes(), + v.into_bytes(), + false, + false, + ) + .encode(&mut stream_buffer[cur_stream..]); } } } else { @@ -168,9 +204,16 @@ impl<'a> ReprEncoder<'a> { 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..]); + 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..]); + stream_result = Indexed::new( + self.table.known_received_count - index - 1, + false, + ) + .encode(&mut stream_buffer[cur_stream..]); } } } @@ -183,19 +226,19 @@ impl<'a> ReprEncoder<'a> { } (Err(state), Ok(stream_size)) => { cur_stream += stream_size; - self.state = Some(state); - self.iter = Some(iter); + *field_iter = Some(iter); + *field_state = Some(state); return (encoder_buffer.len(), stream_buffer.len()); } (Ok(encoder_size), Err(state)) => { cur_encoder += encoder_size; - self.state = Some(state); - self.iter = Some(iter); + *field_iter = Some(iter); + *field_state = Some(state); return (encoder_buffer.len(), stream_buffer.len()); } (Err(_), Err(state)) => { - self.state = Some(state); - self.iter = Some(iter); + *field_iter = Some(iter); + *field_state = Some(state); return (encoder_buffer.len(), stream_buffer.len()); } } @@ -252,34 +295,8 @@ impl<'a> ReprEncoder<'a> { } } - -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 { + SetCap(SetCap), Indexed(Indexed), InsertWithName(InsertWithName), InsertWithLiteral(InsertWithLiteral), @@ -289,6 +306,27 @@ pub(crate) enum ReprEncodeState { IndexedWithPostName(IndexedWithPostName), Duplicate(Duplicate), } +pub(crate) struct SetCap { + capacity: Integer, +} + +impl SetCap { + fn from(capacity: Integer) -> Self { + Self { capacity } + } + + pub(crate) fn new(capacity: usize) -> Self { + Self { + capacity: Integer::index(0x20, capacity, PrefixMask::SETCAP.0), + } + } + + pub(crate) fn encode(self, dst: &mut [u8]) -> Result { + self.capacity + .encode(dst) + .map_err(|e| ReprEncodeState::SetCap(SetCap::from(e))) + } +} pub(crate) struct Duplicate { index: Integer, @@ -300,7 +338,9 @@ impl Duplicate { } fn new(index: usize) -> Self { - Self { index: Integer::index(0x00, index, PrefixMask::DUPLICATE.0) } + Self { + index: Integer::index(0x00, index, PrefixMask::DUPLICATE.0), + } } fn encode(self, dst: &mut [u8]) -> Result { @@ -322,10 +362,14 @@ impl Indexed { fn new(index: usize, is_static: bool) -> Self { if is_static { // in static table - Self { index: Integer::index(0xc0, index, PrefixMask::INDEXED.0) } + Self { + index: Integer::index(0xc0, index, PrefixMask::INDEXED.0), + } } else { // in dynamic table - Self { index: Integer::index(0x80, index, PrefixMask::INDEXED.0) } + Self { + index: Integer::index(0x80, index, PrefixMask::INDEXED.0), + } } } @@ -336,7 +380,6 @@ impl Indexed { } } - pub(crate) struct IndexedWithPostName { index: Integer, } @@ -347,7 +390,9 @@ impl IndexedWithPostName { } fn new(index: usize) -> Self { - Self { index: Integer::index(0x10, index, PrefixMask::INDEXINGWITHPOSTNAME.0) } + Self { + index: Integer::index(0x10, index, PrefixMask::INDEXINGWITHPOSTNAME.0), + } } fn encode(self, dst: &mut [u8]) -> Result { @@ -357,7 +402,6 @@ impl IndexedWithPostName { } } - pub(crate) struct InsertWithName { inner: IndexAndValue, } @@ -390,7 +434,6 @@ impl InsertWithName { } } - pub(crate) struct IndexingWithName { inner: IndexAndValue, } @@ -400,36 +443,34 @@ impl IndexingWithName { Self { inner } } - fn new(index: usize, value: Vec, is_huffman: bool, is_static: bool, no_permit: bool) -> Self { + 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), - } - } + (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), + }, } } @@ -440,7 +481,6 @@ impl IndexingWithName { } } - pub(crate) struct IndexingWithPostName { inner: IndexAndValue, } @@ -473,7 +513,6 @@ impl IndexingWithPostName { } } - pub(crate) struct IndexingWithLiteral { inner: NameAndValue, } @@ -481,34 +520,26 @@ pub(crate) struct IndexingWithLiteral { 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), - } - } + (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), + }, } } @@ -523,7 +554,6 @@ impl IndexingWithLiteral { } } - pub(crate) struct InsertWithLiteral { inner: NameAndValue, } @@ -556,7 +586,6 @@ impl InsertWithLiteral { } } - pub(crate) struct IndexAndValue { index: Option, value_length: Option, @@ -604,7 +633,6 @@ impl IndexAndValue { } } - pub(crate) struct NameAndValue { index: Option, name_length: Option, @@ -648,8 +676,6 @@ impl NameAndValue { } } - - macro_rules! state_def { ($name: ident, $decoded: ty, $($state: ident),* $(,)?) => { pub(crate) enum $name { @@ -678,44 +704,25 @@ macro_rules! state_def { } } -state_def!( - InstDecodeState, - DecoderInstruction, - DecInstIndex -); +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 } + Self { buf } } - pub(crate) fn load(&mut self, holder: &mut InstDecStateHolder) { - self.state = holder.state.take(); - } - pub(crate) fn decode(&mut self) -> Result, H3Error> { + + pub(crate) fn decode( + &mut self, + ins_state: &mut Option, + ) -> Result, H3Error_QPACK> { if self.buf.is_empty() { return Ok(None); } - match self - .state + match ins_state .take() .unwrap_or_else(|| InstDecodeState::DecInstIndex(DecInstIndex::new())) .decode(&mut self.buf) @@ -724,18 +731,21 @@ impl<'a> DecInstDecoder<'a> { // `Representation`, `Ok(None)` will be returned. Users need to call // `save` to save the current state to a `ReprDecStateHolder`. DecResult::NeedMore(state) => { - self.state = Some(state); + *ins_state = Some(state); Ok(None) } - DecResult::Decoded(repr) => { - Ok(Some(repr)) - } + DecResult::Decoded(repr) => Ok(Some(repr)), DecResult::Error(error) => Err(error), } } } -state_def!(DecInstIndexInner, (DecoderInstPrefixBit, usize), InstFirstByte, InstTrailingBytes); +state_def!( + DecInstIndexInner, + (DecoderInstPrefixBit, usize), + InstFirstByte, + InstTrailingBytes +); pub(crate) struct DecInstIndex { inner: DecInstIndexInner, @@ -760,7 +770,7 @@ impl DecInstIndex { DecResult::Decoded(DecoderInstruction::InsertCountIncrement { increment: index }) } DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3Error::ConnectionError(QPACK_DECODER_STREAM_ERROR)), + _ => DecResult::Error(H3Error_QPACK::ConnectionError(QPACK_DECODER_STREAM_ERROR)), } } } @@ -768,7 +778,10 @@ impl DecInstIndex { pub(crate) struct InstFirstByte; impl InstFirstByte { - fn decode(self, buf: &mut &[u8]) -> DecResult<(DecoderInstPrefixBit, usize), DecInstIndexInner> { + 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()); @@ -797,7 +810,10 @@ impl InstTrailingBytes { fn new(inst: DecoderInstPrefixBit, index: IntegerDecoder) -> Self { Self { inst, index } } - fn decode(mut self, buf: &mut &[u8]) -> DecResult<(DecoderInstPrefixBit, usize), DecInstIndexInner> { + 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() { @@ -851,7 +867,7 @@ impl Octets { } } -struct PartsIter { +pub(crate) struct PartsIter { pseudo: PseudoHeaders, map: HeadersIntoIter, next_type: PartsIterDirection, @@ -869,7 +885,7 @@ enum PartsIterDirection { impl PartsIter { /// Creates a new `PartsIter` from the given `Parts`. - fn new(parts: Parts) -> Self { + pub(crate) fn new(parts: Parts) -> Self { Self { pseudo: parts.pseudo, map: parts.map.into_iter(), @@ -912,4 +928,3 @@ impl PartsIter { } } } - diff --git a/ylong_http/src/h3/qpack/format/mod.rs b/ylong_http/src/h3/qpack/format/mod.rs index 6a59097..91582e3 100644 --- a/ylong_http/src/h3/qpack/format/mod.rs +++ b/ylong_http/src/h3/qpack/format/mod.rs @@ -10,10 +10,7 @@ // 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. -pub(crate) mod encoder; pub(crate) mod decoder; +pub(crate) mod encoder; -pub(crate) use encoder::{ReprEncoder,ReprEncStateHolder}; - - - +pub(crate) use encoder::ReprEncoder; diff --git a/ylong_http/src/h3/qpack/integer.rs b/ylong_http/src/h3/qpack/integer.rs index 70fc014..5c396cb 100644 --- a/ylong_http/src/h3/qpack/integer.rs +++ b/ylong_http/src/h3/qpack/integer.rs @@ -10,8 +10,8 @@ // 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. +use crate::h3::qpack::error::{ErrorCode, H3Error_QPACK}; use std::cmp::Ordering; -use crate::h3::error::{ErrorCode, H3Error}; pub(crate) struct Integer { pub(crate) int: IntegerEncoder, @@ -64,12 +64,14 @@ impl IntegerDecoder { /// 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> { + pub(crate) fn next_byte(&mut self, byte: u8) -> Result, H3Error_QPACK> { 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 + .ok_or(H3Error_QPACK::ConnectionError( + ErrorCode::QPACK_DECOMPRESSION_FAILED, + ))?; //todo: modify the error code self.shift += 7; match (byte & 0x80) == 0x00 { true => Ok(Some(self.index)), @@ -103,7 +105,6 @@ impl IntegerEncoder { } } - /// return the value of the integer pub(crate) fn get_index(&self) -> usize { self.i @@ -141,4 +142,4 @@ impl IntegerEncoder { 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 index 0a997fd..6e0a04b 100644 --- a/ylong_http/src/h3/qpack/mod.rs +++ b/ylong_http/src/h3/qpack/mod.rs @@ -11,16 +11,16 @@ // See the License for the specific language governing permissions and // limitations under the License. - -pub(crate) mod table; +mod decoder; mod encoder; +mod error; mod format; mod integer; -mod decoder; +pub(crate) mod table; -pub(crate) use decoder::QpackDecoder; use crate::h3::qpack::format::decoder::Name; - +pub(crate) use decoder::QpackDecoder; +pub(crate) use encoder::QpackEncoder; pub(crate) struct RequireInsertCount(usize); @@ -77,7 +77,11 @@ impl DecoderInstPrefixBit { pub(crate) fn prefix_midbit_value(&self, byte: u8) -> MidBit { match self.0 { - _ => MidBit { n: None, t: None, h: None }, + _ => MidBit { + n: None, + t: None, + h: None, + }, } } } @@ -108,10 +112,26 @@ impl EncoderInstPrefixBit { 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 }, + 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, + }, } } } @@ -151,21 +171,52 @@ impl ReprPrefixBit { /// 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 }, + 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 }, - + 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 { @@ -186,21 +237,38 @@ pub(crate) enum Representation { /// (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 }, - + 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. @@ -209,12 +277,10 @@ pub(crate) struct MidBit { 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); @@ -232,4 +298,4 @@ impl PrefixMask { 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 index f3c212c..f21a54b 100644 --- a/ylong_http/src/h3/qpack/table.rs +++ b/ylong_http/src/h3/qpack/table.rs @@ -28,7 +28,6 @@ use std::collections::{HashMap, VecDeque}; /// /// Dynamic table entries can have empty values. - pub(crate) struct TableSearcher<'a> { dynamic: &'a DynamicTable, } @@ -38,7 +37,6 @@ impl<'a> TableSearcher<'a> { 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) { @@ -61,7 +59,11 @@ impl<'a> TableSearcher<'a> { } } - pub(crate) fn find_index_name_dynamic(&self, header: &Field, value: &str) -> Option { + pub(crate) fn find_index_name_dynamic( + &self, + header: &Field, + value: &str, + ) -> Option { match self.dynamic.index_name(header, value) { x @ Some(TableIndex::FieldName(_)) => x, _ => Some(TableIndex::None), @@ -93,7 +95,6 @@ impl<'a> TableSearcher<'a> { } } - pub(crate) struct DynamicTable { queue: VecDeque<(Field, String)>, // The size of the dynamic table is the sum of the size of its entries @@ -130,14 +131,15 @@ impl DynamicTable { self.capacity / 32 } /// Updates `DynamicTable` by a given `Header` and value pair. - pub(crate) fn update(&mut self, field: Field, value: String)-> Option { + pub(crate) fn update(&mut self, field: Field, value: String) -> Option { self.insert_count += 1; self.size += field.len() + value.len() + 32; self.queue.push_back((field.clone(), value.clone())); - self.ref_count.insert(self.queue.len() + self.remove_count - 1, 0); + self.ref_count + .insert(self.queue.len() + self.remove_count - 1, 0); self.fit_size(); match self.index(&field, &value) { - x => x, + x => x, _ => Some(TableIndex::None), } } @@ -148,10 +150,9 @@ impl DynamicTable { } 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)){ + if let Some(0) = self.ref_count.get(&(i + self.remove_count)) { eviction_space += h.len() + v.len() + 32; - } - else { + } else { if eviction_space >= field.len() + value.len() + 32 { return true; } @@ -193,7 +194,6 @@ impl DynamicTable { index } - fn index_name(&self, header: &Field, value: &str) -> Option { // find latest let mut index = None; @@ -211,9 +211,10 @@ impl DynamicTable { } pub(crate) fn field_name(&self, index: usize) -> Option { - self.queue.get(index - self.remove_count).map(|(field, _)| field.clone()) + self.queue + .get(index - self.remove_count) + .map(|(field, _)| field.clone()) } - } #[derive(PartialEq, Clone)] @@ -223,7 +224,6 @@ pub(crate) enum TableIndex { None, } - /// The [`Static Table`][static_table] implementation of [QPACK]. /// /// [static_table]: https://www.rfc-editor.org/rfc/rfc9204.html#static-table @@ -283,7 +283,9 @@ impl StaticTable { 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"))), + 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"))), @@ -313,7 +315,10 @@ impl StaticTable { 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"))), + 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"))), @@ -329,39 +334,135 @@ impl StaticTable { 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"))), + 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"))), + 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"))), @@ -371,24 +472,72 @@ impl StaticTable { 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"))), + 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'"))), + 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"))), + 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, } } @@ -466,7 +615,9 @@ impl StaticTable { ("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", "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)), @@ -478,8 +629,12 @@ impl StaticTable { ("range", "bytes=0-") => Some(TableIndex::Field(55)), ("range", _) => Some(TableIndex::FieldName(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)), + ("strict-transport-security", "max-age=31536000; includesubdomains") => { + Some(TableIndex::Field(57)) + } + ("strict-transport-security", "max-age=31536000; includesubdomains; preload") => { + Some(TableIndex::Field(58)) + } ("strict-transport-security", _) => Some(TableIndex::FieldName(56)), ("vary", "accept-encoding") => Some(TableIndex::Field(59)), ("vary", "origin") => Some(TableIndex::Field(60)), @@ -495,7 +650,9 @@ impl StaticTable { ("access-control-allow-headers", "*") => Some(TableIndex::Field(75)), ("access-control-allow-headers", _) => Some(TableIndex::FieldName(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", "get, post, options") => { + Some(TableIndex::Field(77)) + } ("access-control-allow-methods", "options") => Some(TableIndex::Field(78)), ("access-control-allow-methods", _) => Some(TableIndex::FieldName(76)), ("access-control-expose-headers", "content-length") => Some(TableIndex::Field(79)), @@ -508,7 +665,10 @@ impl StaticTable { ("alt-svc", "clear") => Some(TableIndex::Field(83)), ("alt-svc", _) => Some(TableIndex::FieldName(83)), ("authorization", _) => Some(TableIndex::FieldName(84)), - ("content-security-policy", "script-src 'none'; object-src 'none'; base-uri 'none'") => Some(TableIndex::Field(85)), + ( + "content-security-policy", + "script-src 'none'; object-src 'none'; base-uri 'none'", + ) => Some(TableIndex::Field(85)), ("content-security-policy", _) => Some(TableIndex::FieldName(85)), ("early-data", "1") => Some(TableIndex::Field(86)), ("early-data", _) => Some(TableIndex::FieldName(86)), @@ -567,4 +727,4 @@ impl Field { Field::Other(s) => s, } } -} \ No newline at end of file +} diff --git a/ylong_http/src/lib.rs b/ylong_http/src/lib.rs index 9fac33a..a38a699 100644 --- a/ylong_http/src/lib.rs +++ b/ylong_http/src/lib.rs @@ -41,6 +41,7 @@ pub mod request; pub mod response; pub mod version; +mod pseudo; #[cfg(test)] pub(crate) mod test_util; diff --git a/ylong_http/src/h2/pseudo.rs b/ylong_http/src/pseudo.rs similarity index 57% rename from ylong_http/src/h2/pseudo.rs rename to ylong_http/src/pseudo.rs index 2a15d35..ea732bc 100644 --- a/ylong_http/src/h2/pseudo.rs +++ b/ylong_http/src/pseudo.rs @@ -17,17 +17,16 @@ /// /// # Note /// The current structure is not responsible for checking every value. -// TODO: 考虑将 PseudoHeaders 拆分成 `RequestPseudo` 和 `ResponsePseudo`. +// TODO: Consider Split PseudoHeaders into `RequestPseudo` and `ResponsePseudo`. #[derive(Clone, PartialEq, Eq)] pub struct PseudoHeaders { - authority: Option, - method: Option, - path: Option, - scheme: Option, - status: Option, + pub(crate) authority: Option, + pub(crate) method: Option, + pub(crate) path: Option, + pub(crate) scheme: Option, + pub(crate) status: Option, } -// TODO: 去掉冗余的方法。 impl PseudoHeaders { /// Create a new `PseudoHeaders`. pub(crate) fn new() -> Self { @@ -53,16 +52,6 @@ impl PseudoHeaders { 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() @@ -73,16 +62,6 @@ impl PseudoHeaders { 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() @@ -93,16 +72,6 @@ impl PseudoHeaders { 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() @@ -113,16 +82,6 @@ impl PseudoHeaders { 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() @@ -133,16 +92,6 @@ impl PseudoHeaders { 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() @@ -157,7 +106,7 @@ impl Default for PseudoHeaders { #[cfg(test)] mod ut_pseudo_headers { - use crate::h2::pseudo::PseudoHeaders; + use crate::pseudo::PseudoHeaders; /// UT test cases for `PseudoHeaders::new`. /// @@ -201,10 +150,10 @@ mod ut_pseudo_headers { #[test] fn ut_pseudo_headers_authority() { let mut pseudo = PseudoHeaders::new(); - assert!(pseudo.authority().is_none()); + assert!(pseudo.authority.is_none()); pseudo.authority = Some(String::from("authority")); - assert_eq!(pseudo.authority(), Some("authority")); + assert_eq!(pseudo.authority, Some(String::from("authority"))); } /// UT test cases for `PseudoHeaders::set_authority`. @@ -217,13 +166,13 @@ mod ut_pseudo_headers { #[test] fn ut_pseudo_headers_set_authority() { let mut pseudo = PseudoHeaders::new(); - assert!(pseudo.authority().is_none()); + assert!(pseudo.authority.is_none()); - pseudo.set_authority(Some(String::from("authority"))); - assert_eq!(pseudo.authority(), Some("authority")); + pseudo.authority = Some(String::from("authority")); + assert_eq!(pseudo.authority, Some(String::from("authority"))); - pseudo.set_authority(None); - assert!(pseudo.authority().is_none()); + pseudo.authority = None; + assert!(pseudo.authority.is_none()); } /// UT test cases for `PseudoHeaders::take_authority`. @@ -260,56 +209,6 @@ mod ut_pseudo_headers { 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 @@ -326,40 +225,6 @@ mod ut_pseudo_headers { 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 @@ -393,40 +258,6 @@ mod ut_pseudo_headers { 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 @@ -460,40 +291,6 @@ mod ut_pseudo_headers { 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 -- Gitee From b045cb6f2366132235b585840037e9d4062f36b8 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Sat, 7 Oct 2023 13:52:57 +0800 Subject: [PATCH 6/8] QPACK implementation and optimization Signed-off-by: Weng Shihao --- ylong_http/src/h3/mod.rs | 5 +- ylong_http/src/h3/parts.rs | 2 +- ylong_http/src/h3/qpack/decoder.rs | 262 ++++++---- ylong_http/src/h3/qpack/encoder.rs | 581 +++++++++++++--------- ylong_http/src/h3/qpack/error.rs | 8 +- ylong_http/src/h3/qpack/format/decoder.rs | 138 ++--- ylong_http/src/h3/qpack/format/encoder.rs | 117 ++--- ylong_http/src/h3/qpack/integer.rs | 8 +- ylong_http/src/h3/qpack/mod.rs | 13 +- ylong_http/src/h3/qpack/table.rs | 39 +- ylong_http/src/lib.rs | 2 +- ylong_http/src/test_util.rs | 2 +- 12 files changed, 682 insertions(+), 495 deletions(-) diff --git a/ylong_http/src/h3/mod.rs b/ylong_http/src/h3/mod.rs index 61d62e5..6348dae 100644 --- a/ylong_http/src/h3/mod.rs +++ b/ylong_http/src/h3/mod.rs @@ -13,5 +13,6 @@ // TODO: `HTTP/3` Module. -mod parts; -mod qpack; + +pub mod parts; +pub mod qpack; diff --git a/ylong_http/src/h3/parts.rs b/ylong_http/src/h3/parts.rs index b263643..cc2ba5b 100644 --- a/ylong_http/src/h3/parts.rs +++ b/ylong_http/src/h3/parts.rs @@ -43,7 +43,7 @@ impl Parts { self.pseudo.is_empty() && self.map.is_empty() } - pub(crate) fn update(&mut self, headers: Field, value: String) { + pub fn update(&mut self, headers: Field, value: String) { match headers { Field::Authority => self.pseudo.authority = Some(value), Field::Method => self.pseudo.method = Some(value), diff --git a/ylong_http/src/h3/qpack/decoder.rs b/ylong_http/src/h3/qpack/decoder.rs index 0c97c11..8c60909 100644 --- a/ylong_http/src/h3/qpack/decoder.rs +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -12,8 +12,8 @@ // limitations under the License. use crate::h3::parts::Parts; -use crate::h3::qpack::error::ErrorCode::{QPACK_DECOMPRESSION_FAILED, QPACK_ENCODER_STREAM_ERROR}; -use crate::h3::qpack::error::H3Error_QPACK; +use crate::h3::qpack::error::ErrorCode::{QpackDecompressionFailed, QpackEncoderStreamError}; +use crate::h3::qpack::error::H3errorQpack; use crate::h3::qpack::{ DeltaBase, EncoderInstPrefixBit, EncoderInstruction, MidBit, ReprPrefixBit, Representation, RequireInsertCount, @@ -27,23 +27,56 @@ use crate::h3::qpack::integer::Integer; use crate::h3::qpack::table::Field::Path; use crate::h3::qpack::table::{DynamicTable, Field, TableSearcher}; -struct FiledLines { +/// An decoder is used to de-compress field in a compression format for efficiently representing +/// HTTP fields that is to be used in HTTP/3. This is a variation of HPACK compression that seeks +/// to reduce head-of-line blocking. +/// +/// # Examples +/// ``` +/// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +/// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +/// use crate::ylong_http::test_util::decode; +/// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +/// +/// // Required content: +/// let mut dynamic_table = DynamicTable::with_empty(); +/// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +/// +/// //decode instruction +/// // convert hex string to dec-array +/// let mut inst = decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468").unwrap().as_slice().to_vec(); +/// decoder.decode_ins(&mut inst); +/// +/// //decode field section +/// // convert hex string to dec-array +/// let mut repr = decode("03811011").unwrap().as_slice().to_vec(); +/// decoder.decode_repr(&mut repr); +/// +/// ``` + +pub(crate) struct FiledLines { parts: Parts, header_size: usize, } -pub(crate) struct QpackDecoder<'a> { +pub struct QpackDecoder<'a> { field_list_size: usize, + // max header list size table: &'a mut DynamicTable, + // dynamic table repr_state: Option, + // field decode state inst_state: Option, + // instruction decode state lines: FiledLines, + // field lines, which is used to store the decoded field lines base: usize, - require_insert_count: usize, + // RFC required, got from field section prefix + require_insert_count: usize, // RFC required, got from field section prefix } impl<'a> QpackDecoder<'a> { - pub(crate) fn new(field_list_size: usize, table: &'a mut DynamicTable) -> Self { + pub fn new(field_list_size: usize, table: &'a mut DynamicTable) -> Self { Self { field_list_size, table, @@ -59,12 +92,12 @@ impl<'a> QpackDecoder<'a> { } /// Users can call `decode_ins` multiple times to decode decoder instructions. - pub(crate) fn decode_ins(&mut self, buf: &mut [u8]) -> Result<(), H3Error_QPACK> { + pub fn decode_ins(&mut self, buf: &[u8]) -> Result<(), H3errorQpack> { let mut decoder = EncInstDecoder::new(); let mut updater = Updater::new(&mut self.table); let mut cnt = 0; loop { - match decoder.decode(&mut buf[cnt..], &mut self.inst_state)? { + match decoder.decode(&buf[cnt..], &mut self.inst_state)? { Some(inst) => match inst { (offset, EncoderInstruction::SetCap { capacity }) => { println!("set cap"); @@ -112,20 +145,20 @@ impl<'a> QpackDecoder<'a> { /// +---+---------------------------+ /// | Encoded Field Lines ... /// +-------------------------------+ - pub(crate) fn decode_repr(&mut self, buf: &mut [u8]) -> Result<(), H3Error_QPACK> { + pub fn decode_repr(&mut self, buf: &[u8]) -> Result<(), H3errorQpack> { let mut decoder = ReprDecoder::new(); let mut searcher = Searcher::new(self.field_list_size, &self.table, &mut self.lines); let mut cnt = 0; loop { - match decoder.decode(&mut buf[cnt..], &mut self.repr_state)? { + match decoder.decode(&buf[cnt..], &mut self.repr_state)? { Some(( - offset, - Representation::FieldSectionPrefix { - require_insert_count, - signal, - delta_base, - }, - )) => { + offset, + Representation::FieldSectionPrefix { + require_insert_count, + signal, + delta_base, + }, + )) => { cnt += offset; if require_insert_count.0 == 0 { self.require_insert_count = 0; @@ -145,7 +178,9 @@ impl<'a> QpackDecoder<'a> { self.base = self.require_insert_count + delta_base.0; } searcher.base = self.base; - //todo:block + if self.require_insert_count > self.table.insert_count { + //todo:block + } } Some((offset, Representation::Indexed { mid_bit, index })) => { cnt += offset; @@ -156,36 +191,36 @@ impl<'a> QpackDecoder<'a> { searcher.search(Representation::IndexedWithPostIndex { index })?; } Some(( - offset, - Representation::LiteralWithIndexing { - mid_bit, - name, - value, - }, - )) => { + offset, + Representation::LiteralWithIndexing { + mid_bit, + name, + value, + }, + )) => { println!("offset:{}", offset); cnt += offset; searcher.search_literal_with_indexing(mid_bit, name, value)?; } Some(( - offset, - Representation::LiteralWithPostIndexing { - mid_bit, - name, - value, - }, - )) => { + offset, + Representation::LiteralWithPostIndexing { + mid_bit, + name, + value, + }, + )) => { cnt += offset; searcher.search_literal_with_post_indexing(mid_bit, name, value)?; } Some(( - offset, - Representation::LiteralWithLiteralName { - mid_bit, - name, - value, - }, - )) => { + offset, + Representation::LiteralWithLiteralName { + mid_bit, + name, + value, + }, + )) => { cnt += offset; searcher.search_listeral_with_literal(mid_bit, name, value)?; } @@ -210,13 +245,13 @@ impl<'a> QpackDecoder<'a> { &mut self, stream_id: usize, buf: &mut [u8], - ) -> Result<(Parts, Option), H3Error_QPACK> { + ) -> Result<(Parts, Option), H3errorQpack> { if !self.repr_state.is_none() { - return Err(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)); + return Err(H3errorQpack::ConnectionError(QpackDecompressionFailed)); } self.lines.header_size = 0; if self.require_insert_count > 0 { - let mut ack = Integer::index(0x80, stream_id, 0x7f); + let 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))); @@ -237,13 +272,13 @@ impl<'a> QpackDecoder<'a> { &mut self, stream_id: usize, buf: &mut [u8], - ) -> Result { - let mut ack = Integer::index(0x40, stream_id, 0x3f); + ) -> Result { + let ack = Integer::index(0x40, stream_id, 0x3f); let size = ack.encode(buf); if let Ok(size) = size { return Ok(size); } - Err(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)) + Err(H3errorQpack::ConnectionError(QpackDecompressionFailed)) } } @@ -256,7 +291,7 @@ impl<'a> Updater<'a> { Self { table } } - fn update_capacity(&mut self, capacity: usize) -> Result<(), H3Error_QPACK> { + fn update_capacity(&mut self, capacity: usize) -> Result<(), H3errorQpack> { self.table.update_size(capacity); Ok(()) } @@ -266,18 +301,18 @@ impl<'a> Updater<'a> { mid_bit: MidBit, name: Name, value: Vec, - ) -> Result<(), H3Error_QPACK> { + ) -> Result<(), H3errorQpack> { 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_QPACK> { + fn duplicate(&mut self, index: usize) -> Result<(), H3errorQpack> { let table_searcher = TableSearcher::new(self.table); let (f, v) = table_searcher .find_field_dynamic(self.table.insert_count - index - 1) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; + .ok_or(H3errorQpack::ConnectionError(QpackEncoderStreamError))?; self.table.update(f, v); Ok(()) } @@ -288,27 +323,27 @@ impl<'a> Updater<'a> { name: Name, value: Vec, insert_count: usize, - ) -> Result<(Field, String), H3Error_QPACK> { + ) -> Result<(Field, String), H3errorQpack> { 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_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? + .ok_or(H3errorQpack::ConnectionError(QpackEncoderStreamError))? } else { searcher .find_field_name_dynamic(insert_count - index - 1) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))? + .ok_or(H3errorQpack::ConnectionError(QpackEncoderStreamError))? } } Name::Literal(octets) => Field::Other( String::from_utf8(octets) - .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?, + .map_err(|_| H3errorQpack::ConnectionError(QpackEncoderStreamError))?, ), }; let v = String::from_utf8(value) - .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_ENCODER_STREAM_ERROR))?; + .map_err(|_| H3errorQpack::ConnectionError(QpackEncoderStreamError))?; Ok((h, v)) } } @@ -330,7 +365,7 @@ impl<'a> Searcher<'a> { } } - fn search(&mut self, repr: Representation) -> Result<(), H3Error_QPACK> { + fn search(&mut self, repr: Representation) -> Result<(), H3errorQpack> { match repr { Representation::Indexed { mid_bit, index } => self.search_indexed(mid_bit, index), Representation::IndexedWithPostIndex { index } => self.search_post_indexed(index), @@ -338,30 +373,30 @@ impl<'a> Searcher<'a> { } } - fn search_indexed(&mut self, mid_bit: MidBit, index: usize) -> Result<(), H3Error_QPACK> { + fn search_indexed(&mut self, mid_bit: MidBit, index: usize) -> Result<(), H3errorQpack> { let table_searcher = TableSearcher::new(&mut self.table); if let Some(true) = mid_bit.t { let (f, v) = table_searcher .find_field_static(index) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))?; self.lines.parts.update(f, v); return Ok(()); } else { let (f, v) = table_searcher .find_field_dynamic(self.base - index - 1) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))?; self.lines.parts.update(f, v); return Ok(()); } } - fn search_post_indexed(&mut self, index: usize) -> Result<(), H3Error_QPACK> { + fn search_post_indexed(&mut self, index: usize) -> Result<(), H3errorQpack> { let table_searcher = TableSearcher::new(&mut self.table); let (f, v) = table_searcher .find_field_dynamic(self.base + index) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))?; self.check_field_list_size(&f, &v)?; self.lines.parts.update(f, v); return Ok(()); @@ -372,7 +407,7 @@ impl<'a> Searcher<'a> { mid_bit: MidBit, name: Name, value: Vec, - ) -> Result<(), H3Error_QPACK> { + ) -> Result<(), H3errorQpack> { let (f, v) = self.get_field_by_name_and_value( mid_bit, name, @@ -389,7 +424,7 @@ impl<'a> Searcher<'a> { mid_bit: MidBit, name: Name, value: Vec, - ) -> Result<(), H3Error_QPACK> { + ) -> Result<(), H3errorQpack> { let (f, v) = self.get_field_by_name_and_value( mid_bit, name, @@ -406,7 +441,7 @@ impl<'a> Searcher<'a> { mid_bit: MidBit, name: Name, value: Vec, - ) -> Result<(), H3Error_QPACK> { + ) -> Result<(), H3errorQpack> { let (h, v) = self.get_field_by_name_and_value( mid_bit, name, @@ -424,7 +459,7 @@ impl<'a> Searcher<'a> { name: Name, value: Vec, repr: ReprPrefixBit, - ) -> Result<(Field, String), H3Error_QPACK> { + ) -> Result<(Field, String), H3errorQpack> { let h = match name { Name::Index(index) => { if repr == ReprPrefixBit::LITERALWITHINDEXING { @@ -432,36 +467,36 @@ impl<'a> Searcher<'a> { if let Some(true) = mid_bit.t { searcher .find_field_name_static(index) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))? } else { searcher .find_field_name_dynamic(self.base - index - 1) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))? } } else { let searcher = TableSearcher::new(&self.table); searcher .find_field_name_dynamic(self.base + index) - .ok_or(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))? + .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))? } } Name::Literal(octets) => Field::Other( String::from_utf8(octets) - .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?, + .map_err(|_| H3errorQpack::ConnectionError(QpackDecompressionFailed))?, ), }; let v = String::from_utf8(value) - .map_err(|_| H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED))?; + .map_err(|_| H3errorQpack::ConnectionError(QpackDecompressionFailed))?; 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_QPACK> { + fn check_field_list_size(&mut self, key: &Field, value: &String) -> Result<(), H3errorQpack> { 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_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)) + Err(H3errorQpack::ConnectionError(QpackDecompressionFailed)) } else { Ok(()) } @@ -493,19 +528,20 @@ mod ut_qpack_decoder { test_literal_post_indexing_dynamic(); test_literal_with_literal_name(); test_setcap(); + decode_long_field(); fn get_state(state: &Option) { match state { - Some(x @ ReprDecodeState::FiledSectionPrefix(_)) => { + Some(ReprDecodeState::FiledSectionPrefix(_)) => { println!("FiledSectionPrefix"); } - Some(x @ ReprDecodeState::ReprIndex(_)) => { + Some(ReprDecodeState::ReprIndex(_)) => { println!("Indexed"); } - Some(x @ ReprDecodeState::ReprValueString(_)) => { + Some(ReprDecodeState::ReprValueString(_)) => { println!("ReprValueString"); } - Some(x @ ReprDecodeState::ReprNameAndValue(_)) => { + Some(ReprDecodeState::ReprNameAndValue(_)) => { println!("ReprNameAndValue"); } None => { @@ -586,8 +622,9 @@ mod ut_qpack_decoder { dynamic_table_insert_eviction(); fn literal_field_line_with_name_reference() { println!("run literal_field_line_with_name_reference"); - let mut dynamic_table = DynamicTable::with_capacity(4096); - let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); + let decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); qpack_test_case!( decoder, "0000510b2f696e6465782e68746d6c", @@ -598,14 +635,15 @@ mod ut_qpack_decoder { } fn dynamic_table() { println!("dynamic_table"); - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); let mut ins = decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468") .unwrap() .as_slice() .to_vec(); - decoder.decode_ins(&mut ins); + let _ = decoder.decode_ins(&mut ins); get_state(&decoder.repr_state); qpack_test_case!( decoder, @@ -615,13 +653,14 @@ mod ut_qpack_decoder { ); } fn speculative_insert() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); let mut ins = decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565") .unwrap() .as_slice() .to_vec(); - decoder.decode_ins(&mut ins); + let _ = decoder.decode_ins(&mut ins); qpack_test_case!( decoder, "028010", @@ -630,20 +669,18 @@ mod ut_qpack_decoder { ); } fn duplicate_instruction_stream_cancellation() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); dynamic_table.update(Field::Authority, String::from("www.example.com")); dynamic_table.update(Field::Path, String::from("/sample/path")); dynamic_table.update( Field::Other(String::from("custom-key")), String::from("custom-value"), ); - dynamic_table.ref_count.insert(0, 0); //Acked - dynamic_table.ref_count.insert(1, 0); //Acked - dynamic_table.ref_count.insert(2, 0); //Acked dynamic_table.known_received_count = 3; let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); let mut ins = decode("02").unwrap().as_slice().to_vec(); - decoder.decode_ins(&mut ins); + let _ = decoder.decode_ins(&mut ins); qpack_test_case!( decoder, "058010c180", @@ -653,7 +690,8 @@ mod ut_qpack_decoder { ); } fn dynamic_table_insert_eviction() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); dynamic_table.update(Field::Authority, String::from("www.example.com")); dynamic_table.update(Field::Path, String::from("/sample/path")); dynamic_table.update( @@ -661,16 +699,13 @@ mod ut_qpack_decoder { String::from("custom-value"), ); dynamic_table.update(Field::Authority, String::from("www.example.com")); - dynamic_table.ref_count.insert(0, 0); //Acked - dynamic_table.ref_count.insert(1, 0); //Acked - dynamic_table.ref_count.insert(2, 0); //Acked dynamic_table.known_received_count = 3; let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); let mut ins = decode("810d637573746f6d2d76616c756532") .unwrap() .as_slice() .to_vec(); - decoder.decode_ins(&mut ins); + let _ = decoder.decode_ins(&mut ins); qpack_test_case!( decoder, "068111", @@ -682,22 +717,24 @@ mod ut_qpack_decoder { fn test_need_more() { println!("test_need_more"); - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); let mut text = decode("00").unwrap().as_slice().to_vec(); //510b2f696e6465782e68746d6c println!("text={:?}", text); - decoder.decode_repr(&mut text); + let _ = decoder.decode_repr(&mut text); get_state(&decoder.repr_state); let mut text2 = decode("00510b2f696e6465782e68746d6c") .unwrap() .as_slice() .to_vec(); println!("text2={:?}", text2); - decoder.decode_repr(&mut text2); + let _ = decoder.decode_repr(&mut text2); } fn test_indexed_static() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); qpack_test_case!( QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), @@ -708,7 +745,8 @@ mod ut_qpack_decoder { } fn test_indexed_dynamic() { // Test index "custom-field"=>"custom-value" in dynamic table - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); //abs = 0 dynamic_table.update( Field::Other(String::from("custom-field")), @@ -731,7 +769,8 @@ mod ut_qpack_decoder { } fn test_post_indexed_dynamic() { // Test index "custom-field"=>"custom-value" in dynamic table - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); //abs = 0 dynamic_table.update( Field::Other(String::from("custom1-field")), @@ -758,7 +797,8 @@ mod ut_qpack_decoder { ); } fn test_literal_indexing_static() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); qpack_test_case!( QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), "00007f020d637573746f6d312d76616c7565", @@ -768,7 +808,8 @@ mod ut_qpack_decoder { } fn test_literal_indexing_dynamic() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); //abs = 0 dynamic_table.update( Field::Other(String::from("custom-field")), @@ -792,7 +833,8 @@ mod ut_qpack_decoder { fn test_literal_post_indexing_dynamic() { // Test index "custom-field"=>"custom-value" in dynamic table - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); //abs = 0 dynamic_table.update( Field::Other(String::from("custom1-field")), @@ -820,7 +862,8 @@ mod ut_qpack_decoder { } fn test_literal_with_literal_name() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); qpack_test_case!( QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table), "00003706637573746f6d322d76616c75650d637573746f6d312d76616c7565", @@ -830,11 +873,24 @@ mod ut_qpack_decoder { } fn test_setcap() { - let mut dynamic_table = DynamicTable::with_capacity(4096); + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); let mut ins = decode("3fbd01").unwrap().as_slice().to_vec(); - decoder.decode_ins(&mut ins); + let _ = decoder.decode_ins(&mut ins); assert_eq!(decoder.table.capacity(), 220); } + + fn decode_long_field() { + let mut dynamic_table = DynamicTable::with_empty(); + dynamic_table.update_size(4096); + let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); + let mut repr = decode("ffffff01ffff01037fffff01") + .unwrap() + .as_slice() + .to_vec(); + let _ = decoder.decode_repr(&mut repr); + assert_eq!(decoder.base, 32382); + } } } diff --git a/ylong_http/src/h3/qpack/encoder.rs b/ylong_http/src/h3/qpack/encoder.rs index fd14bcc..6d392f6 100644 --- a/ylong_http/src/h3/qpack/encoder.rs +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -12,95 +12,140 @@ // limitations under the License. use crate::h3::parts::Parts; -use crate::h3::qpack::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; -use crate::h3::qpack::error::H3Error_QPACK; +use crate::h3::qpack::error::ErrorCode::QpackDecoderStreamError; +use crate::h3::qpack::error::H3errorQpack; use crate::h3::qpack::format::encoder::{ DecInstDecoder, InstDecodeState, PartsIter, ReprEncodeState, SetCap, }; use crate::h3::qpack::format::ReprEncoder; use crate::h3::qpack::integer::{Integer, IntegerEncoder}; -use crate::h3::qpack::table::DynamicTable; +use crate::h3::qpack::table::{DynamicTable, Field}; use crate::h3::qpack::{DecoderInstruction, PrefixMask}; use std::collections::{HashMap, VecDeque}; -pub(crate) struct QpackEncoder { - table: DynamicTable, +/// An encoder is used to compress field in a compression format for efficiently representing +/// HTTP fields that is to be used in HTTP/3. This is a variation of HPACK compression that seeks +/// to reduce head-of-line blocking. +/// +/// # Examples +/// ``` +/// use crate::ylong_http::h3::qpack::encoder::QpackEncoder; +/// use crate::ylong_http::h3::parts::Parts; +/// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +/// use crate::ylong_http::test_util::decode; +/// +/// +/// +/// // the (field, value) is: ("custom-key", "custom-value2") +/// // Required content: +/// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands. +/// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format. +/// let mut encoder_cur = 0; // index of encoder_buf. +/// let mut stream_cur = 0; // index of stream_buf. +/// let mut table = DynamicTable::with_empty(); +/// +/// // create a new encoder. +/// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); +/// +/// // set dynamic table capacity. +/// encoder_cur += encoder.set_capacity(220, &mut encoder_buf[encoder_buf..]); +/// +/// // set field section. +/// let mut field = Parts::new(); +/// field.update(Field::Other(String::from("custom-key")), String::from("custom-value")); +/// encoder.set_parts(field); +/// +/// // encode field section. +/// let (cur1, cur2, _) = encoder.encode(&mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..]); +/// encoder_cur += cur1; +/// stream_cur += cur2; +/// +/// assert_eq!(stream_buf[..encoder_cur].to_vec().as_slice(), decode("028010").unwrap().as_slice()); +/// assert_eq!(stream_buf[..stream_cur].to_vec().as_slice(), decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565").unwrap().as_slice()); +/// +/// +/// ``` + +pub struct QpackEncoder<'a> { + table: &'a mut DynamicTable, + // Headers to be encode. field_iter: Option, + // save the state of encoding field. field_state: Option, + // save the state of decoding instructions. inst_state: Option, - stream_reference: VecDeque>, + // list of fields to be inserted. + insert_list: VecDeque<(Field, String)>, + insert_length: usize, + // `RFC`: the number of insertions that the decoder needs to receive before it can decode the field section. + required_insert_count: usize, + stream_id: usize, - // if not insert to dynamic table, the required insert count will be 0. - is_insert: bool, // allow reference to the inserting field default is false. allow_post: bool, // RFC9204-2.1.1.1. if index QpackEncoder<'a> { + pub fn new( + table: &'a mut DynamicTable, stream_id: usize, allow_post: bool, draining_index: usize, - ) -> (QpackEncoder, usize) { - let mut s = Self { - table: DynamicTable::with_capacity(max_size), + ) -> QpackEncoder { + Self { + table: table, field_iter: None, field_state: None, inst_state: None, - stream_reference: VecDeque::new(), + insert_list: VecDeque::new(), + insert_length: 0, + required_insert_count: 0, stream_id, - is_insert: false, allow_post, draining_index, - }; + } + } + + pub fn set_capacity(&mut self, max_size: usize, encoder_buf: &mut [u8]) -> usize { + self.table.update_size(max_size); if let Ok(cur) = SetCap::new(max_size).encode(&mut encoder_buf[..]) { - return (s, cur); + return cur; } - (s, 0) + 0 } - pub(crate) fn set_parts(&mut self, parts: Parts) { + pub fn set_parts(&mut self, parts: Parts) { self.field_iter = Some(PartsIter::new(parts)); } - fn ack(&mut self, stream_id: usize) -> Result, H3Error_QPACK> { + fn ack(&mut self, stream_id: usize) -> Result, H3errorQpack> { 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); - } - self.table.known_received_count += 1; - } - } else { - return Err(H3Error_QPACK::ConnectionError(QPACK_DECODER_STREAM_ERROR)); - } + + if self.table.known_received_count < self.required_insert_count { + self.table.known_received_count = self.required_insert_count; + } else { + return Err(H3errorQpack::ConnectionError(QpackDecoderStreamError)); } + Ok(Some(DecoderInst::Ack)) } /// Users can call `decode_ins` multiple times to decode decoder instructions. - pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result, H3Error_QPACK> { + pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result, H3errorQpack> { let mut decoder = DecInstDecoder::new(buf); loop { match decoder.decode(&mut self.inst_state)? { Some(DecoderInstruction::Ack { stream_id }) => { return self.ack(stream_id); } + //todo: stream cancel Some(DecoderInstruction::StreamCancel { stream_id }) => { assert_eq!(stream_id, self.stream_id); return Ok(Some(DecoderInst::StreamCancel)); } + //todo: insert count increment Some(DecoderInstruction::InsertCountIncrement { increment }) => { self.table.known_received_count += increment; return Ok(Some(DecoderInst::InsertCountIncrement)); @@ -115,44 +160,45 @@ impl QpackEncoder { fn get_prefix(&self, prefix_buf: &mut [u8]) -> usize { let mut cur_prefix = 0; let mut wire_ric = 0; - if self.is_insert { - wire_ric = self.table.insert_count % (2 * self.table.max_entries()) + 1; + if self.required_insert_count != 0 { + wire_ric = self.required_insert_count % (2 * self.table.max_entries()) + 1; } cur_prefix += Integer::index(0x00, wire_ric, 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); + let base = self.table.insert_count; + println!("base: {}", base); + println!("required_insert_count: {}", self.required_insert_count); + if base >= self.required_insert_count { + cur_prefix += Integer::index(0x00, base - self.required_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); + cur_prefix += Integer::index(0x80, self.required_insert_count - base - 1, 0x7f) + .encode(&mut prefix_buf[cur_prefix..]) + .unwrap_or(0); } cur_prefix } /// Users can call `encode` multiple times to encode multiple complete field sections. - pub(crate) fn encode( + /// + /// # Return + pub fn encode( &mut self, - encoder_buf: &mut [u8], - stream_buf: &mut [u8], + encoder_buf: &mut [u8], //instructions encoded results + stream_buf: &mut [u8], //headers encoded results ) -> (usize, usize, Option<([u8; 1024], usize)>) { - let (mut cur_prefix, mut cur_encoder, mut cur_stream) = (0, 0, 0); + let (mut cur_encoder, mut cur_stream) = (0, 0); if self.is_finished() { // denote an end of field section - self.stream_reference.push_back(None); + // self.stream_reference.push_back(None); + //todo: size of prefix_buf let mut prefix_buf = [0u8; 1024]; - cur_prefix = self.get_prefix(&mut prefix_buf[0..]); + let cur_prefix = self.get_prefix(&mut prefix_buf[0..]); + for (field, value) in self.insert_list.iter() { + self.table.update(field.clone(), value.clone()); + } (cur_encoder, cur_stream, Some((prefix_buf, cur_prefix))) } else { let mut encoder = ReprEncoder::new(&mut self.table, self.draining_index); @@ -161,9 +207,10 @@ impl QpackEncoder { &mut self.field_state, &mut encoder_buf[0..], &mut stream_buf[0..], - &mut self.stream_reference, - &mut self.is_insert, self.allow_post, + &mut self.insert_list, + &mut self.required_insert_count, + &mut self.insert_length, ); (cur_encoder, cur_stream, None) } @@ -186,13 +233,9 @@ mod ut_qpack_encoder { use crate::h3::parts::Parts; use crate::h3::qpack::encoder; use crate::h3::qpack::encoder::QpackEncoder; - use crate::h3::qpack::table::Field; + use crate::h3::qpack::table::{DynamicTable, Field}; use crate::test_util::decode; - - #[test] - fn ut_qpack_encoder() { - rfc9204_test_cases(); - macro_rules! qpack_test_cases { + macro_rules! qpack_test_cases { ($enc: expr,$encoder_buf:expr,$encoder_cur:expr, $len: expr, $res: literal,$encoder_res: literal, $size: expr, { $($h: expr, $v: expr $(,)?)*} $(,)?) => { let mut _encoder = $enc; let mut stream_buf = [0u8; $len]; @@ -201,11 +244,11 @@ mod ut_qpack_encoder { let mut parts = Parts::new(); parts.update($h, $v); _encoder.set_parts(parts); - let (mut cur1,mut cur2,_) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]); + let (cur1,cur2,_) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]); $encoder_cur += cur1; stream_cur += cur2; )* - let (mut cur1,mut cur2,mut prefix) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]); + let (cur1, cur2, prefix) = _encoder.encode(&mut $encoder_buf[$encoder_cur..],&mut stream_buf[stream_cur..]); $encoder_cur += cur1; stream_cur += cur2; if let Some((prefix_buf,cur_prefix)) = prefix{ @@ -213,174 +256,262 @@ mod ut_qpack_encoder { stream_buf[..cur_prefix].copy_from_slice(&prefix_buf[..cur_prefix]); stream_cur += cur_prefix; } + println!("stream_buf: {:#?}",stream_buf); let result = decode($res).unwrap(); if let Some(res) = decode($encoder_res){ assert_eq!($encoder_buf[..$encoder_cur].to_vec().as_slice(), res.as_slice()); } - println!("stream_buf: {:#?}",stream_buf); assert_eq!(stream_cur, $len); assert_eq!(stream_buf.as_slice(), result.as_slice()); assert_eq!(_encoder.table.size(), $size); } } + #[test] + /// The encoder sends an encoded field section containing a literal representation of a field + /// with a static name reference. + fn literal_field_line_with_name_reference() { + println!("literal_field_line_with_name_reference"); + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, false, 0); + let mut encoder_cur = encoder.set_capacity(0, &mut encoder_buf[..]); + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 15, "0000510b2f696e6465782e68746d6c", + "20", + 0, + { + Field::Path, + String::from("/index.html"), + }, + ); + } - /// The following test cases are from RFC9204. - fn rfc9204_test_cases() { - literal_field_line_with_name_reference(); - dynamic_table(); - speculative_insert(); - duplicate_instruction_stream_cancellation(); - dynamic_table_insert_eviction(); - - /// The encoder sends an encoded field section containing a literal representation of a field with a static name reference. - fn literal_field_line_with_name_reference() { - let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = - QpackEncoder::with_capacity(0, &mut encoder_buf[..], 0, false, 0); - qpack_test_cases!( - encoder, - encoder_buf, - encoder_cur, - 15, "0000510b2f696e6465782e68746d6c", - "20", - 0, - { - Field::Path, - String::from("/index.html"), - }, - ); - } + #[test] + ///The encoder sets the dynamic table capacity, inserts a header with a dynamic name + /// reference, then sends a potentially blocking, encoded field section referencing + /// this new entry. The decoder acknowledges processing the encoded field section, + /// which implicitly acknowledges all dynamic table insertions up to the Required + /// Insert Count. + fn dynamic_table() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, true, 0); + let mut encoder_cur = encoder.set_capacity(220, &mut encoder_buf[..]); + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 4, "03811011", + "3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468", + 106, + { + Field::Authority, + String::from("www.example.com"), + Field::Path, + String::from("/sample/path"), + }, + ); + } - ///The encoder sets the dynamic table capacity, inserts a header with a dynamic name - /// reference, then sends a potentially blocking, encoded field section referencing - /// this new entry. The decoder acknowledges processing the encoded field section, - /// which implicitly acknowledges all dynamic table insertions up to the Required - /// Insert Count. - fn dynamic_table() { - let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = - QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true, 0); - qpack_test_cases!( - encoder, - encoder_buf, - encoder_cur, - 4, "03811011", - "3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468", - 106, - { - Field::Authority, - String::from("www.example.com"), - Field::Path, - String::from("/sample/path"), - }, - ); - } + #[test] + ///The encoder inserts a header into the dynamic table with a literal name. + /// The decoder acknowledges receipt of the entry. The encoder does not send any + /// encoded field sections. + fn speculative_insert() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, true, 0); + let _ = encoder.set_capacity(220, &mut encoder_buf[..]); + let mut encoder_cur = 0; + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 3, "028010", + "4a637573746f6d2d6b65790c637573746f6d2d76616c7565", + 54, + { + Field::Other(String::from("custom-key")), + String::from("custom-value"), + }, + ); + } - ///The encoder inserts a header into the dynamic table with a literal name. - /// The decoder acknowledges receipt of the entry. The encoder does not send any - /// encoded field sections. - fn speculative_insert() { - let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = - QpackEncoder::with_capacity(220, &mut encoder_buf[..], 0, true, 0); - encoder_cur = 0; - qpack_test_cases!( - encoder, - encoder_buf, - encoder_cur, - 3, "028010", - "4a637573746f6d2d6b65790c637573746f6d2d76616c7565", - 54, - { - Field::Other(String::from("custom-key")), - String::from("custom-value"), - }, - ); - } + #[test] + fn duplicate_instruction_stream_cancellation() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); + let _ = encoder.set_capacity(4096, &mut encoder_buf[..]); + encoder + .table + .update(Field::Authority, String::from("www.example.com")); + encoder + .table + .update(Field::Path, String::from("/sample/path")); + encoder.table.update( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ); + encoder.required_insert_count = 3; + let mut encoder_cur = 0; + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 5, "050080c181", + "02", + 274, + { + Field::Authority, + String::from("www.example.com"), + Field::Path, + String::from("/"), + Field::Other(String::from("custom-key")), + String::from("custom-value") + }, + ); + } - /// ## About the setting of Base in RFC 9204 - /// (1). From RFC: If the encoder inserted entries in the dynamic table while encoding the field - /// section and is referencing them, Required Insert Count will be greater than the Base. - /// (2). From RFC: An encoder that produces table updates before encoding a field section might - /// set Base to the value of Required Insert Count. In such a case, both the Sign bit - /// and the Delta Base will be set to zero. - /// ## My implementation - /// I utilize the above condition (1), and the base is set to the count of decoder known entries(known receive count). - /// Just As the above test: `dynamic_table()` is same as RFC 9204. - /// But, the following test utilized the (2), So, it is something different from RFC 9204. because the above reason. + #[test] + fn dynamic_table_insert_eviction() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); + let _ = encoder.set_capacity(4096, &mut encoder_buf[..]); + encoder + .table + .update(Field::Authority, String::from("www.example.com")); + encoder + .table + .update(Field::Path, String::from("/sample/path")); + encoder.table.update( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ); + encoder + .table + .update(Field::Authority, String::from("www.example.com")); + encoder.required_insert_count = 3; //acked + let mut encoder_cur = 0; + qpack_test_cases!( + encoder, + encoder_buf, + encoder_cur, + 3, "040183", + "810d637573746f6d2d76616c756532", + 272, + { + Field::Other(String::from("custom-key")), + String::from("custom-value2") + }, + ); + } - fn duplicate_instruction_stream_cancellation() { - let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = - QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true, 1); - encoder - .table - .update(Field::Authority, String::from("www.example.com")); - encoder - .table - .update(Field::Path, String::from("/sample/path")); - encoder.table.update( - Field::Other(String::from("custom-key")), - String::from("custom-value"), - ); - encoder.table.ref_count.insert(0, 0); //Acked - encoder.table.ref_count.insert(1, 0); //Acked - encoder.table.ref_count.insert(2, 0); //Acked - encoder.table.known_received_count = 3; - encoder_cur = 0; - qpack_test_cases!( - encoder, - encoder_buf, - encoder_cur, - 5, "058010c180", - "02", - 217, - { - Field::Authority, - String::from("www.example.com"), - Field::Path, - String::from("/"), - Field::Other(String::from("custom-key")), - String::from("custom-value") - }, - ); - } + #[test] + fn test_ack() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); + let mut encoder_cur = encoder.set_capacity(4096, &mut encoder_buf[..]); - fn dynamic_table_insert_eviction() { - let mut encoder_buf = [0u8; 1024]; - let (mut encoder, mut encoder_cur) = - QpackEncoder::with_capacity(4096, &mut encoder_buf[..], 0, true, 1); - encoder - .table - .update(Field::Authority, String::from("www.example.com")); - encoder - .table - .update(Field::Path, String::from("/sample/path")); - encoder.table.update( - Field::Other(String::from("custom-key")), - String::from("custom-value"), - ); - encoder - .table - .update(Field::Authority, String::from("www.example.com")); - encoder.table.ref_count.insert(0, 0); //Acked - encoder.table.ref_count.insert(1, 0); //Acked - encoder.table.ref_count.insert(2, 0); //Acked - encoder.table.known_received_count = 3; - encoder_cur = 0; - qpack_test_cases!( - encoder, - encoder_buf, - encoder_cur, - 3, "068111", - "810d637573746f6d2d76616c756532", - 272, - { - Field::Other(String::from("custom-key")), - String::from("custom-value2") - }, - ); - } + let field_list: [(Field, String); 3] = [ + (Field::Authority, String::from("www.example.com")), + (Field::Path, String::from("/sample/path")), + ( + Field::Other(String::from("custom-key")), + String::from("custom-value"), + ), + ]; + let mut stream_cur = 0; + for (field, value) in field_list.iter() { + let mut parts = Parts::new(); + parts.update(field.clone(), value.clone()); + encoder.set_parts(parts); + let mut stream_buf = [0u8; 1024]; + let ( cur1, cur2, _) = encoder.encode( + &mut encoder_buf[encoder_cur..], + &mut stream_buf[stream_cur..], + ); + encoder_cur += cur1; + stream_cur += cur2; } + let _ = encoder.decode_ins(decode("80").unwrap().as_slice()); + assert_eq!(encoder.table.known_received_count, 3); + } + + #[test] + fn encode_post_name() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); + let _ = encoder.set_capacity(60, &mut encoder_buf[..]); + let mut encoder_cur = 0; + let mut stream_buf = [0u8; 100]; + let mut stream_cur = 0; + let mut parts = Parts::new(); + parts.update( + Field::Other(String::from("custom-key")), + String::from("custom-value1"), + ); + encoder.set_parts(parts); + let ( cur1, cur2, _) = encoder.encode( + &mut encoder_buf[encoder_cur..], + &mut stream_buf[stream_cur..], + ); + encoder_cur += cur1; + stream_cur += cur2; + let mut parts = Parts::new(); + parts.update( + Field::Other(String::from("custom-key")), + String::from("custom-value2"), + ); + encoder.set_parts(parts); + let ( cur1, cur2, _) = encoder.encode( + &mut encoder_buf[encoder_cur..], + &mut stream_buf[stream_cur..], + ); + encoder_cur += cur1; + stream_cur += cur2; + assert_eq!( + [16, 0, 13, 99, 117, 115, 116, 111, 109, 45, 118, 97, 108, 117, 101, 50], + stream_buf[..stream_cur] + ); + assert_eq!( + [74, 99, 117, 115, 116, 111, 109, 45, 107, 101, 121, 13, 99, 117, 115, 116, 111, 109, 45, 118, 97, 108, 117, 101, 49], + encoder_buf[..encoder_cur] + ) + } + #[test] + fn test_indexing_with_litreal() { + let mut encoder_buf = [0u8; 1024]; + let mut table = DynamicTable::with_empty(); + let mut encoder = QpackEncoder::new(&mut table, 0, false, 1); + let _ = encoder.set_capacity(60, &mut encoder_buf[..]); + let encoder_cur = 0; + let mut stream_buf = [0u8; 100]; + let mut stream_cur = 0; + let mut parts = Parts::new(); + parts.update( + Field::Other(String::from("custom-key")), + String::from("custom-value1"), + ); + encoder.set_parts(parts); + let ( _, cur2, _) = encoder.encode( + &mut encoder_buf[encoder_cur..], + &mut stream_buf[stream_cur..], + ); + stream_cur += cur2; + + assert_eq!( + [ + 39, 3, 99, 117, 115, 116, 111, 109, 45, 107, 101, 121, 13, 99, 117, 115, 116, 111, + 109, 45, 118, 97, 108, 117, 101, 49 + ], + stream_buf[..stream_cur] + ); } } diff --git a/ylong_http/src/h3/qpack/error.rs b/ylong_http/src/h3/qpack/error.rs index 3df4992..b0018a9 100644 --- a/ylong_http/src/h3/qpack/error.rs +++ b/ylong_http/src/h3/qpack/error.rs @@ -10,15 +10,15 @@ // 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. -pub enum H3Error_QPACK { +pub enum H3errorQpack { ConnectionError(ErrorCode), } #[derive(Debug, Eq, PartialEq, Clone)] pub enum ErrorCode { - QPACK_DECOMPRESSION_FAILED = 0x0200, + QpackDecompressionFailed = 0x0200, - QPACK_ENCODER_STREAM_ERROR = 0x0201, + QpackEncoderStreamError = 0x0201, - QPACK_DECODER_STREAM_ERROR = 0x0202, + QpackDecoderStreamError = 0x0202, } diff --git a/ylong_http/src/h3/qpack/format/decoder.rs b/ylong_http/src/h3/qpack/format/decoder.rs index 81d2940..0159127 100644 --- a/ylong_http/src/h3/qpack/format/decoder.rs +++ b/ylong_http/src/h3/qpack/format/decoder.rs @@ -10,8 +10,8 @@ // 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. -use crate::h3::qpack::error::ErrorCode::QPACK_DECOMPRESSION_FAILED; -use crate::h3::qpack::error::{ErrorCode, H3Error_QPACK}; +use crate::h3::qpack::error::ErrorCode::QpackDecompressionFailed; +use crate::h3::qpack::error::{ErrorCode, H3errorQpack}; use crate::h3::qpack::format::decoder::DecResult::Error; use crate::h3::qpack::integer::IntegerDecoder; use crate::h3::qpack::{ @@ -31,9 +31,9 @@ impl EncInstDecoder { pub(crate) fn decode( &mut self, - buf: &mut [u8], + buf: &[u8], inst_state: &mut Option, - ) -> Result, H3Error_QPACK> { + ) -> Result, H3errorQpack> { if buf.is_empty() { return Ok(None); } @@ -70,9 +70,9 @@ impl ReprDecoder { /// decode a `Representation`. pub(crate) fn decode( &mut self, - buf: &mut [u8], + buf: &[u8], repr_state: &mut Option, - ) -> Result, H3Error_QPACK> { + ) -> Result, H3errorQpack> { // If buf is empty, leave the state unchanged. let buf_len = buf.len(); if buf.is_empty() { @@ -122,7 +122,7 @@ macro_rules! state_def { } impl $name { - fn decode(self, buf: & mut [u8]) -> DecResult<$decoded, $name> { + fn decode(self, buf: & [u8]) -> DecResult<$decoded, $name> { match self { $( Self::$state(state) => state.decode(buf), @@ -196,7 +196,7 @@ impl FiledSectionPrefix { Self { inner } } - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Representation), ReprDecodeState> { + fn decode(self, buf: &[u8]) -> DecResult<(usize, Representation), ReprDecodeState> { match self.inner.decode(buf) { DecResult::Decoded((buf_index, ric, signal, delta_base)) => DecResult::Decoded(( buf_index, @@ -225,37 +225,37 @@ impl EncInstIndex { fn from_inner(inner: InstIndexInner) -> Self { Self { inner } } - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, EncoderInstruction), InstDecodeState> { + fn decode(self, buf: &[u8]) -> DecResult<(usize, EncoderInstruction), InstDecodeState> { match self.inner.decode(buf) { DecResult::Decoded((buf_index, EncoderInstPrefixBit::SETCAP, _, index)) => { DecResult::Decoded((buf_index, EncoderInstruction::SetCap { capacity: index })) } DecResult::Decoded(( - buf_index, - EncoderInstPrefixBit::INSERTWITHINDEX, - mid_bit, - index, - )) => { + buf_index, + EncoderInstPrefixBit::INSERTWITHINDEX, + mid_bit, + index, + )) => { let res = InstValueString::new( EncoderInstPrefixBit::INSERTWITHINDEX, mid_bit, Name::Index(index), ) - .decode(&mut buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded(( - buf_index, - EncoderInstPrefixBit::INSERTWITHLITERAL, - mid_bit, - namelen, - )) => { + buf_index, + EncoderInstPrefixBit::INSERTWITHLITERAL, + mid_bit, + namelen, + )) => { let res = InstNameAndValue::new( EncoderInstPrefixBit::INSERTWITHLITERAL, mid_bit, namelen, ) - .decode(&mut buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded((remain_buf, EncoderInstPrefixBit::DUPLICATE, _, index)) => { @@ -265,8 +265,8 @@ impl EncInstIndex { DecResult::NeedMore(EncInstIndex::from_inner(inner).into()) } DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3Error_QPACK::ConnectionError( - ErrorCode::QPACK_DECOMPRESSION_FAILED, + _ => DecResult::Error(H3errorQpack::ConnectionError( + ErrorCode::QpackDecompressionFailed, )), } } @@ -283,7 +283,7 @@ impl ReprIndex { fn from_inner(inner: ReprIndexInner) -> Self { Self { inner } } - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Representation), ReprDecodeState> { + fn decode(self, buf: &[u8]) -> DecResult<(usize, Representation), ReprDecodeState> { match self.inner.decode(buf) { DecResult::Decoded((buf_index, ReprPrefixBit::INDEXED, mid_bit, index)) => { DecResult::Decoded((buf_index, Representation::Indexed { mid_bit, index })) @@ -297,38 +297,38 @@ impl ReprIndex { mid_bit, Name::Index(index), ) - .decode(&mut buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded(( - buf_index, - ReprPrefixBit::LITERALWITHPOSTINDEXING, - mid_bit, - index, - )) => { + buf_index, + ReprPrefixBit::LITERALWITHPOSTINDEXING, + mid_bit, + index, + )) => { let res = ReprValueString::new( ReprPrefixBit::LITERALWITHPOSTINDEXING, mid_bit, Name::Index(index), ) - .decode(&mut buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded(( - buf_index, - ReprPrefixBit::LITERALWITHLITERALNAME, - mid_bit, - namelen, - )) => { + buf_index, + ReprPrefixBit::LITERALWITHLITERALNAME, + mid_bit, + namelen, + )) => { let res = ReprNameAndValue::new(ReprPrefixBit::LITERALWITHLITERALNAME, mid_bit, namelen) - .decode(&mut buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::NeedMore(inner) => DecResult::NeedMore(ReprIndex::from_inner(inner).into()), DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3Error_QPACK::ConnectionError( - ErrorCode::QPACK_DECOMPRESSION_FAILED, + _ => DecResult::Error(H3errorQpack::ConnectionError( + ErrorCode::QpackDecompressionFailed, )), } } @@ -339,7 +339,7 @@ pub(crate) struct FSPTwoIntergers; impl FSPTwoIntergers { fn decode( self, - buf: &mut [u8], + buf: &[u8], ) -> DecResult<(usize, RequireInsertCount, bool, DeltaBase), FSPInner> { let mut buf_index = 1; if buf.is_empty() { @@ -350,7 +350,7 @@ impl FSPTwoIntergers { let ric = match IntegerDecoder::first_byte(buf[buf_index - 1], mask.0) { Ok(ric) => ric, Err(mut int) => { - let mut res: usize; + let res: usize; loop { // If `buf` has been completely decoded here, return the current state. @@ -381,7 +381,7 @@ impl FSPTwoIntergers { let delta_base = match IntegerDecoder::first_byte(byte, mask.0) { Ok(delta_base) => delta_base, Err(mut int) => { - let mut res: usize; + let res: usize; loop { // If `buf` has been completely decoded here, return the current state. buf_index += 1; @@ -419,10 +419,10 @@ macro_rules! decode_first_byte { impl $struct_name { fn decode( self, - buf: &mut [u8], + buf: &[u8], ) -> DecResult<(usize, $prefix_type, MidBit, usize), $inner_type> { // If `buf` has been completely decoded here, return the current state. - let mut buf_index = 1; + let buf_index = 1; if buf.is_empty() { return DecResult::NeedMore(self.into()); } @@ -436,8 +436,8 @@ macro_rules! decode_first_byte { Ok(idx) => DecResult::Decoded((buf_index, prefix, 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) => { - let res = <$trailing_bytes>::new(prefix, mid_bit, int) - .decode(&mut buf[buf_index..]); + let res = + <$trailing_bytes>::new(prefix, mid_bit, int).decode(&buf[buf_index..]); if let DecResult::Decoded((cnt, prefix, mid_bit, int)) = res { return DecResult::Decoded((cnt + buf_index, prefix, mid_bit, int)); } else { @@ -482,7 +482,7 @@ macro_rules! trailing_bytes_decoder { fn decode( mut self, - buf: &mut [u8], + buf: &[u8], ) -> DecResult<(usize, $prefix_type, MidBit, usize), $inner_type> { let mut buf_index = 1; let buf_len = buf.len(); @@ -525,7 +525,7 @@ impl LengthTrailingBytes { Self { is_huffman, length } } - fn decode(mut self, buf: &mut [u8]) -> DecResult<(usize, Vec), LiteralString> { + fn decode(mut self, buf: &[u8]) -> DecResult<(usize, Vec), LiteralString> { let mut buf_index = 1; let buf_len = buf.len(); loop { @@ -537,7 +537,7 @@ impl LengthTrailingBytes { (Ok(None), _) => {} (Err(e), _) => return e.into(), (Ok(Some(length)), true) => { - let res = HuffmanStringBytes::new(length).decode(&mut buf[buf_index..]); + let res = HuffmanStringBytes::new(length).decode(&buf[buf_index..]); if let DecResult::Decoded((cnt, vec)) = res { return DecResult::Decoded((cnt + buf_index, vec)); } else { @@ -545,7 +545,7 @@ impl LengthTrailingBytes { } } (Ok(Some(length)), false) => { - let res = AsciiStringBytes::new(length).decode(&mut buf[buf_index..]); + let res = AsciiStringBytes::new(length).decode(&buf[buf_index..]); if let DecResult::Decoded((cnt, vec)) = res { return DecResult::Decoded((cnt + buf_index, vec)); } else { @@ -571,7 +571,7 @@ impl AsciiStringBytes { } } - fn decode(mut self, buf: &mut [u8]) -> DecResult<(usize, Vec), LiteralString> { + fn decode(mut self, buf: &[u8]) -> DecResult<(usize, Vec), LiteralString> { match (buf.len() + self.octets.len()).cmp(&self.length) { Ordering::Greater | Ordering::Equal => { let pos = self.length - self.octets.len(); @@ -608,12 +608,12 @@ macro_rules! name_and_value_decoder { } } - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, $output_type), $state_type> { + fn decode(self, buf: &[u8]) -> DecResult<(usize, $output_type), $state_type> { match self.inner.decode(buf) { DecResult::Decoded((buf_index, octets)) => { let res = <$value_string>::new(self.prefix, self.mid_bit, Name::Literal(octets)) - .decode(&mut buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::NeedMore(inner) => DecResult::NeedMore( @@ -646,8 +646,8 @@ name_and_value_decoder!( pub(crate) struct LengthFirstByte; impl LengthFirstByte { - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Vec), LiteralString> { - let mut buf_index = 1; + fn decode(self, buf: &[u8]) -> DecResult<(usize, Vec), LiteralString> { + let buf_index = 1; if buf.is_empty() { return DecResult::NeedMore(self.into()); } @@ -657,15 +657,15 @@ impl LengthFirstByte { (buf[buf_index - 1] & 0x80) == 0x80, ) { (Ok(len), true) => { - let res = HuffmanStringBytes::new(len).decode(&mut buf[buf_index..]); + let res = HuffmanStringBytes::new(len).decode(&buf[buf_index..]); return_res!(res, buf_index) } (Ok(len), false) => { - let res = AsciiStringBytes::new(len).decode(&mut buf[buf_index..]); + let res = AsciiStringBytes::new(len).decode(&buf[buf_index..]); return_res!(res, buf_index) } (Err(int), huffman) => { - let res = LengthTrailingBytes::new(huffman, int).decode(&mut buf[buf_index..]); + let res = LengthTrailingBytes::new(huffman, int).decode(&buf[buf_index..]); return_res!(res, buf_index) } } @@ -687,22 +687,22 @@ impl HuffmanStringBytes { } } - fn decode(mut self, buf: &mut [u8]) -> DecResult<(usize, Vec), LiteralString> { + fn decode(mut self, buf: &[u8]) -> DecResult<(usize, Vec), 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_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); + return H3errorQpack::ConnectionError(QpackDecompressionFailed).into(); } // let (_, mut remain_buf) = buf.split_at_mut(pos); match self.huffman.finish() { Ok(vec) => DecResult::Decoded((pos, vec)), - Err(_) => H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(), + Err(_) => H3errorQpack::ConnectionError(QpackDecompressionFailed).into(), } } Ordering::Less => { if self.huffman.decode(buf).is_err() { - return H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED).into(); + return H3errorQpack::ConnectionError(QpackDecompressionFailed).into(); } self.read += buf.len(); // let (_, mut remain_buf) = buf.split_at_mut(buf.len()); @@ -744,7 +744,7 @@ impl InstValueString { } } - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, EncoderInstruction), InstDecodeState> { + fn decode(self, buf: &[u8]) -> DecResult<(usize, EncoderInstruction), InstDecodeState> { match (self.inst, self.inner.decode(buf)) { (EncoderInstPrefixBit::INSERTWITHINDEX, DecResult::Decoded((buf_index, value))) => { DecResult::Decoded(( @@ -766,7 +766,7 @@ impl InstValueString { }, )) } - (_, _) => Error(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)), + (_, _) => Error(H3errorQpack::ConnectionError(QpackDecompressionFailed)), } } } @@ -792,7 +792,7 @@ impl ReprValueString { } } - fn decode(self, buf: &mut [u8]) -> DecResult<(usize, Representation), ReprDecodeState> { + fn decode(self, buf: &[u8]) -> DecResult<(usize, Representation), ReprDecodeState> { match (self.repr, self.inner.decode(buf)) { (ReprPrefixBit::LITERALWITHINDEXING, DecResult::Decoded((buf_index, value))) => { DecResult::Decoded(( @@ -824,7 +824,7 @@ impl ReprValueString { }, )) } - (_, _) => Error(H3Error_QPACK::ConnectionError(QPACK_DECOMPRESSION_FAILED)), + (_, _) => Error(H3errorQpack::ConnectionError(QpackDecompressionFailed)), } } } @@ -840,11 +840,11 @@ pub(crate) enum DecResult { NeedMore(S), /// Errors that may occur when decoding. - Error(H3Error_QPACK), + Error(H3errorQpack), } -impl From for DecResult { - fn from(e: H3Error_QPACK) -> Self { +impl From for DecResult { + fn from(e: H3errorQpack) -> Self { DecResult::Error(e) } } diff --git a/ylong_http/src/h3/qpack/format/encoder.rs b/ylong_http/src/h3/qpack/format/encoder.rs index 97ad56b..ae3c781 100644 --- a/ylong_http/src/h3/qpack/format/encoder.rs +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -11,8 +11,8 @@ // See the License for the specific language governing permissions and // limitations under the License. use crate::h3::parts::Parts; -use crate::h3::qpack::error::ErrorCode::QPACK_DECODER_STREAM_ERROR; -use crate::h3::qpack::error::H3Error_QPACK; +use crate::h3::qpack::error::ErrorCode::QpackDecoderStreamError; +use crate::h3::qpack::error::H3errorQpack; use crate::h3::qpack::format::decoder::DecResult; use crate::h3::qpack::integer::{Integer, IntegerDecoder, IntegerEncoder}; use crate::h3::qpack::table::{DynamicTable, Field, TableIndex, TableSearcher}; @@ -46,12 +46,14 @@ impl<'a> ReprEncoder<'a> { field_state: &mut Option, encoder_buffer: &mut [u8], stream_buffer: &mut [u8], - stream_reference: &mut VecDeque>, - is_insert: &mut bool, allow_post: bool, + insert_list: &mut VecDeque<(Field, String)>, + required_insert_count: &mut usize, + insert_length: &mut usize, ) -> (usize, usize) { let mut cur_encoder = 0; let mut cur_stream = 0; + let mut base = self.table.insert_count; if let Some(mut iter) = field_iter.take() { while let Some((h, v)) = iter.next() { let searcher = TableSearcher::new(&self.table); @@ -71,20 +73,23 @@ impl<'a> ReprEncoder<'a> { if dynamic_index == Some(TableIndex::None) || !self.should_index(&dynamic_index) { // if index is close to eviction, drop it and use duplicate - let dyn_index = dynamic_index.clone(); - dynamic_index = Some(TableIndex::None); - + // let dyn_index = dynamic_index.clone(); + // dynamic_index = Some(TableIndex::None); + let mut is_duplicate = false; if static_name_index == Some(TableIndex::None) { dynamic_name_index = searcher.find_index_name_dynamic(&h, &v); } - if self.table.have_enough_space(&h, &v) { - *is_insert = true; - if !self.should_index(&dyn_index) { - if let Some(TableIndex::Field(index)) = dyn_index { - encoder_result = - Duplicate::new(self.table.insert_count - index.clone() - 1) - .encode(&mut encoder_buffer[cur_encoder..]); + if self.table.have_enough_space(&h, &v, &insert_length) { + if !self.should_index(&dynamic_index) { + if let Some(TableIndex::Field(index)) = dynamic_index { + encoder_result = Duplicate::new(base - index.clone() - 1) + .encode(&mut encoder_buffer[cur_encoder..]); + self.table.update(h.clone(), v.clone()); + base = max(base, self.table.insert_count); + dynamic_index = + Some(TableIndex::Field(self.table.insert_count - 1)); + is_duplicate = true; } } else { encoder_result = match ( @@ -100,23 +105,30 @@ impl<'a> ReprEncoder<'a> { false, true, ) - .encode(&mut encoder_buffer[cur_encoder..]) + .encode(&mut encoder_buffer[cur_encoder..]) } // insert with name reference in dynamic table (_, Some(TableIndex::FieldName(index)), true) => { // convert abs index to rel index InsertWithName::new( - self.table.insert_count - index.clone() - 1, + base - index.clone() - 1, v.clone().into_bytes(), false, false, ) - .encode(&mut encoder_buffer[cur_encoder..]) + .encode(&mut encoder_buffer[cur_encoder..]) } // Duplicate (_, Some(TableIndex::FieldName(index)), false) => { - Duplicate::new(index.clone()) - .encode(&mut encoder_buffer[cur_encoder..]) + let res = Duplicate::new(index.clone()) + .encode(&mut encoder_buffer[cur_encoder..]); + self.table.update(h.clone(), v.clone()); + base = max(base, self.table.insert_count); + dynamic_name_index = Some(TableIndex::FieldName( + self.table.insert_count - 1, + )); + is_duplicate = true; + res } // insert with literal name (_, _, _) => InsertWithLiteral::new( @@ -124,19 +136,22 @@ impl<'a> ReprEncoder<'a> { v.clone().into_bytes(), false, ) - .encode(&mut encoder_buffer[cur_encoder..]), + .encode(&mut encoder_buffer[cur_encoder..]), } }; if self.table.size() + h.len() + v.len() + 32 >= self.table.capacity() { self.draining_index += 1; } - let index = self.table.update(h.clone(), v.clone()); - if allow_post { - if let Some(TableIndex::Field(x)) = index { - dynamic_index = Some(TableIndex::Field(x)); + insert_list.push_back((h.clone(), v.clone())); + *insert_length += h.len() + v.len() + 32; + } + if allow_post && !is_duplicate { + for (post_index, (t_h, t_v)) in insert_list.iter().enumerate() { + if t_h == &h && t_v == &v { + dynamic_index = Some(TableIndex::Field(post_index)) } - if let Some(TableIndex::FieldName(index)) = index { - dynamic_name_index = Some(TableIndex::FieldName(index)); + if t_h == &h { + dynamic_name_index = Some(TableIndex::FieldName(post_index)); } } } @@ -146,29 +161,26 @@ impl<'a> ReprEncoder<'a> { 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 { + if base <= index { stream_result = IndexingWithPostName::new( - index - self.table.known_received_count, + index - base, v.clone().into_bytes(), false, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } else { stream_result = IndexingWithName::new( - self.table.known_received_count - index - 1, + base - index - 1, v.clone().into_bytes(), false, false, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } + *required_insert_count = max(*required_insert_count, index + 1); } } else { // Encode with name reference in static table @@ -182,7 +194,7 @@ impl<'a> ReprEncoder<'a> { true, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } } else { stream_result = IndexingWithLiteral::new( @@ -191,7 +203,7 @@ impl<'a> ReprEncoder<'a> { false, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } } } else { @@ -199,22 +211,14 @@ impl<'a> ReprEncoder<'a> { // Encode with index in dynamic table if let Some(TableIndex::Field(index)) = dynamic_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..]); + if base <= index { + stream_result = IndexedWithPostName::new(index - base) + .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..]); + stream_result = Indexed::new(base - index - 1, false) + .encode(&mut stream_buffer[cur_stream..]); } + *required_insert_count = max(*required_insert_count, index + 1); } } } @@ -224,14 +228,12 @@ impl<'a> ReprEncoder<'a> { cur_stream += stream_size; cur_encoder += encoder_size; } - (Err(state), Ok(stream_size)) => { - cur_stream += stream_size; + (Err(state), Ok(_)) => { *field_iter = Some(iter); *field_state = Some(state); return (encoder_buffer.len(), stream_buffer.len()); } - (Ok(encoder_size), Err(state)) => { - cur_encoder += encoder_size; + (Ok(_), Err(state)) => { *field_iter = Some(iter); *field_state = Some(state); return (encoder_buffer.len(), stream_buffer.len()); @@ -306,6 +308,7 @@ pub(crate) enum ReprEncodeState { IndexedWithPostName(IndexedWithPostName), Duplicate(Duplicate), } + pub(crate) struct SetCap { capacity: Integer, } @@ -717,7 +720,7 @@ impl<'a> DecInstDecoder<'a> { pub(crate) fn decode( &mut self, ins_state: &mut Option, - ) -> Result, H3Error_QPACK> { + ) -> Result, H3errorQpack> { if self.buf.is_empty() { return Ok(None); } @@ -770,7 +773,7 @@ impl DecInstIndex { DecResult::Decoded(DecoderInstruction::InsertCountIncrement { increment: index }) } DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3Error_QPACK::ConnectionError(QPACK_DECODER_STREAM_ERROR)), + _ => DecResult::Error(H3errorQpack::ConnectionError(QpackDecoderStreamError)), } } } diff --git a/ylong_http/src/h3/qpack/integer.rs b/ylong_http/src/h3/qpack/integer.rs index 5c396cb..e76fdb5 100644 --- a/ylong_http/src/h3/qpack/integer.rs +++ b/ylong_http/src/h3/qpack/integer.rs @@ -10,7 +10,7 @@ // 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. -use crate::h3::qpack::error::{ErrorCode, H3Error_QPACK}; +use crate::h3::qpack::error::{ErrorCode, H3errorQpack}; use std::cmp::Ordering; pub(crate) struct Integer { @@ -64,13 +64,13 @@ impl IntegerDecoder { /// 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_QPACK> { + pub(crate) fn next_byte(&mut self, byte: u8) -> Result, H3errorQpack> { 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_QPACK::ConnectionError( - ErrorCode::QPACK_DECOMPRESSION_FAILED, + .ok_or(H3errorQpack::ConnectionError( + ErrorCode::QpackDecompressionFailed, ))?; //todo: modify the error code self.shift += 7; match (byte & 0x80) == 0x00 { diff --git a/ylong_http/src/h3/qpack/mod.rs b/ylong_http/src/h3/qpack/mod.rs index 6e0a04b..f8f00c9 100644 --- a/ylong_http/src/h3/qpack/mod.rs +++ b/ylong_http/src/h3/qpack/mod.rs @@ -11,15 +11,16 @@ // See the License for the specific language governing permissions and // limitations under the License. -mod decoder; -mod encoder; -mod error; +pub mod decoder; +pub mod encoder; +pub(crate) mod error; mod format; mod integer; -pub(crate) mod table; - +pub mod table; use crate::h3::qpack::format::decoder::Name; +pub(crate) use decoder::FiledLines; pub(crate) use decoder::QpackDecoder; +pub(crate) use encoder::DecoderInst; pub(crate) use encoder::QpackEncoder; pub(crate) struct RequireInsertCount(usize); @@ -75,7 +76,7 @@ impl DecoderInstPrefixBit { } } - pub(crate) fn prefix_midbit_value(&self, byte: u8) -> MidBit { + pub(crate) fn prefix_midbit_value(&self) -> MidBit { match self.0 { _ => MidBit { n: None, diff --git a/ylong_http/src/h3/qpack/table.rs b/ylong_http/src/h3/qpack/table.rs index f21a54b..c791a5c 100644 --- a/ylong_http/src/h3/qpack/table.rs +++ b/ylong_http/src/h3/qpack/table.rs @@ -89,13 +89,10 @@ impl<'a> TableSearcher<'a> { self.dynamic.field_name(index) } - pub(crate) fn can_index(&self, header: &Field, value: &str) -> bool { - //todo - true - } + } -pub(crate) struct DynamicTable { +pub struct DynamicTable { queue: VecDeque<(Field, String)>, // The size of the dynamic table is the sum of the size of its entries size: usize, @@ -103,19 +100,17 @@ pub(crate) struct DynamicTable { 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 { + pub fn with_empty() -> Self { Self { queue: VecDeque::new(), size: 0, - capacity, + capacity: 0, insert_count: 0, remove_count: 0, known_received_count: 0, - ref_count: HashMap::new(), } } @@ -135,30 +130,32 @@ impl DynamicTable { self.insert_count += 1; self.size += field.len() + value.len() + 32; self.queue.push_back((field.clone(), value.clone())); - self.ref_count - .insert(self.queue.len() + self.remove_count - 1, 0); self.fit_size(); match self.index(&field, &value) { x => x, - _ => Some(TableIndex::None), } } - pub(crate) fn have_enough_space(&self, field: &Field, value: &String) -> bool { - if self.size + field.len() + value.len() + 32 <= self.capacity { + pub(crate) fn have_enough_space( + &self, + field: &Field, + value: &String, + insert_length: &usize, + ) -> bool { + if self.size + field.len() + value.len() + 32 <= self.capacity - insert_length { 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)) { + if i <= self.known_received_count { eviction_space += h.len() + v.len() + 32; } else { - if eviction_space >= field.len() + value.len() + 32 { + if eviction_space - insert_length >= field.len() + value.len() + 32 { return true; } return false; } - if eviction_space >= field.len() + value.len() + 32 { + if eviction_space - insert_length >= field.len() + value.len() + 32 { return true; } } @@ -239,9 +236,9 @@ pub(crate) enum TableIndex { /// 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. +/// as a connection error of type QpackDecompressionFailed. /// If this index is received on the encoder stream, -/// this MUST be treated as a connection error of type QPACK_ENCODER_STREAM_ERROR. +/// this MUST be treated as a connection error of type QpackEncoderStreamError. /// struct StaticTable; @@ -599,7 +596,6 @@ impl StaticTable { ("accept-ranges", _) => Some(TableIndex::FieldName(32)), ("access-control-allow-headers", "cache-control") => Some(TableIndex::Field(33)), ("access-control-allow-headers", "content-type") => Some(TableIndex::Field(34)), - ("access-control-allow-headers", _) => Some(TableIndex::FieldName(33)), ("access-control-allow-origin", "*") => Some(TableIndex::Field(35)), ("access-control-allow-origin", _) => Some(TableIndex::FieldName(35)), ("cache-control", "max-age=0") => Some(TableIndex::Field(36)), @@ -690,13 +686,12 @@ impl StaticTable { ("x-frame-options", _) => Some(TableIndex::FieldName(97)), _ => None, }, - _ => None, } } } #[derive(Clone, PartialEq, Eq, Debug)] -pub(crate) enum Field { +pub enum Field { Authority, Method, Path, diff --git a/ylong_http/src/lib.rs b/ylong_http/src/lib.rs index a38a699..6d94e53 100644 --- a/ylong_http/src/lib.rs +++ b/ylong_http/src/lib.rs @@ -43,7 +43,7 @@ pub mod version; mod pseudo; #[cfg(test)] -pub(crate) mod test_util; +pub mod test_util; #[cfg(feature = "tokio_base")] pub(crate) use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf}; diff --git a/ylong_http/src/test_util.rs b/ylong_http/src/test_util.rs index 7d9c9a7..0d55480 100644 --- a/ylong_http/src/test_util.rs +++ b/ylong_http/src/test_util.rs @@ -11,7 +11,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -pub(crate) fn decode(str: &str) -> Option> { +pub fn decode(str: &str) -> Option> { if str.len() % 2 != 0 { return None; } -- Gitee From f17e3c9a0f5835bb797d0ca24195c17be78a1a5c Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Sat, 7 Oct 2023 14:06:36 +0800 Subject: [PATCH 7/8] QPACK implementation and optimization Signed-off-by: Weng Shihao --- ylong_http/src/h3/mod.rs | 1 - ylong_http/src/h3/qpack/decoder.rs | 56 +++++++++++------------ ylong_http/src/h3/qpack/encoder.rs | 15 +++--- ylong_http/src/h3/qpack/format/decoder.rs | 50 ++++++++++---------- ylong_http/src/h3/qpack/format/encoder.rs | 14 +++--- ylong_http/src/h3/qpack/table.rs | 2 - 6 files changed, 69 insertions(+), 69 deletions(-) diff --git a/ylong_http/src/h3/mod.rs b/ylong_http/src/h3/mod.rs index 6348dae..577cdb2 100644 --- a/ylong_http/src/h3/mod.rs +++ b/ylong_http/src/h3/mod.rs @@ -13,6 +13,5 @@ // TODO: `HTTP/3` Module. - pub mod parts; pub mod qpack; diff --git a/ylong_http/src/h3/qpack/decoder.rs b/ylong_http/src/h3/qpack/decoder.rs index 8c60909..36af398 100644 --- a/ylong_http/src/h3/qpack/decoder.rs +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -152,13 +152,13 @@ impl<'a> QpackDecoder<'a> { loop { match decoder.decode(&buf[cnt..], &mut self.repr_state)? { Some(( - offset, - Representation::FieldSectionPrefix { - require_insert_count, - signal, - delta_base, - }, - )) => { + offset, + Representation::FieldSectionPrefix { + require_insert_count, + signal, + delta_base, + }, + )) => { cnt += offset; if require_insert_count.0 == 0 { self.require_insert_count = 0; @@ -191,36 +191,36 @@ impl<'a> QpackDecoder<'a> { searcher.search(Representation::IndexedWithPostIndex { index })?; } Some(( - offset, - Representation::LiteralWithIndexing { - mid_bit, - name, - value, - }, - )) => { + offset, + Representation::LiteralWithIndexing { + mid_bit, + name, + value, + }, + )) => { println!("offset:{}", offset); cnt += offset; searcher.search_literal_with_indexing(mid_bit, name, value)?; } Some(( - offset, - Representation::LiteralWithPostIndexing { - mid_bit, - name, - value, - }, - )) => { + offset, + Representation::LiteralWithPostIndexing { + mid_bit, + name, + value, + }, + )) => { cnt += offset; searcher.search_literal_with_post_indexing(mid_bit, name, value)?; } Some(( - offset, - Representation::LiteralWithLiteralName { - mid_bit, - name, - value, - }, - )) => { + offset, + Representation::LiteralWithLiteralName { + mid_bit, + name, + value, + }, + )) => { cnt += offset; searcher.search_listeral_with_literal(mid_bit, name, value)?; } diff --git a/ylong_http/src/h3/qpack/encoder.rs b/ylong_http/src/h3/qpack/encoder.rs index 6d392f6..9e8897a 100644 --- a/ylong_http/src/h3/qpack/encoder.rs +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -432,7 +432,7 @@ mod ut_qpack_encoder { parts.update(field.clone(), value.clone()); encoder.set_parts(parts); let mut stream_buf = [0u8; 1024]; - let ( cur1, cur2, _) = encoder.encode( + let (cur1, cur2, _) = encoder.encode( &mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..], ); @@ -458,7 +458,7 @@ mod ut_qpack_encoder { String::from("custom-value1"), ); encoder.set_parts(parts); - let ( cur1, cur2, _) = encoder.encode( + let (cur1, cur2, _) = encoder.encode( &mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..], ); @@ -470,7 +470,7 @@ mod ut_qpack_encoder { String::from("custom-value2"), ); encoder.set_parts(parts); - let ( cur1, cur2, _) = encoder.encode( + let (cur1, cur2, _) = encoder.encode( &mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..], ); @@ -481,7 +481,10 @@ mod ut_qpack_encoder { stream_buf[..stream_cur] ); assert_eq!( - [74, 99, 117, 115, 116, 111, 109, 45, 107, 101, 121, 13, 99, 117, 115, 116, 111, 109, 45, 118, 97, 108, 117, 101, 49], + [ + 74, 99, 117, 115, 116, 111, 109, 45, 107, 101, 121, 13, 99, 117, 115, 116, 111, + 109, 45, 118, 97, 108, 117, 101, 49 + ], encoder_buf[..encoder_cur] ) } @@ -491,7 +494,7 @@ mod ut_qpack_encoder { let mut table = DynamicTable::with_empty(); let mut encoder = QpackEncoder::new(&mut table, 0, false, 1); let _ = encoder.set_capacity(60, &mut encoder_buf[..]); - let encoder_cur = 0; + let encoder_cur = 0; let mut stream_buf = [0u8; 100]; let mut stream_cur = 0; let mut parts = Parts::new(); @@ -500,7 +503,7 @@ mod ut_qpack_encoder { String::from("custom-value1"), ); encoder.set_parts(parts); - let ( _, cur2, _) = encoder.encode( + let (_, cur2, _) = encoder.encode( &mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..], ); diff --git a/ylong_http/src/h3/qpack/format/decoder.rs b/ylong_http/src/h3/qpack/format/decoder.rs index 0159127..9271150 100644 --- a/ylong_http/src/h3/qpack/format/decoder.rs +++ b/ylong_http/src/h3/qpack/format/decoder.rs @@ -231,31 +231,31 @@ impl EncInstIndex { DecResult::Decoded((buf_index, EncoderInstruction::SetCap { capacity: index })) } DecResult::Decoded(( - buf_index, - EncoderInstPrefixBit::INSERTWITHINDEX, - mid_bit, - index, - )) => { + buf_index, + EncoderInstPrefixBit::INSERTWITHINDEX, + mid_bit, + index, + )) => { let res = InstValueString::new( EncoderInstPrefixBit::INSERTWITHINDEX, mid_bit, Name::Index(index), ) - .decode(&buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded(( - buf_index, - EncoderInstPrefixBit::INSERTWITHLITERAL, - mid_bit, - namelen, - )) => { + buf_index, + EncoderInstPrefixBit::INSERTWITHLITERAL, + mid_bit, + namelen, + )) => { let res = InstNameAndValue::new( EncoderInstPrefixBit::INSERTWITHLITERAL, mid_bit, namelen, ) - .decode(&buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded((remain_buf, EncoderInstPrefixBit::DUPLICATE, _, index)) => { @@ -297,29 +297,29 @@ impl ReprIndex { mid_bit, Name::Index(index), ) - .decode(&buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded(( - buf_index, - ReprPrefixBit::LITERALWITHPOSTINDEXING, - mid_bit, - index, - )) => { + buf_index, + ReprPrefixBit::LITERALWITHPOSTINDEXING, + mid_bit, + index, + )) => { let res = ReprValueString::new( ReprPrefixBit::LITERALWITHPOSTINDEXING, mid_bit, Name::Index(index), ) - .decode(&buf[buf_index..]); + .decode(&buf[buf_index..]); return_res!(res, buf_index) } DecResult::Decoded(( - buf_index, - ReprPrefixBit::LITERALWITHLITERALNAME, - mid_bit, - namelen, - )) => { + buf_index, + ReprPrefixBit::LITERALWITHLITERALNAME, + mid_bit, + namelen, + )) => { let res = ReprNameAndValue::new(ReprPrefixBit::LITERALWITHLITERALNAME, mid_bit, namelen) .decode(&buf[buf_index..]); @@ -647,7 +647,7 @@ pub(crate) struct LengthFirstByte; impl LengthFirstByte { fn decode(self, buf: &[u8]) -> DecResult<(usize, Vec), LiteralString> { - let buf_index = 1; + let buf_index = 1; if buf.is_empty() { return DecResult::NeedMore(self.into()); } diff --git a/ylong_http/src/h3/qpack/format/encoder.rs b/ylong_http/src/h3/qpack/format/encoder.rs index ae3c781..fa8ad86 100644 --- a/ylong_http/src/h3/qpack/format/encoder.rs +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -105,7 +105,7 @@ impl<'a> ReprEncoder<'a> { false, true, ) - .encode(&mut encoder_buffer[cur_encoder..]) + .encode(&mut encoder_buffer[cur_encoder..]) } // insert with name reference in dynamic table (_, Some(TableIndex::FieldName(index)), true) => { @@ -116,7 +116,7 @@ impl<'a> ReprEncoder<'a> { false, false, ) - .encode(&mut encoder_buffer[cur_encoder..]) + .encode(&mut encoder_buffer[cur_encoder..]) } // Duplicate (_, Some(TableIndex::FieldName(index)), false) => { @@ -136,7 +136,7 @@ impl<'a> ReprEncoder<'a> { v.clone().into_bytes(), false, ) - .encode(&mut encoder_buffer[cur_encoder..]), + .encode(&mut encoder_buffer[cur_encoder..]), } }; if self.table.size() + h.len() + v.len() + 32 >= self.table.capacity() { @@ -169,7 +169,7 @@ impl<'a> ReprEncoder<'a> { false, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } else { stream_result = IndexingWithName::new( base - index - 1, @@ -178,7 +178,7 @@ impl<'a> ReprEncoder<'a> { false, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } *required_insert_count = max(*required_insert_count, index + 1); } @@ -194,7 +194,7 @@ impl<'a> ReprEncoder<'a> { true, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } } else { stream_result = IndexingWithLiteral::new( @@ -203,7 +203,7 @@ impl<'a> ReprEncoder<'a> { false, false, ) - .encode(&mut stream_buffer[cur_stream..]); + .encode(&mut stream_buffer[cur_stream..]); } } } else { diff --git a/ylong_http/src/h3/qpack/table.rs b/ylong_http/src/h3/qpack/table.rs index c791a5c..4baaf99 100644 --- a/ylong_http/src/h3/qpack/table.rs +++ b/ylong_http/src/h3/qpack/table.rs @@ -88,8 +88,6 @@ impl<'a> TableSearcher<'a> { pub(crate) fn find_field_name_dynamic(&self, index: usize) -> Option { self.dynamic.field_name(index) } - - } pub struct DynamicTable { -- Gitee From 985c1e7b3e71ef389d0c62dcad8f3b7089f19ba6 Mon Sep 17 00:00:00 2001 From: "Signed-off-by: wengshihao" Date: Sat, 7 Oct 2023 18:32:17 +0800 Subject: [PATCH 8/8] QPACK implementation and optimization Signed-off-by: Weng Shihao --- ylong_http/Cargo.toml | 4 +- ylong_http/src/body/mime/mimetype.rs | 2 +- ylong_http/src/h2/decoder.rs | 20 +- ylong_http/src/h2/encoder.rs | 30 +- ylong_http/src/h2/hpack/decoder.rs | 42 +- ylong_http/src/h2/mod.rs | 3 +- ylong_http/src/h2/parts.rs | 12 +- ylong_http/src/{ => h2}/pseudo.rs | 231 +++++++- ylong_http/src/h3/mod.rs | 2 + ylong_http/src/h3/parts.rs | 16 +- ylong_http/src/h3/pseudo.rs | 512 ++++++++++++++++++ ylong_http/src/h3/qpack/decoder.rs | 197 ++++--- ylong_http/src/h3/qpack/encoder.rs | 198 ++++--- ylong_http/src/h3/qpack/error.rs | 6 +- ylong_http/src/h3/qpack/format/decoder.rs | 28 +- ylong_http/src/h3/qpack/format/encoder.rs | 123 +++-- ylong_http/src/h3/qpack/format/mod.rs | 2 +- ylong_http/src/h3/qpack/integer.rs | 2 +- ylong_http/src/h3/qpack/mod.rs | 12 +- ylong_http/src/h3/qpack/table.rs | 14 +- ylong_http/src/lib.rs | 3 +- .../src/async_impl/conn/http2.rs | 10 +- ylong_http_client/src/async_impl/http_body.rs | 2 +- 23 files changed, 1179 insertions(+), 292 deletions(-) rename ylong_http/src/{ => h2}/pseudo.rs (57%) create mode 100644 ylong_http/src/h3/pseudo.rs diff --git a/ylong_http/Cargo.toml b/ylong_http/Cargo.toml index c80d4ad..9a77072 100644 --- a/ylong_http/Cargo.toml +++ b/ylong_http/Cargo.toml @@ -8,7 +8,7 @@ repository = "https://gitee.com/openharmony/commonlibrary_rust_ylong_http" keywords = ["ylong", "http"] [features] -default = ["http1_1", "http2", "tokio_base","huffman","http3"] +default = [] full = [ "http1_1", "http2", @@ -21,7 +21,7 @@ http3 = [] # Uses HTTP/3. huffman = [] # Uses Huffman encoding in `Hpack` and `Qpack`. tokio_base = ["tokio"] # Uses asynchronous components of `tokio` -ylong_base = [] # Uses asynchronous components of `ylong` +ylong_base = ["ylong_runtime"] # Uses asynchronous components of `ylong` [dependencies] tokio = { version = "1.20.1", features = ["io-util"], optional = true } diff --git a/ylong_http/src/body/mime/mimetype.rs b/ylong_http/src/body/mime/mimetype.rs index 0dfc983..8c995eb 100644 --- a/ylong_http/src/body/mime/mimetype.rs +++ b/ylong_http/src/body/mime/mimetype.rs @@ -27,7 +27,7 @@ use crate::error::{ErrorKind, HttpError}; /// between: /// /// ```type/subtype``` -/// +/// /// It is case-insensitive but are traditionally written in lowercase, such as: /// ```application/octet-stream```. /// diff --git a/ylong_http/src/h2/decoder.rs b/ylong_http/src/h2/decoder.rs index f887333..fdde469 100644 --- a/ylong_http/src/h2/decoder.rs +++ b/ylong_http/src/h2/decoder.rs @@ -915,43 +915,33 @@ mod ut_frame_decoder { match *key { ":method" => { assert_eq!( - pseudo - .method - .clone() - .expect("pseudo.method get failed !"), + pseudo.method().expect("pseudo.method get failed !"), *value ); } ":scheme" => { assert_eq!( - pseudo - .scheme - .clone() - .expect("pseudo.scheme get failed !"), + pseudo.scheme().expect("pseudo.scheme get failed !"), *value ); } ":authority" => { assert_eq!( pseudo - .authority - .clone() + .authority() .expect("pseudo.authority get failed !"), *value ); } ":path" => { assert_eq!( - pseudo.path.clone().expect("pseudo.path get failed !"), + pseudo.path().expect("pseudo.path get failed !"), *value ); } ":status" => { assert_eq!( - pseudo - .status - .clone() - .expect("pseudo.status get failed !"), + pseudo.status().expect("pseudo.status get failed !"), *value ); } diff --git a/ylong_http/src/h2/encoder.rs b/ylong_http/src/h2/encoder.rs index 4da309e..a9257aa 100644 --- a/ylong_http/src/h2/encoder.rs +++ b/ylong_http/src/h2/encoder.rs @@ -1240,10 +1240,12 @@ mod ut_frame_encoder { let mut frame_encoder = FrameEncoder::new(4096, 8190); let mut new_parts = Parts::new(); - new_parts.pseudo.method = Some("GET".to_string()); - new_parts.pseudo.scheme = Some("https".to_string()); - new_parts.pseudo.path = Some("/code".to_string()); - new_parts.pseudo.authority = Some("example.com".to_string()); + new_parts.pseudo.set_method(Some("GET".to_string())); + new_parts.pseudo.set_scheme(Some("https".to_string())); + new_parts.pseudo.set_path(Some("/code".to_string())); + new_parts + .pseudo + .set_authority(Some("example.com".to_string())); let mut frame_flag = FrameFlags::empty(); frame_flag.set_end_headers(true); frame_flag.set_end_stream(true); @@ -1396,10 +1398,12 @@ mod ut_frame_encoder { let mut encoder = FrameEncoder::new(4096, 8190); let mut new_parts = Parts::new(); - new_parts.pseudo.method = Some("GET".to_string()); - new_parts.pseudo.scheme = Some("https".to_string()); - new_parts.pseudo.path = Some("/code".to_string()); - new_parts.pseudo.authority = Some("example.com".to_string()); + new_parts.pseudo.set_method(Some("GET".to_string())); + new_parts.pseudo.set_scheme(Some("https".to_string())); + new_parts.pseudo.set_path(Some("/code".to_string())); + new_parts + .pseudo + .set_authority(Some("example.com".to_string())); let mut frame_flag = FrameFlags::empty(); frame_flag.set_end_headers(true); frame_flag.set_end_stream(false); @@ -1707,10 +1711,12 @@ mod ut_frame_encoder { let mut frame_encoder = FrameEncoder::new(4096, 8190); let mut new_parts = Parts::new(); assert!(new_parts.is_empty()); - new_parts.pseudo.method = Some("GET".to_string()); - new_parts.pseudo.scheme = Some("https".to_string()); - new_parts.pseudo.path = Some("/code".to_string()); - new_parts.pseudo.authority = Some("example.com".to_string()); + new_parts.pseudo.set_method(Some("GET".to_string())); + new_parts.pseudo.set_scheme(Some("https".to_string())); + new_parts.pseudo.set_path(Some("/code".to_string())); + new_parts + .pseudo + .set_authority(Some("example.com".to_string())); let mut frame_flag = FrameFlags::empty(); frame_flag.set_end_headers(false); diff --git a/ylong_http/src/h2/hpack/decoder.rs b/ylong_http/src/h2/hpack/decoder.rs index a90ec59..8022c9b 100644 --- a/ylong_http/src/h2/hpack/decoder.rs +++ b/ylong_http/src/h2/hpack/decoder.rs @@ -229,11 +229,11 @@ mod ut_hpack_decoder { $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); + 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); }; } @@ -335,7 +335,7 @@ mod ut_hpack_decoder { hpack_test_case!( HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE), "040c2f73616d706c652f70617468", - { None, None, Some(String::from("/sample/path")), None, None }, + { None, None, Some("/sample/path"), None, None }, { 0 } ); @@ -351,7 +351,7 @@ mod ut_hpack_decoder { hpack_test_case!( HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE), "82", - { None, Some(String::from("GET")), None, None, None }, + { None, Some("GET"), None, None, None }, { 0 } ); @@ -362,7 +362,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684410f7777772e6578616d706c652e636f6d", - { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, + { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, { 57, Authority => "www.example.com" } ); @@ -370,7 +370,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684be58086e6f2d6361636865", - { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, + { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, { "cache-control" => "no-cache" }, { 110, "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -379,7 +379,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828785bf400a637573746f6d2d6b65790c637573746f6d2d76616c7565", - { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/index.html")), Some(String::from("https")), None }, + { Some("www.example.com"), Some("GET"), Some("/index.html"), Some("https"), None }, { "custom-key" => "custom-value" }, { 164, "custom-key" => "custom-value", "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -392,7 +392,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684418cf1e3c2e5f23a6ba0ab90f4ff", - { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, + { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, { 57, Authority => "www.example.com" } ); @@ -400,7 +400,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828684be5886a8eb10649cbf", - { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/")), Some(String::from("http")), None }, + { Some("www.example.com"), Some("GET"), Some("/"), Some("http"), None }, { "cache-control" => "no-cache" }, { 110, "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -409,7 +409,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "828785bf408825a849e95ba97d7f8925a849e95bb8e8b4bf", - { Some(String::from("www.example.com")), Some(String::from("GET")), Some(String::from("/index.html")), Some(String::from("https")), None }, + { Some("www.example.com"), Some("GET"), Some("/index.html"), Some("https"), None }, { "custom-key" => "custom-value" }, { 164, "custom-key" => "custom-value", "cache-control" => "no-cache", Authority => "www.example.com" } ); @@ -426,7 +426,7 @@ mod ut_hpack_decoder { 2032303a31333a323120474d546e1768\ 747470733a2f2f7777772e6578616d70\ 6c652e636f6d", - { None, None, None, None, Some(String::from("302")) }, + { None, None, None, None, Some("302") }, { "location" => "https://www.example.com", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -445,7 +445,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "4803333037c1c0bf", - { None, None, None, None, Some(String::from("307")) }, + { None, None, None, None, Some("307") }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -470,7 +470,7 @@ mod ut_hpack_decoder { 5541585157454f49553b206d61782d61\ 67653d333630303b2076657273696f6e\ 3d31", - { None, None, None, None, Some(String::from("200")) }, + { None, None, None, None, Some("200") }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:22 GMT", @@ -497,7 +497,7 @@ mod ut_hpack_decoder { 941054d444a8200595040b8166e082a6\ 2d1bff6e919d29ad171863c78f0b97c8\ e9ae82ae43d3", - { None, None, None, None, Some(String::from("302")) }, + { None, None, None, None, Some("302") }, { "location" => "https://www.example.com", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -516,7 +516,7 @@ mod ut_hpack_decoder { hpack_test_case!( &mut hpack_decoder, "4883640effc1c0bf", - { None, None, None, None, Some(String::from("307")) }, + { None, None, None, None, Some("307") }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", @@ -539,7 +539,7 @@ mod ut_hpack_decoder { 77ad94e7821dd7f2e6c7b335dfdfcd5b\ 3960d5af27087f3672c1ab270fb5291f\ 9587316065c003ed4ee5b1063d5007", - { None, None, None, None, Some(String::from("200")) }, + { None, None, None, None, Some("200") }, { "cache-control" => "private", "date" => "Mon, 21 Oct 2013 20:13:22 GMT", @@ -562,7 +562,7 @@ mod ut_hpack_decoder { hpack_test_case!( HpackDecoder::with_max_size(4096, MAX_HEADER_LIST_SIZE), "04", "0c", "2f", "73", "61", "6d", "70", "6c", "65", "2f", "70", "61", "74", "68", - { None, None, Some(String::from("/sample/path")), None, None }, + { None, None, Some("/sample/path"), None, None }, { 0 } ); @@ -573,7 +573,7 @@ mod ut_hpack_decoder { "941054d444a8200595040b8166e082a6", "2d1bff6e919d29ad171863c78f0b97c8", "e9ae82ae43d3", - { None, None, None, None, Some(String::from("302")) }, + { None, None, None, None, Some("302") }, { "location" => "https://www.example.com", "date" => "Mon, 21 Oct 2013 20:13:21 GMT", diff --git a/ylong_http/src/h2/mod.rs b/ylong_http/src/h2/mod.rs index 4c352f6..9bdadd7 100644 --- a/ylong_http/src/h2/mod.rs +++ b/ylong_http/src/h2/mod.rs @@ -56,8 +56,8 @@ mod error; mod frame; mod hpack; mod parts; +mod pseudo; -pub use crate::pseudo::PseudoHeaders; pub use decoder::{FrameDecoder, FrameKind, Frames, FramesIntoIter}; pub use encoder::FrameEncoder; pub use error::{ErrorCode, H2Error}; @@ -67,3 +67,4 @@ pub use frame::{ }; pub(crate) use hpack::{HpackDecoder, HpackEncoder}; pub use parts::Parts; +pub use pseudo::PseudoHeaders; diff --git a/ylong_http/src/h2/parts.rs b/ylong_http/src/h2/parts.rs index af57477..8122ee7 100644 --- a/ylong_http/src/h2/parts.rs +++ b/ylong_http/src/h2/parts.rs @@ -12,8 +12,8 @@ // limitations under the License. use crate::h2::hpack::table::Header; +use crate::h2::pseudo::PseudoHeaders; use crate::headers::Headers; -use crate::pseudo::PseudoHeaders; /// HTTP2 HEADERS frame payload implementation. #[derive(PartialEq, Eq, Clone)] @@ -47,11 +47,11 @@ impl Parts { pub(crate) fn update(&mut self, headers: Header, value: String) { match headers { - Header::Authority => self.pseudo.authority = Some(value), - Header::Method => self.pseudo.method = Some(value), - Header::Path => self.pseudo.path = Some(value), - Header::Scheme => self.pseudo.scheme = Some(value), - Header::Status => self.pseudo.status = Some(value), + Header::Authority => self.pseudo.set_authority(Some(value)), + Header::Method => self.pseudo.set_method(Some(value)), + Header::Path => self.pseudo.set_path(Some(value)), + Header::Scheme => self.pseudo.set_scheme(Some(value)), + Header::Status => self.pseudo.set_status(Some(value)), Header::Other(header) => self.map.append(header.as_str(), value.as_str()).unwrap(), } } diff --git a/ylong_http/src/pseudo.rs b/ylong_http/src/h2/pseudo.rs similarity index 57% rename from ylong_http/src/pseudo.rs rename to ylong_http/src/h2/pseudo.rs index ea732bc..2a15d35 100644 --- a/ylong_http/src/pseudo.rs +++ b/ylong_http/src/h2/pseudo.rs @@ -17,16 +17,17 @@ /// /// # Note /// The current structure is not responsible for checking every value. -// TODO: Consider Split PseudoHeaders into `RequestPseudo` and `ResponsePseudo`. +// TODO: 考虑将 PseudoHeaders 拆分成 `RequestPseudo` 和 `ResponsePseudo`. #[derive(Clone, PartialEq, Eq)] pub struct PseudoHeaders { - pub(crate) authority: Option, - pub(crate) method: Option, - pub(crate) path: Option, - pub(crate) scheme: Option, - pub(crate) status: Option, + authority: Option, + method: Option, + path: Option, + scheme: Option, + status: Option, } +// TODO: 去掉冗余的方法。 impl PseudoHeaders { /// Create a new `PseudoHeaders`. pub(crate) fn new() -> Self { @@ -52,6 +53,16 @@ impl PseudoHeaders { 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() @@ -62,6 +73,16 @@ impl PseudoHeaders { 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() @@ -72,6 +93,16 @@ impl PseudoHeaders { 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() @@ -82,6 +113,16 @@ impl PseudoHeaders { 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() @@ -92,6 +133,16 @@ impl PseudoHeaders { 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() @@ -106,7 +157,7 @@ impl Default for PseudoHeaders { #[cfg(test)] mod ut_pseudo_headers { - use crate::pseudo::PseudoHeaders; + use crate::h2::pseudo::PseudoHeaders; /// UT test cases for `PseudoHeaders::new`. /// @@ -150,10 +201,10 @@ mod ut_pseudo_headers { #[test] fn ut_pseudo_headers_authority() { let mut pseudo = PseudoHeaders::new(); - assert!(pseudo.authority.is_none()); + assert!(pseudo.authority().is_none()); pseudo.authority = Some(String::from("authority")); - assert_eq!(pseudo.authority, Some(String::from("authority"))); + assert_eq!(pseudo.authority(), Some("authority")); } /// UT test cases for `PseudoHeaders::set_authority`. @@ -166,13 +217,13 @@ mod ut_pseudo_headers { #[test] fn ut_pseudo_headers_set_authority() { let mut pseudo = PseudoHeaders::new(); - assert!(pseudo.authority.is_none()); + assert!(pseudo.authority().is_none()); - pseudo.authority = Some(String::from("authority")); - assert_eq!(pseudo.authority, Some(String::from("authority"))); + pseudo.set_authority(Some(String::from("authority"))); + assert_eq!(pseudo.authority(), Some("authority")); - pseudo.authority = None; - assert!(pseudo.authority.is_none()); + pseudo.set_authority(None); + assert!(pseudo.authority().is_none()); } /// UT test cases for `PseudoHeaders::take_authority`. @@ -209,6 +260,56 @@ mod ut_pseudo_headers { 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 @@ -225,6 +326,40 @@ mod ut_pseudo_headers { 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 @@ -258,6 +393,40 @@ mod ut_pseudo_headers { 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 @@ -291,6 +460,40 @@ mod ut_pseudo_headers { 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 diff --git a/ylong_http/src/h3/mod.rs b/ylong_http/src/h3/mod.rs index 577cdb2..d89ded0 100644 --- a/ylong_http/src/h3/mod.rs +++ b/ylong_http/src/h3/mod.rs @@ -15,3 +15,5 @@ pub mod parts; pub mod qpack; + +pub mod pseudo; diff --git a/ylong_http/src/h3/parts.rs b/ylong_http/src/h3/parts.rs index cc2ba5b..c1f1018 100644 --- a/ylong_http/src/h3/parts.rs +++ b/ylong_http/src/h3/parts.rs @@ -12,8 +12,10 @@ // limitations under the License. use crate::h3::qpack::table::Field; +use crate::h3::pseudo::PseudoHeaders; use crate::headers::Headers; -use crate::pseudo::PseudoHeaders; + +/// HTTP2 HEADERS frame payload implementation. #[derive(PartialEq, Eq, Clone)] pub struct Parts { pub(crate) pseudo: PseudoHeaders, @@ -43,13 +45,13 @@ impl Parts { self.pseudo.is_empty() && self.map.is_empty() } - pub fn update(&mut self, headers: Field, value: String) { + pub(crate) fn update(&mut self, headers: Field, value: String) { match headers { - Field::Authority => self.pseudo.authority = Some(value), - Field::Method => self.pseudo.method = Some(value), - Field::Path => self.pseudo.path = Some(value), - Field::Scheme => self.pseudo.scheme = Some(value), - Field::Status => self.pseudo.status = Some(value), + 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(), } } diff --git a/ylong_http/src/h3/pseudo.rs b/ylong_http/src/h3/pseudo.rs new file mode 100644 index 0000000..bbccdf5 --- /dev/null +++ b/ylong_http/src/h3/pseudo.rs @@ -0,0 +1,512 @@ +// 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, + method: Option, + path: Option, + scheme: Option, + status: Option, +} + +// 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 index 36af398..e351858 100644 --- a/ylong_http/src/h3/qpack/decoder.rs +++ b/ylong_http/src/h3/qpack/decoder.rs @@ -12,7 +12,7 @@ // limitations under the License. use crate::h3::parts::Parts; -use crate::h3::qpack::error::ErrorCode::{QpackDecompressionFailed, QpackEncoderStreamError}; +use crate::h3::qpack::error::ErrorCode::{DecompressionFailed, EncoderStreamError}; use crate::h3::qpack::error::H3errorQpack; use crate::h3::qpack::{ DeltaBase, EncoderInstPrefixBit, EncoderInstruction, MidBit, ReprPrefixBit, Representation, @@ -31,28 +31,28 @@ use crate::h3::qpack::table::{DynamicTable, Field, TableSearcher}; /// HTTP fields that is to be used in HTTP/3. This is a variation of HPACK compression that seeks /// to reduce head-of-line blocking. /// -/// # Examples -/// ``` -/// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; -/// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; -/// use crate::ylong_http::test_util::decode; -/// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; -/// -/// // Required content: -/// let mut dynamic_table = DynamicTable::with_empty(); -/// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); -/// -/// //decode instruction -/// // convert hex string to dec-array -/// let mut inst = decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468").unwrap().as_slice().to_vec(); -/// decoder.decode_ins(&mut inst); -/// -/// //decode field section -/// // convert hex string to dec-array -/// let mut repr = decode("03811011").unwrap().as_slice().to_vec(); -/// decoder.decode_repr(&mut repr); -/// -/// ``` +/// # Examples(not run) +// ```no_run +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +// use crate::ylong_http::test_util::decode; +// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +// +// // Required content: +// let mut dynamic_table = DynamicTable::with_empty(); +// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +// +// //decode instruction +// // convert hex string to dec-array +// let mut inst = decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468").unwrap().as_slice().to_vec(); +// decoder.decode_ins(&mut inst); +// +// //decode field section +// // convert hex string to dec-array +// let mut repr = decode("03811011").unwrap().as_slice().to_vec(); +// decoder.decode_repr(&mut repr); +// +// ``` pub(crate) struct FiledLines { parts: Parts, @@ -76,6 +76,19 @@ pub struct QpackDecoder<'a> { } impl<'a> QpackDecoder<'a> { + + /// create a new decoder + /// # Examples(not run) + /// +// ```no_run +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +// use crate::ylong_http::test_util::decode; +// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +// // Required content: +// let mut dynamic_table = DynamicTable::with_empty(); +// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +// ``` pub fn new(field_list_size: usize, table: &'a mut DynamicTable) -> Self { Self { field_list_size, @@ -92,9 +105,23 @@ impl<'a> QpackDecoder<'a> { } /// Users can call `decode_ins` multiple times to decode decoder instructions. + /// # Examples(not run) +// ```no_run +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +// use crate::ylong_http::test_util::decode; +// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +// // Required content: +// let mut dynamic_table = DynamicTable::with_empty(); +// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +// //decode instruction +// // convert hex string to dec-array +// let mut inst = decode("3fbd01c00f7777772e6578616d706c652e636f6dc10c2f73616d706c652f70617468").unwrap().as_slice().to_vec(); +// decoder.decode_ins(&mut inst); +// ``` pub fn decode_ins(&mut self, buf: &[u8]) -> Result<(), H3errorQpack> { let mut decoder = EncInstDecoder::new(); - let mut updater = Updater::new(&mut self.table); + let mut updater = Updater::new(self.table); let mut cnt = 0; loop { match decoder.decode(&buf[cnt..], &mut self.inst_state)? { @@ -145,9 +172,23 @@ impl<'a> QpackDecoder<'a> { /// +---+---------------------------+ /// | Encoded Field Lines ... /// +-------------------------------+ + /// # Examples(not run) +// ```no_run +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +// use crate::ylong_http::test_util::decode; +// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +// // Required content: +// let mut dynamic_table = DynamicTable::with_empty(); +// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +// //decode field section +// // convert hex string to dec-array +// let mut repr = decode("03811011").unwrap().as_slice().to_vec(); +// decoder.decode_repr(&mut repr); +// ``` pub fn decode_repr(&mut self, buf: &[u8]) -> Result<(), H3errorQpack> { let mut decoder = ReprDecoder::new(); - let mut searcher = Searcher::new(self.field_list_size, &self.table, &mut self.lines); + let mut searcher = Searcher::new(self.field_list_size, self.table, &mut self.lines); let mut cnt = 0; loop { match decoder.decode(&buf[cnt..], &mut self.repr_state)? { @@ -241,13 +282,30 @@ impl<'a> QpackDecoder<'a> { /// +---+---+---+---+---+---+---+---+ /// | 1 | Stream ID (7+) | /// +---+---------------------------+ - pub(crate) fn finish( + /// # Examples(not run) +// ```no_run +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +// use crate::ylong_http::test_util::decode; +// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +// // Required content: +// let mut dynamic_table = DynamicTable::with_empty(); +// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +// //decode field section +// // convert hex string to dec-array +// let mut repr = decode("03811011").unwrap().as_slice().to_vec(); +// decoder.decode_repr(&mut repr); +// //finish +// let mut qpack_decoder_buf = [0u8;20]; +// decoder.finish(1,&mut qpack_decoder_buf); +// ``` + pub fn finish( &mut self, stream_id: usize, buf: &mut [u8], ) -> Result<(Parts, Option), H3errorQpack> { - if !self.repr_state.is_none() { - return Err(H3errorQpack::ConnectionError(QpackDecompressionFailed)); + if self.repr_state.is_some() { + return Err(H3errorQpack::ConnectionError(DecompressionFailed)); } self.lines.header_size = 0; if self.require_insert_count > 0 { @@ -268,7 +326,24 @@ impl<'a> QpackDecoder<'a> { /// +---+---+---+---+---+---+---+---+ /// | 0 | 1 | Stream ID (6+) | /// +---+---+-----------------------+ - pub(crate) fn stream_cancel( + /// # Examples(not run) +// ```no_run +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::h3::qpack::decoder::QpackDecoder; +// use crate::ylong_http::test_util::decode; +// const MAX_HEADER_LIST_SIZE: usize = 16 << 20; +// // Required content: +// let mut dynamic_table = DynamicTable::with_empty(); +// let mut decoder = QpackDecoder::new(MAX_HEADER_LIST_SIZE, &mut dynamic_table); +// //decode field section +// // convert hex string to dec-array +// let mut repr = decode("03811011").unwrap().as_slice().to_vec(); +// decoder.decode_repr(&mut repr); +// //stream_cancel +// let mut qpack_decoder_buf = [0u8;20]; +// decoder.stream_cancel(1,&mut qpack_decoder_buf); +// ``` + pub fn stream_cancel( &mut self, stream_id: usize, buf: &mut [u8], @@ -278,7 +353,7 @@ impl<'a> QpackDecoder<'a> { if let Ok(size) = size { return Ok(size); } - Err(H3errorQpack::ConnectionError(QpackDecompressionFailed)) + Err(H3errorQpack::ConnectionError(DecompressionFailed)) } } @@ -312,7 +387,7 @@ impl<'a> Updater<'a> { let table_searcher = TableSearcher::new(self.table); let (f, v) = table_searcher .find_field_dynamic(self.table.insert_count - index - 1) - .ok_or(H3errorQpack::ConnectionError(QpackEncoderStreamError))?; + .ok_or(H3errorQpack::ConnectionError(EncoderStreamError))?; self.table.update(f, v); Ok(()) } @@ -330,20 +405,20 @@ impl<'a> Updater<'a> { if let Some(true) = mid_bit.t { searcher .find_field_name_static(index) - .ok_or(H3errorQpack::ConnectionError(QpackEncoderStreamError))? + .ok_or(H3errorQpack::ConnectionError(EncoderStreamError))? } else { searcher .find_field_name_dynamic(insert_count - index - 1) - .ok_or(H3errorQpack::ConnectionError(QpackEncoderStreamError))? + .ok_or(H3errorQpack::ConnectionError(EncoderStreamError))? } } Name::Literal(octets) => Field::Other( String::from_utf8(octets) - .map_err(|_| H3errorQpack::ConnectionError(QpackEncoderStreamError))?, + .map_err(|_| H3errorQpack::ConnectionError(EncoderStreamError))?, ), }; let v = String::from_utf8(value) - .map_err(|_| H3errorQpack::ConnectionError(QpackEncoderStreamError))?; + .map_err(|_| H3errorQpack::ConnectionError(EncoderStreamError))?; Ok((h, v)) } } @@ -374,32 +449,32 @@ impl<'a> Searcher<'a> { } fn search_indexed(&mut self, mid_bit: MidBit, index: usize) -> Result<(), H3errorQpack> { - let table_searcher = TableSearcher::new(&mut self.table); + 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(H3errorQpack::ConnectionError(QpackDecompressionFailed))?; + .ok_or(H3errorQpack::ConnectionError(DecompressionFailed))?; self.lines.parts.update(f, v); - return Ok(()); + Ok(()) } else { let (f, v) = table_searcher .find_field_dynamic(self.base - index - 1) - .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))?; + .ok_or(H3errorQpack::ConnectionError(DecompressionFailed))?; self.lines.parts.update(f, v); - return Ok(()); + Ok(()) } } fn search_post_indexed(&mut self, index: usize) -> Result<(), H3errorQpack> { - let table_searcher = TableSearcher::new(&mut self.table); + let table_searcher = TableSearcher::new(self.table); let (f, v) = table_searcher .find_field_dynamic(self.base + index) - .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))?; + .ok_or(H3errorQpack::ConnectionError(DecompressionFailed))?; self.check_field_list_size(&f, &v)?; self.lines.parts.update(f, v); - return Ok(()); + Ok(()) } fn search_literal_with_indexing( @@ -463,30 +538,30 @@ impl<'a> Searcher<'a> { let h = match name { Name::Index(index) => { if repr == ReprPrefixBit::LITERALWITHINDEXING { - let searcher = TableSearcher::new(&self.table); + let searcher = TableSearcher::new(self.table); if let Some(true) = mid_bit.t { searcher .find_field_name_static(index) - .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))? + .ok_or(H3errorQpack::ConnectionError(DecompressionFailed))? } else { searcher .find_field_name_dynamic(self.base - index - 1) - .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))? + .ok_or(H3errorQpack::ConnectionError(DecompressionFailed))? } } else { - let searcher = TableSearcher::new(&self.table); + let searcher = TableSearcher::new(self.table); searcher .find_field_name_dynamic(self.base + index) - .ok_or(H3errorQpack::ConnectionError(QpackDecompressionFailed))? + .ok_or(H3errorQpack::ConnectionError(DecompressionFailed))? } } Name::Literal(octets) => Field::Other( String::from_utf8(octets) - .map_err(|_| H3errorQpack::ConnectionError(QpackDecompressionFailed))?, + .map_err(|_| H3errorQpack::ConnectionError(DecompressionFailed))?, ), }; let v = String::from_utf8(value) - .map_err(|_| H3errorQpack::ConnectionError(QpackDecompressionFailed))?; + .map_err(|_| H3errorQpack::ConnectionError(DecompressionFailed))?; Ok((h, v)) } pub(crate) fn update_size(&mut self, addition: usize) { @@ -496,7 +571,7 @@ impl<'a> Searcher<'a> { 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(H3errorQpack::ConnectionError(QpackDecompressionFailed)) + Err(H3errorQpack::ConnectionError(DecompressionFailed)) } else { Ok(()) } @@ -554,11 +629,11 @@ mod ut_qpack_decoder { $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); + 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); }; } @@ -628,7 +703,7 @@ mod ut_qpack_decoder { qpack_test_case!( decoder, "0000510b2f696e6465782e68746d6c", - { None, None, Some(String::from("/index.html")), None, None }, + { None, None, Some("/index.html"), None, None }, { 0 } ); println!("passed"); @@ -648,7 +723,7 @@ mod ut_qpack_decoder { qpack_test_case!( decoder, "03811011", - { Some(String::from("www.example.com")), None, Some(String::from("/sample/path")), None, None }, + { Some("www.example.com"), None, Some("/sample/path"), None, None }, { 0 } ); } @@ -684,7 +759,7 @@ mod ut_qpack_decoder { qpack_test_case!( decoder, "058010c180", - { Some(String::from("www.example.com")), None, Some(String::from("/")), None, None }, + { Some("www.example.com"), None, Some("/"), None, None }, { "custom-key"=>"custom-value" }, { 0 } ); @@ -739,7 +814,7 @@ mod ut_qpack_decoder { qpack_test_case!( QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), "0000d1", - { None, Some(String::from("GET")), None, None, None }, + { None, Some("GET"), None, None, None }, { 0 } ); } @@ -802,7 +877,7 @@ mod ut_qpack_decoder { qpack_test_case!( QpackDecoder::new(MAX_HEADER_LIST_SIZE,&mut dynamic_table), "00007f020d637573746f6d312d76616c7565", - { None, Some(String::from("custom1-value")), None, None, None }, + { None, Some("custom1-value"), None, None, None }, { 0 } ); } diff --git a/ylong_http/src/h3/qpack/encoder.rs b/ylong_http/src/h3/qpack/encoder.rs index 9e8897a..f5a1b30 100644 --- a/ylong_http/src/h3/qpack/encoder.rs +++ b/ylong_http/src/h3/qpack/encoder.rs @@ -12,7 +12,7 @@ // limitations under the License. use crate::h3::parts::Parts; -use crate::h3::qpack::error::ErrorCode::QpackDecoderStreamError; +use crate::h3::qpack::error::ErrorCode::DecoderStreamError; use crate::h3::qpack::error::H3errorQpack; use crate::h3::qpack::format::encoder::{ DecInstDecoder, InstDecodeState, PartsIter, ReprEncodeState, SetCap, @@ -28,43 +28,43 @@ use std::collections::{HashMap, VecDeque}; /// to reduce head-of-line blocking. /// /// # Examples -/// ``` -/// use crate::ylong_http::h3::qpack::encoder::QpackEncoder; -/// use crate::ylong_http::h3::parts::Parts; -/// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; -/// use crate::ylong_http::test_util::decode; -/// -/// -/// -/// // the (field, value) is: ("custom-key", "custom-value2") -/// // Required content: -/// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands. -/// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format. -/// let mut encoder_cur = 0; // index of encoder_buf. -/// let mut stream_cur = 0; // index of stream_buf. -/// let mut table = DynamicTable::with_empty(); -/// -/// // create a new encoder. -/// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); -/// -/// // set dynamic table capacity. -/// encoder_cur += encoder.set_capacity(220, &mut encoder_buf[encoder_buf..]); -/// -/// // set field section. -/// let mut field = Parts::new(); -/// field.update(Field::Other(String::from("custom-key")), String::from("custom-value")); -/// encoder.set_parts(field); -/// -/// // encode field section. -/// let (cur1, cur2, _) = encoder.encode(&mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..]); -/// encoder_cur += cur1; -/// stream_cur += cur2; -/// -/// assert_eq!(stream_buf[..encoder_cur].to_vec().as_slice(), decode("028010").unwrap().as_slice()); -/// assert_eq!(stream_buf[..stream_cur].to_vec().as_slice(), decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565").unwrap().as_slice()); -/// -/// -/// ``` +// ```no_run +// use crate::ylong_http::h3::qpack::encoder::QpackEncoder; +// use crate::ylong_http::h3::parts::Parts; +// use crate::ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use crate::ylong_http::test_util::decode; +// +// +// +// // the (field, value) is: ("custom-key", "custom-value2") +// // Required content: +// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands. +// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format. +// let mut encoder_cur = 0; // index of encoder_buf. +// let mut stream_cur = 0; // index of stream_buf. +// let mut table = DynamicTable::with_empty(); +// +// // create a new encoder. +// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); +// +// // set dynamic table capacity. +// encoder_cur += encoder.set_capacity(220, &mut encoder_buf[encoder_buf..]); +// +// // set field section. +// let mut field = Parts::new(); +// field.update(Field::Other(String::from("custom-key")), String::from("custom-value")); +// encoder.set_parts(field); +// +// // encode field section. +// let (cur1, cur2, _) = encoder.encode(&mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..]); +// encoder_cur += cur1; +// stream_cur += cur2; +// +// assert_eq!(stream_buf[..encoder_cur].to_vec().as_slice(), decode("028010").unwrap().as_slice()); +// assert_eq!(stream_buf[..stream_cur].to_vec().as_slice(), decode("4a637573746f6d2d6b65790c637573746f6d2d76616c7565").unwrap().as_slice()); +// +// +// ``` pub struct QpackEncoder<'a> { table: &'a mut DynamicTable, @@ -88,6 +88,21 @@ pub struct QpackEncoder<'a> { } impl<'a> QpackEncoder<'a> { + + /// create a new encoder. + /// #Examples +// ```no_run +// use ylong_http::h3::qpack::encoder::QpackEncoder; +// use ylong_http::h3::qpack::table::DynamicTable; +// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands. +// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format. +// let mut encoder_cur = 0; // index of encoder_buf. +// let mut stream_cur = 0; // index of stream_buf. +// let mut table = DynamicTable::with_empty(); +// +// // create a new encoder. +// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); +// ``` pub fn new( table: &'a mut DynamicTable, stream_id: usize, @@ -95,7 +110,7 @@ impl<'a> QpackEncoder<'a> { draining_index: usize, ) -> QpackEncoder { Self { - table: table, + table, field_iter: None, field_state: None, inst_state: None, @@ -108,6 +123,19 @@ impl<'a> QpackEncoder<'a> { } } + /// Set the maximum dynamic table size. + /// # Examples + /// ```no_run + /// use ylong_http::h3::qpack::encoder::QpackEncoder; + /// use ylong_http::h3::qpack::table::DynamicTable; + /// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands. + /// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format. + /// let mut encoder_cur = 0; // index of encoder_buf. + /// let mut stream_cur = 0; // index of stream_buf. + /// let mut table = DynamicTable::with_empty(); + /// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); + /// let mut encoder_cur = encoder.set_capacity(220, &mut encoder_buf[..]); + /// ``` pub fn set_capacity(&mut self, max_size: usize, encoder_buf: &mut [u8]) -> usize { self.table.update_size(max_size); if let Ok(cur) = SetCap::new(max_size).encode(&mut encoder_buf[..]) { @@ -116,6 +144,19 @@ impl<'a> QpackEncoder<'a> { 0 } + + /// Set the field section to be encoded. + /// # Examples +// ```no_run +// use ylong_http::h3::qpack::encoder::QpackEncoder; +// use ylong_http::h3::parts::Parts; +// use ylong_http::h3::qpack::table::{DynamicTable, Field}; +// let mut table = DynamicTable::with_empty(); +// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); +// let mut parts = Parts::new(); +// parts.update(Field::Other(String::from("custom-key")), String::from("custom-value")); +// encoder.set_parts(parts); +// ``` pub fn set_parts(&mut self, parts: Parts) { self.field_iter = Some(PartsIter::new(parts)); } @@ -126,34 +167,41 @@ impl<'a> QpackEncoder<'a> { if self.table.known_received_count < self.required_insert_count { self.table.known_received_count = self.required_insert_count; } else { - return Err(H3errorQpack::ConnectionError(QpackDecoderStreamError)); + return Err(H3errorQpack::ConnectionError(DecoderStreamError)); } Ok(Some(DecoderInst::Ack)) } /// Users can call `decode_ins` multiple times to decode decoder instructions. - pub(crate) fn decode_ins(&mut self, buf: &[u8]) -> Result, H3errorQpack> { + /// # Return + /// `Ok(None)` means that the decoder instruction is not complete. + /// # Examples +// ```no_run +// use ylong_http::h3::qpack::encoder::QpackEncoder; +// use ylong_http::h3::parts::Parts; +// use ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use ylong_http::test_util::decode; +// let mut table = DynamicTable::with_empty(); +// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); +// let _ = encoder.decode_ins(&mut decode("80").unwrap().as_slice()); +// ``` + pub fn decode_ins(&mut self, buf: &[u8]) -> Result, H3errorQpack> { let mut decoder = DecInstDecoder::new(buf); - loop { - match decoder.decode(&mut self.inst_state)? { - Some(DecoderInstruction::Ack { stream_id }) => { - return self.ack(stream_id); - } - //todo: stream cancel - Some(DecoderInstruction::StreamCancel { stream_id }) => { - assert_eq!(stream_id, self.stream_id); - return Ok(Some(DecoderInst::StreamCancel)); - } - //todo: insert count increment - Some(DecoderInstruction::InsertCountIncrement { increment }) => { - self.table.known_received_count += increment; - return Ok(Some(DecoderInst::InsertCountIncrement)); - } - None => { - return Ok(None); - } + + match decoder.decode(&mut self.inst_state)? { + Some(DecoderInstruction::Ack { stream_id }) => self.ack(stream_id), + //todo: stream cancel + Some(DecoderInstruction::StreamCancel { stream_id }) => { + assert_eq!(stream_id, self.stream_id); + Ok(Some(DecoderInst::StreamCancel)) + } + //todo: insert count increment + Some(DecoderInstruction::InsertCountIncrement { increment }) => { + self.table.known_received_count += increment; + Ok(Some(DecoderInst::InsertCountIncrement)) } + None => Ok(None), } } @@ -182,8 +230,25 @@ impl<'a> QpackEncoder<'a> { cur_prefix } /// Users can call `encode` multiple times to encode multiple complete field sections. - /// - /// # Return + /// # Examples +// ```no_run +// use ylong_http::h3::qpack::encoder::QpackEncoder; +// use ylong_http::h3::parts::Parts; +// use ylong_http::h3::qpack::table::{DynamicTable, Field}; +// use ylong_http::test_util::decode; +// let mut encoder_buf = [0u8; 1024]; // QPACK stream providing control commands. +// let mut stream_buf = [0u8; 1024]; // Field section encoded in QPACK format. +// let mut encoder_cur = 0; // index of encoder_buf. +// let mut stream_cur = 0; // index of stream_buf. +// let mut table = DynamicTable::with_empty(); +// let mut encoder = QpackEncoder::new(&mut table, 0, true, 1); +// let mut parts = Parts::new(); +// parts.update(Field::Other(String::from("custom-key")), String::from("custom-value")); +// encoder.set_parts(parts); +// let (cur1, cur2, _) = encoder.encode(&mut encoder_buf[encoder_cur..], &mut stream_buf[stream_cur..]); +// encoder_cur += cur1; +// stream_cur += cur2; +// ``` pub fn encode( &mut self, encoder_buf: &mut [u8], //instructions encoded results @@ -201,16 +266,19 @@ impl<'a> QpackEncoder<'a> { } (cur_encoder, cur_stream, Some((prefix_buf, cur_prefix))) } else { - let mut encoder = ReprEncoder::new(&mut self.table, self.draining_index); + let mut encoder = ReprEncoder::new( + self.table, + self.draining_index, + self.allow_post, + &mut self.insert_length, + ); (cur_encoder, cur_stream) = encoder.encode( &mut self.field_iter, &mut self.field_state, &mut encoder_buf[0..], &mut stream_buf[0..], - self.allow_post, &mut self.insert_list, &mut self.required_insert_count, - &mut self.insert_length, ); (cur_encoder, cur_stream, None) } @@ -222,7 +290,7 @@ impl<'a> QpackEncoder<'a> { } } -pub(crate) enum DecoderInst { +pub enum DecoderInst { Ack, StreamCancel, InsertCountIncrement, diff --git a/ylong_http/src/h3/qpack/error.rs b/ylong_http/src/h3/qpack/error.rs index b0018a9..aa3029f 100644 --- a/ylong_http/src/h3/qpack/error.rs +++ b/ylong_http/src/h3/qpack/error.rs @@ -16,9 +16,9 @@ pub enum H3errorQpack { #[derive(Debug, Eq, PartialEq, Clone)] pub enum ErrorCode { - QpackDecompressionFailed = 0x0200, + DecompressionFailed = 0x0200, - QpackEncoderStreamError = 0x0201, + EncoderStreamError = 0x0201, - QpackDecoderStreamError = 0x0202, + DecoderStreamError = 0x0202, } diff --git a/ylong_http/src/h3/qpack/format/decoder.rs b/ylong_http/src/h3/qpack/format/decoder.rs index 9271150..fff4f8d 100644 --- a/ylong_http/src/h3/qpack/format/decoder.rs +++ b/ylong_http/src/h3/qpack/format/decoder.rs @@ -10,7 +10,7 @@ // 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. -use crate::h3::qpack::error::ErrorCode::QpackDecompressionFailed; +use crate::h3::qpack::error::ErrorCode::DecompressionFailed; use crate::h3::qpack::error::{ErrorCode, H3errorQpack}; use crate::h3::qpack::format::decoder::DecResult::Error; use crate::h3::qpack::integer::IntegerDecoder; @@ -29,6 +29,14 @@ impl EncInstDecoder { Self {} } + /// Decodes `buf`. Every time users call `decode`, it will try to + /// decode a `EncoderInstruction`. + /// # Example +// ```no_run +// use crate::h3::qpack::format::decoder::EncInstDecoder; +// let mut decoder = EncInstDecoder::new(); +// +// ``` pub(crate) fn decode( &mut self, buf: &[u8], @@ -202,8 +210,8 @@ impl FiledSectionPrefix { buf_index, Representation::FieldSectionPrefix { require_insert_count: ric, - signal: signal, - delta_base: delta_base, + signal, + delta_base, }, )), DecResult::NeedMore(inner) => { @@ -266,7 +274,7 @@ impl EncInstIndex { } DecResult::Error(e) => e.into(), _ => DecResult::Error(H3errorQpack::ConnectionError( - ErrorCode::QpackDecompressionFailed, + ErrorCode::DecompressionFailed, )), } } @@ -328,7 +336,7 @@ impl ReprIndex { DecResult::NeedMore(inner) => DecResult::NeedMore(ReprIndex::from_inner(inner).into()), DecResult::Error(e) => e.into(), _ => DecResult::Error(H3errorQpack::ConnectionError( - ErrorCode::QpackDecompressionFailed, + ErrorCode::DecompressionFailed, )), } } @@ -692,17 +700,17 @@ impl HuffmanStringBytes { Ordering::Greater | Ordering::Equal => { let pos = self.length - self.read; if self.huffman.decode(&buf[..pos]).is_err() { - return H3errorQpack::ConnectionError(QpackDecompressionFailed).into(); + return H3errorQpack::ConnectionError(DecompressionFailed).into(); } // let (_, mut remain_buf) = buf.split_at_mut(pos); match self.huffman.finish() { Ok(vec) => DecResult::Decoded((pos, vec)), - Err(_) => H3errorQpack::ConnectionError(QpackDecompressionFailed).into(), + Err(_) => H3errorQpack::ConnectionError(DecompressionFailed).into(), } } Ordering::Less => { if self.huffman.decode(buf).is_err() { - return H3errorQpack::ConnectionError(QpackDecompressionFailed).into(); + return H3errorQpack::ConnectionError(DecompressionFailed).into(); } self.read += buf.len(); // let (_, mut remain_buf) = buf.split_at_mut(buf.len()); @@ -766,7 +774,7 @@ impl InstValueString { }, )) } - (_, _) => Error(H3errorQpack::ConnectionError(QpackDecompressionFailed)), + (_, _) => Error(H3errorQpack::ConnectionError(DecompressionFailed)), } } } @@ -824,7 +832,7 @@ impl ReprValueString { }, )) } - (_, _) => Error(H3errorQpack::ConnectionError(QpackDecompressionFailed)), + (_, _) => Error(H3errorQpack::ConnectionError(DecompressionFailed)), } } } diff --git a/ylong_http/src/h3/qpack/format/encoder.rs b/ylong_http/src/h3/qpack/format/encoder.rs index fa8ad86..8d2b79d 100644 --- a/ylong_http/src/h3/qpack/format/encoder.rs +++ b/ylong_http/src/h3/qpack/format/encoder.rs @@ -11,52 +11,81 @@ // See the License for the specific language governing permissions and // limitations under the License. use crate::h3::parts::Parts; -use crate::h3::qpack::error::ErrorCode::QpackDecoderStreamError; +use crate::h3::qpack::error::ErrorCode::DecoderStreamError; use crate::h3::qpack::error::H3errorQpack; use crate::h3::qpack::format::decoder::DecResult; use crate::h3::qpack::integer::{Integer, IntegerDecoder, IntegerEncoder}; use crate::h3::qpack::table::{DynamicTable, Field, TableIndex, TableSearcher}; use crate::h3::qpack::{DecoderInstPrefixBit, DecoderInstruction, EncoderInstruction, PrefixMask}; use crate::headers::HeadersIntoIter; -use crate::pseudo::PseudoHeaders; +use crate::h3::pseudo::PseudoHeaders; use std::arch::asm; use std::cmp::{max, Ordering}; use std::collections::{HashMap, VecDeque}; use std::result; use std::sync::Arc; -pub(crate) struct ReprEncoder<'a> { +pub struct ReprEncoder<'a> { table: &'a mut DynamicTable, draining_index: usize, + allow_post: bool, + insert_length: &'a mut usize, } impl<'a> ReprEncoder<'a> { /// Creates a new, empty `ReprEncoder`. - pub(crate) fn new(table: &'a mut DynamicTable, draining_index: usize) -> Self { + /// # Examples +// ```no_run +// use ylong_http::h3::qpack::table::DynamicTable; +// use ylong_http::h3::qpack::format::encoder::ReprEncoder; +// let mut table = DynamicTable::new(4096); +// let mut insert_length = 0; +// let mut encoder = ReprEncoder::new(&mut table, 0, true, &mut insert_length); +// ``` + pub fn new( + table: &'a mut DynamicTable, + draining_index: usize, + allow_post: bool, + insert_length: &'a mut usize, + ) -> Self { Self { table, draining_index, + allow_post, + insert_length, } } - /// written to `dst` and the length of the decoded content will be returned. + /// written to `buffer` and the length of the decoded content will be returned. + /// # Examples +// ```no_run +// use std::collections::VecDeque;use ylong_http::h3::qpack::table::DynamicTable; +// use ylong_http::h3::qpack::format::encoder::ReprEncoder; +// let mut table = DynamicTable::new(4096); +// let mut insert_length = 0; +// let mut encoder = ReprEncoder::new(&mut table, 0, true, &mut insert_length); +// let mut qpack_buffer = [0u8; 1024]; +// let mut stream_buffer = [0u8; 1024]; // stream buffer +// let mut insert_list = VecDeque::new(); // fileds to insert +// let mut required_insert_count = 0; // RFC required. +// let mut field_iter = None; // for field iterator +// let mut field_state = None; // for field encode state +// encoder.encode(&mut field_iter, &mut field_state, &mut qpack_buffer, &mut stream_buffer, &mut insert_list, &mut required_insert_count); pub(crate) fn encode( &mut self, field_iter: &mut Option, field_state: &mut Option, encoder_buffer: &mut [u8], stream_buffer: &mut [u8], - allow_post: bool, insert_list: &mut VecDeque<(Field, String)>, required_insert_count: &mut usize, - insert_length: &mut usize, ) -> (usize, usize) { let mut cur_encoder = 0; let mut cur_stream = 0; let mut base = self.table.insert_count; if let Some(mut iter) = field_iter.take() { while let Some((h, v)) = iter.next() { - let searcher = TableSearcher::new(&self.table); + let searcher = TableSearcher::new(self.table); let mut stream_result: Result = Result::Ok(0); let mut encoder_result: Result = Result::Ok(0); let static_index = searcher.find_index_static(&h, &v); @@ -80,10 +109,10 @@ impl<'a> ReprEncoder<'a> { dynamic_name_index = searcher.find_index_name_dynamic(&h, &v); } - if self.table.have_enough_space(&h, &v, &insert_length) { + if self.table.have_enough_space(&h, &v, self.insert_length) { if !self.should_index(&dynamic_index) { if let Some(TableIndex::Field(index)) = dynamic_index { - encoder_result = Duplicate::new(base - index.clone() - 1) + encoder_result = Duplicate::new(base - index - 1) .encode(&mut encoder_buffer[cur_encoder..]); self.table.update(h.clone(), v.clone()); base = max(base, self.table.insert_count); @@ -100,7 +129,7 @@ impl<'a> ReprEncoder<'a> { // insert with name reference in static table (Some(TableIndex::FieldName(index)), _, _) => { InsertWithName::new( - index.clone(), + *index, v.clone().into_bytes(), false, true, @@ -111,7 +140,7 @@ impl<'a> ReprEncoder<'a> { (_, Some(TableIndex::FieldName(index)), true) => { // convert abs index to rel index InsertWithName::new( - base - index.clone() - 1, + base - index - 1, v.clone().into_bytes(), false, false, @@ -120,7 +149,7 @@ impl<'a> ReprEncoder<'a> { } // Duplicate (_, Some(TableIndex::FieldName(index)), false) => { - let res = Duplicate::new(index.clone()) + let res = Duplicate::new(*index) .encode(&mut encoder_buffer[cur_encoder..]); self.table.update(h.clone(), v.clone()); base = max(base, self.table.insert_count); @@ -143,9 +172,9 @@ impl<'a> ReprEncoder<'a> { self.draining_index += 1; } insert_list.push_back((h.clone(), v.clone())); - *insert_length += h.len() + v.len() + 32; + *self.insert_length += h.len() + v.len() + 32; } - if allow_post && !is_duplicate { + if self.allow_post && !is_duplicate { for (post_index, (t_h, t_v)) in insert_list.iter().enumerate() { if t_h == &h && t_v == &v { dynamic_index = Some(TableIndex::Field(post_index)) @@ -249,50 +278,48 @@ impl<'a> ReprEncoder<'a> { (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 + // ## 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, index: &Option) -> bool { match index { Some(TableIndex::Field(x)) => { if *x < self.draining_index { return false; } - return true; + true } Some(TableIndex::FieldName(x)) => { if *x < self.draining_index { return false; } - return true; - } - _ => { - return true; + true } + _ => true, } } } @@ -773,7 +800,7 @@ impl DecInstIndex { DecResult::Decoded(DecoderInstruction::InsertCountIncrement { increment: index }) } DecResult::Error(e) => e.into(), - _ => DecResult::Error(H3errorQpack::ConnectionError(QpackDecoderStreamError)), + _ => DecResult::Error(H3errorQpack::ConnectionError(DecoderStreamError)), } } } diff --git a/ylong_http/src/h3/qpack/format/mod.rs b/ylong_http/src/h3/qpack/format/mod.rs index 91582e3..7035841 100644 --- a/ylong_http/src/h3/qpack/format/mod.rs +++ b/ylong_http/src/h3/qpack/format/mod.rs @@ -11,6 +11,6 @@ // See the License for the specific language governing permissions and // limitations under the License. pub(crate) mod decoder; -pub(crate) mod encoder; +pub mod encoder; pub(crate) use encoder::ReprEncoder; diff --git a/ylong_http/src/h3/qpack/integer.rs b/ylong_http/src/h3/qpack/integer.rs index e76fdb5..6c6b471 100644 --- a/ylong_http/src/h3/qpack/integer.rs +++ b/ylong_http/src/h3/qpack/integer.rs @@ -70,7 +70,7 @@ impl IntegerDecoder { .and_then(|res| res.checked_mul((byte & 0x7f) as usize)) .and_then(|res| res.checked_add(self.index)) .ok_or(H3errorQpack::ConnectionError( - ErrorCode::QpackDecompressionFailed, + ErrorCode::DecompressionFailed, ))?; //todo: modify the error code self.shift += 7; match (byte & 0x80) == 0x00 { diff --git a/ylong_http/src/h3/qpack/mod.rs b/ylong_http/src/h3/qpack/mod.rs index f8f00c9..f21f9d3 100644 --- a/ylong_http/src/h3/qpack/mod.rs +++ b/ylong_http/src/h3/qpack/mod.rs @@ -14,7 +14,7 @@ pub mod decoder; pub mod encoder; pub(crate) mod error; -mod format; +pub mod format; mod integer; pub mod table; use crate::h3::qpack::format::decoder::Name; @@ -77,12 +77,10 @@ impl DecoderInstPrefixBit { } pub(crate) fn prefix_midbit_value(&self) -> MidBit { - match self.0 { - _ => MidBit { - n: None, - t: None, - h: None, - }, + MidBit { + n: None, + t: None, + h: None, } } } diff --git a/ylong_http/src/h3/qpack/table.rs b/ylong_http/src/h3/qpack/table.rs index 4baaf99..4d1cdc1 100644 --- a/ylong_http/src/h3/qpack/table.rs +++ b/ylong_http/src/h3/qpack/table.rs @@ -129,9 +129,7 @@ impl DynamicTable { self.size += field.len() + value.len() + 32; self.queue.push_back((field.clone(), value.clone())); self.fit_size(); - match self.index(&field, &value) { - x => x, - } + self.index(&field, &value) } pub(crate) fn have_enough_space( @@ -181,9 +179,8 @@ impl DynamicTable { // find latest let mut index = None; for (n, (h, v)) in self.queue.iter().enumerate() { - match (header == h, value == v, &index) { - (true, true, _) => index = Some(TableIndex::Field(n + self.remove_count)), - _ => {} + if let (true, true, _) = (header == h, value == v, &index) { + index = Some(TableIndex::Field(n + self.remove_count)) } } index @@ -193,9 +190,8 @@ impl DynamicTable { // find latest let mut index = None; for (n, (h, v)) in self.queue.iter().enumerate() { - match (header == h, value == v, &index) { - (true, _, _) => index = Some(TableIndex::FieldName(n + self.remove_count)), - _ => {} + if let (true, _, _) = (header == h, value == v, &index) { + index = Some(TableIndex::FieldName(n + self.remove_count)) } } index diff --git a/ylong_http/src/lib.rs b/ylong_http/src/lib.rs index 6d94e53..9fac33a 100644 --- a/ylong_http/src/lib.rs +++ b/ylong_http/src/lib.rs @@ -41,9 +41,8 @@ pub mod request; pub mod response; pub mod version; -mod pseudo; #[cfg(test)] -pub mod test_util; +pub(crate) mod test_util; #[cfg(feature = "tokio_base")] pub(crate) use tokio::io::{AsyncRead, AsyncReadExt, ReadBuf}; diff --git a/ylong_http_client/src/async_impl/conn/http2.rs b/ylong_http_client/src/async_impl/conn/http2.rs index 68dc833..d00f546 100644 --- a/ylong_http_client/src/async_impl/conn/http2.rs +++ b/ylong_http_client/src/async_impl/conn/http2.rs @@ -40,9 +40,9 @@ pub(crate) async fn request( request: &mut Request, retryable: &mut Retryable, ) -> Result, HttpClientError> -where - T: Body, - S: AsyncRead + AsyncWrite + Sync + Send + Unpin + 'static, + where + T: Body, + S: AsyncRead + AsyncWrite + Sync + Send + Unpin + 'static, { let part = request.part().clone(); let body = request.body_mut(); @@ -83,8 +83,8 @@ fn frame_2_response( headers_frame: Frame, retryable: &mut Retryable, ) -> Result, HttpClientError> -where - S: AsyncRead + AsyncWrite + Sync + Send + Unpin + 'static, + where + S: AsyncRead + AsyncWrite + Sync + Send + Unpin + 'static, { let part = match headers_frame.payload() { Payload::Headers(headers) => { diff --git a/ylong_http_client/src/async_impl/http_body.rs b/ylong_http_client/src/async_impl/http_body.rs index b13e105..60b1f00 100644 --- a/ylong_http_client/src/async_impl/http_body.rs +++ b/ylong_http_client/src/async_impl/http_body.rs @@ -568,11 +568,11 @@ impl Chunk { #[cfg(test)] mod ut_async_http_body { - use ylong_http::body::{async_impl, ChunkBodyDecoder}; use crate::async_impl::http_body::Chunk; use crate::async_impl::HttpBody; use crate::util::normalizer::BodyLength; use crate::ErrorKind; + use ylong_http::body::{async_impl, ChunkBodyDecoder}; /// UT test cases for `Chunk::get_trailers`. /// -- Gitee