sark_http/h1/field/
mod.rs1use core::mem;
4
5use crate::field::{
6 self,
7 scan::Match,
8 text::{Ascii, IntError},
9};
10
11mod cursor;
12mod entry;
13pub mod expect;
14pub mod scan;
15pub mod syntax;
16mod transfer;
17pub mod value;
18
19pub(in crate::h1) use cursor::{Cursor, End};
20pub use entry::Entry;
21pub use transfer::Transfer;
22
23pub(in crate::h1) enum Progress<'owner> {
24 Field(Entry<'owner>),
25 More,
26 End(End),
27}
28
29const _: () = assert!(core::mem::size_of::<Progress<'_>>() == 64);
30
31#[derive(Clone, Copy, PartialEq, Eq)]
32pub(in crate::h1) struct Limit {
33 count: u32,
34 line_bytes: u32,
35}
36
37impl Limit {
38 pub(in crate::h1) const fn new(count: usize, line: usize) -> Self {
39 Self {
40 count: Self::narrow(count),
41 line_bytes: Self::narrow(line),
42 }
43 }
44
45 const fn narrow(value: usize) -> u32 {
46 if value > u32::MAX as usize {
47 u32::MAX
48 } else {
49 value as u32
50 }
51 }
52}
53
54#[derive(Clone, Copy, Debug, PartialEq, Eq)]
55pub enum Error {
56 DuplicateContentLength,
57 ContentLengthWithTransferEncoding,
58 InvalidContentLength(IntError),
59 InvalidTransferEncoding(value::Error),
60}
61
62#[repr(transparent)]
66#[derive(Clone, Copy, Default, PartialEq, Eq)]
67pub struct Connection(u8);
68
69#[derive(Clone, Copy, Debug, PartialEq, Eq)]
70pub struct TokenError {
71 pub index: usize,
72 pub byte: u8,
73}
74
75impl Connection {
76 pub(crate) const CLOSE: Self = Self(1 << 0);
77 pub(crate) const KEEP_ALIVE: Self = Self(1 << 1);
78 const UPGRADE: u8 = 1 << 2;
79
80 pub fn try_push(mut self, value: &[u8]) -> Result<Self, TokenError> {
81 let mut rest = value;
82 while !rest.is_empty() {
83 let base = value.len() - rest.len();
84 let raw = match Match::find_by(rest, |byte| byte == b',') {
85 Some(comma) => {
86 rest = comma.suffix();
87 comma.prefix()
88 }
89 None => mem::take(&mut rest),
90 };
91 let mut token = raw;
92 while let [b' ' | b'\t', rest @ ..] = token {
93 token = rest;
94 }
95 let start = raw.len() - token.len();
96 while let [rest @ .., b' ' | b'\t'] = token {
97 token = rest;
98 }
99 if token.is_empty() {
100 continue;
101 }
102 if let Some((index, byte)) = token
103 .iter()
104 .copied()
105 .enumerate()
106 .find(|(_, byte)| !field::Error::is_name_byte(*byte))
107 {
108 return Err(TokenError {
109 index: base + start + index,
110 byte,
111 });
112 }
113 if token.eq_ignore_ascii_case(b"close") {
114 self.0 |= Self::CLOSE.0;
115 } else if token.eq_ignore_ascii_case(b"keep-alive") {
116 self.0 |= Self::KEEP_ALIVE.0;
117 } else if token.eq_ignore_ascii_case(b"upgrade") {
118 self.0 |= Self::UPGRADE;
119 }
120 }
121 Ok(self)
122 }
123
124 #[doc(hidden)]
126 pub fn append(&mut self, fields: Self) {
127 self.0 |= fields.0;
128 }
129
130 pub const fn is_close(self) -> bool {
131 self.0 & Self::CLOSE.0 != 0
132 }
133
134 pub const fn is_keep(self) -> bool {
135 self.0 & Self::KEEP_ALIVE.0 != 0
136 }
137
138 pub const fn is_upgrade(self) -> bool {
139 self.0 & Self::UPGRADE != 0
140 }
141}
142
143#[derive(Clone, Copy, Default, PartialEq, Eq)]
147pub struct KeepAlive {
148 timeout: Option<u64>,
149}
150
151impl KeepAlive {
152 pub(crate) fn parse(mut prior: Option<u64>, value: &[u8]) -> Option<u64> {
153 for raw in value.split(|byte| *byte == b',') {
154 let param = field::Error::trim_ows(raw);
155 let Some(split) = param.iter().position(|byte| *byte == b'=') else {
156 continue;
157 };
158 let name = field::Error::trim_ows(¶m[..split]);
159 if !name.eq_ignore_ascii_case(b"timeout") {
160 continue;
161 }
162 let Ok(timeout) = Ascii::new(field::Error::trim_ows(¶m[split + 1..])).parse_u64()
163 else {
164 continue;
165 };
166 prior = Some(prior.map_or(timeout, |current| current.min(timeout)));
167 }
168 prior
169 }
170
171 pub(crate) const fn new(timeout: Option<u64>) -> Self {
172 Self { timeout }
173 }
174
175 pub const fn timeout_secs(self) -> Option<u64> {
176 self.timeout
177 }
178}
179
180const _: () = assert!(core::mem::size_of::<Connection>() == 1);