Skip to main content

xitca_http/h1/proto/
context.rs

1use core::{mem, net::SocketAddr};
2
3use crate::http::{Extensions, header::HeaderMap};
4
5/// Context is connection specific struct contain states for processing.
6pub struct Context<'a, D, const HEADER_LIMIT: usize> {
7    addr: SocketAddr,
8    state: ContextState,
9    // header map reused by next request.
10    header: Option<HeaderMap>,
11    // http extensions reused by next request.
12    exts: Extensions,
13    date: &'a D,
14}
15
16// A set of state for current request that are used after request's ownership is passed
17// to service call.
18struct ContextState(u8);
19
20impl ContextState {
21    // Enable when current request has 100-continue header.
22    const EXPECT: u8 = 0b_0001;
23    // Enable when current request is CONNECT method.
24    const CONNECT: u8 = 0b_0010;
25    // Enable when current request is HEAD method.
26    const HEAD: u8 = 0b_0100;
27    // Enable when current connection is supposed to be closed after current response is sent.
28    const CLOSE: u8 = 0b_1000;
29    // Enable when current request is HTTP/1.0.
30    const HTTP_10: u8 = 0b1_0000;
31
32    const fn new() -> Self {
33        Self(0)
34    }
35
36    fn insert(&mut self, other: u8) {
37        self.0 |= other;
38    }
39
40    fn remove(&mut self, other: u8) {
41        self.0 &= !other;
42    }
43
44    const fn contains(&self, other: u8) -> bool {
45        (self.0 & other) == other
46    }
47}
48
49impl<'a, D, const HEADER_LIMIT: usize> Context<'a, D, HEADER_LIMIT> {
50    /// Context is constructed with reference of certain type that impl [DateTime] trait.
51    ///
52    /// [DateTime]: crate::date::DateTime
53    #[inline]
54    pub fn new(date: &'a D) -> Self {
55        Self::with_addr(crate::unspecified_socket_addr(), date)
56    }
57
58    /// Context is constructed with [SocketAddr] and reference of certain type that impl [DateTime] trait.
59    ///
60    /// [DateTime]: crate::date::DateTime
61    #[inline]
62    pub fn with_addr(addr: SocketAddr, date: &'a D) -> Self {
63        Self {
64            addr,
65            state: ContextState::new(),
66            header: None,
67            exts: Extensions::new(),
68            date,
69        }
70    }
71
72    /// Get Date type from Context.
73    #[inline]
74    pub fn date(&self) -> &D {
75        self.date
76    }
77
78    /// Take ownership of HeaderMap stored in Context.
79    ///
80    /// When Context does not have one a new HeaderMap is constructed.
81    #[inline]
82    pub fn take_headers(&mut self) -> HeaderMap {
83        self.header.take().unwrap_or_default()
84    }
85
86    /// Take ownership of Extensions stored in Context.
87    #[inline]
88    pub fn take_extensions(&mut self) -> Extensions {
89        mem::take(&mut self.exts)
90    }
91
92    /// Replace a new HeaderMap in current Context.
93    #[inline]
94    pub fn replace_headers(&mut self, headers: HeaderMap) {
95        debug_assert!(headers.is_empty());
96        self.header = Some(headers);
97    }
98
99    /// Replace a new Extensions in current Context.
100    #[inline]
101    pub fn replace_extensions(&mut self, extensions: Extensions) {
102        debug_assert!(extensions.is_empty());
103        self.exts = extensions;
104    }
105
106    /// Reset Context's state to partial default state.
107    #[inline]
108    pub fn reset(&mut self) {
109        self.state = ContextState::new();
110    }
111
112    /// Set Context's state to EXPECT header received.
113    #[inline]
114    pub fn set_expect_header(&mut self) {
115        self.state.insert(ContextState::EXPECT)
116    }
117
118    /// Set Context's state to CONNECT method received.
119    #[inline]
120    pub fn set_connect_method(&mut self) {
121        self.state.insert(ContextState::CONNECT)
122    }
123
124    /// Set Context's state to HEAD method received.
125    #[inline]
126    pub fn set_head_method(&mut self) {
127        self.state.insert(ContextState::HEAD)
128    }
129
130    /// Set Context's state to HTTP/1.0 request version.
131    #[inline]
132    pub fn set_http10(&mut self) {
133        self.state.insert(ContextState::HTTP_10)
134    }
135
136    /// Set Context's state to Close.
137    #[inline]
138    pub fn set_close(&mut self) {
139        self.state.insert(ContextState::CLOSE)
140    }
141
142    /// Remove Context's Close state.
143    #[inline]
144    pub fn remove_close(&mut self) {
145        self.state.remove(ContextState::CLOSE)
146    }
147
148    /// Get expect header state.
149    #[inline]
150    pub const fn is_expect_header(&self) -> bool {
151        self.state.contains(ContextState::EXPECT)
152    }
153
154    /// Get CONNECT method state.
155    #[inline]
156    pub const fn is_connect_method(&self) -> bool {
157        self.state.contains(ContextState::CONNECT)
158    }
159
160    /// Get HEAD method state.
161    #[inline]
162    pub const fn is_head_method(&self) -> bool {
163        self.state.contains(ContextState::HEAD)
164    }
165
166    /// Get HTTP/1.0 request version state.
167    #[inline]
168    pub const fn is_http10(&self) -> bool {
169        self.state.contains(ContextState::HTTP_10)
170    }
171
172    /// Return true if connection type is `Connection: Close`.
173    #[inline]
174    pub const fn is_connection_closed(&self) -> bool {
175        self.state.contains(ContextState::CLOSE)
176    }
177
178    /// Get remote socket address context associated with.
179    #[inline]
180    pub fn socket_addr(&self) -> &SocketAddr {
181        &self.addr
182    }
183}