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