Skip to main content

sark_http/field/head/
mod.rs

1pub mod headers;
2pub(super) mod known;
3mod parse;
4
5use core::mem;
6
7use known::Known;
8
9use crate::{
10    field::text::IntError,
11    h1::{
12        field::{self, TokenError, value},
13        switch, target,
14    },
15};
16
17#[derive(Clone, Copy, PartialEq, Eq, Debug)]
18pub enum Error {
19    Value,
20    Connection(TokenError),
21    ContentLength(IntError),
22    TransferEncoding(value::Error),
23    Host(target::HostError),
24    Message(field::Error),
25    Routing(target::Invalid),
26    Upgrade(switch::UpgradeError),
27}
28
29const _: () = {
30    assert!(mem::size_of::<Error>() == 3 * mem::size_of::<usize>());
31    assert!(mem::size_of::<Option<Error>>() == mem::size_of::<Error>());
32    assert!(!mem::needs_drop::<Error>());
33};
34
35#[derive(Clone, Copy, Default, PartialEq, Eq)]
36pub struct Flags(u16);
37
38impl Flags {
39    pub const CONNECTION_CLOSE: u16 = 1 << 9;
40    pub const CONNECTION_KEEP_ALIVE: u16 = 1 << 10;
41
42    pub fn is_set(self, bit: u16) -> bool {
43        (self.0 & bit) != 0
44    }
45
46    pub fn set(&mut self, bit: u16) {
47        self.0 |= bit;
48    }
49
50    pub fn is_close(self, version: &[u8]) -> bool {
51        if self.is_set(Self::CONNECTION_CLOSE) {
52            return true;
53        }
54        if self.is_set(Self::CONNECTION_KEEP_ALIVE) {
55            return false;
56        }
57        version == b"HTTP/1.0"
58    }
59}
60
61#[repr(u8)]
62#[derive(Clone, Copy, PartialEq, Eq, Debug)]
63pub enum Name {
64    Invalid,
65    Method,
66    Scheme,
67    Path,
68    Status,
69    Authority,
70    Protocol,
71    Host,
72    Connection,
73    ContentLength,
74    TransferEncoding,
75    Expect,
76    AcceptEncoding,
77    Te,
78    KeepAlive,
79    ProxyConnection,
80    Upgrade,
81    Regular,
82}
83
84impl Name {
85    pub const H1: [Self; 7] = [
86        Self::Host,
87        Self::Connection,
88        Self::ContentLength,
89        Self::TransferEncoding,
90        Self::Expect,
91        Self::AcceptEncoding,
92        Self::Upgrade,
93    ];
94
95    pub const fn wire(&self) -> &[u8] {
96        match self {
97            Self::Method => b":method",
98            Self::Scheme => b":scheme",
99            Self::Path => b":path",
100            Self::Status => b":status",
101            Self::Authority => b":authority",
102            Self::Protocol => b":protocol",
103            Self::Host => Known::Host.as_str().as_bytes(),
104            Self::Connection => Known::Connection.as_str().as_bytes(),
105            Self::ContentLength => Known::ContentLength.as_str().as_bytes(),
106            Self::TransferEncoding => Known::TransferEncoding.as_str().as_bytes(),
107            Self::Expect => Known::Expect.as_str().as_bytes(),
108            Self::AcceptEncoding => Known::AcceptEncoding.as_str().as_bytes(),
109            Self::Te => Known::Te.as_str().as_bytes(),
110            Self::KeepAlive => Known::KeepAlive.as_str().as_bytes(),
111            Self::ProxyConnection => Known::ProxyConnection.as_str().as_bytes(),
112            Self::Upgrade => Known::Upgrade.as_str().as_bytes(),
113            Self::Invalid | Self::Regular => b"",
114        }
115    }
116
117    pub const fn is_required(self) -> bool {
118        matches!(
119            self,
120            Self::Host
121                | Self::Connection
122                | Self::ContentLength
123                | Self::TransferEncoding
124                | Self::Expect
125                | Self::Upgrade
126        )
127    }
128
129    pub fn from_h1(name: &[u8]) -> Option<Self> {
130        let known = match name.len() {
131            4 => Self::Host,
132            6 => Self::Expect,
133            7 => Self::Upgrade,
134            10 if name.first()?.eq_ignore_ascii_case(&b'k') => Self::KeepAlive,
135            10 => Self::Connection,
136            14 => Self::ContentLength,
137            15 => Self::AcceptEncoding,
138            17 => Self::TransferEncoding,
139            _ => return None,
140        };
141        name.eq_ignore_ascii_case(known.wire()).then_some(known)
142    }
143}
144
145pub const MAX_HEADER_LINE_BYTES: usize = 8 * 1024;