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
30    const fn new() -> Self {
31        Self(0)
32    }
33
34    fn insert(&mut self, other: u8) {
35        self.0 |= other;
36    }
37
38    fn remove(&mut self, other: u8) {
39        self.0 &= !other;
40    }
41
42    const fn contains(&self, other: u8) -> bool {
43        (self.0 & other) == other
44    }
45}
46
47impl<'a, D, const HEADER_LIMIT: usize> Context<'a, D, HEADER_LIMIT> {
48    /// Context is constructed with reference of certain type that impl [DateTime] trait.
49    ///
50    /// [DateTime]: crate::date::DateTime
51    #[inline]
52    pub fn new(date: &'a D) -> Self {
53        Self::with_addr(crate::unspecified_socket_addr(), date)
54    }
55
56    /// Context is constructed with [SocketAddr] and reference of certain type that impl [DateTime] trait.
57    ///
58    /// [DateTime]: crate::date::DateTime
59    #[inline]
60    pub fn with_addr(addr: SocketAddr, date: &'a D) -> Self {
61        Self {
62            addr,
63            state: ContextState::new(),
64            header: None,
65            exts: Extensions::new(),
66            date,
67        }
68    }
69
70    /// Get Date type from Context.
71    #[inline]
72    pub fn date(&self) -> &D {
73        self.date
74    }
75
76    /// Take ownership of HeaderMap stored in Context.
77    ///
78    /// When Context does not have one a new HeaderMap is constructed.
79    #[inline]
80    pub fn take_headers(&mut self) -> HeaderMap {
81        self.header.take().unwrap_or_default()
82    }
83
84    /// Take ownership of Extensions stored in Context.
85    #[inline]
86    pub fn take_extensions(&mut self) -> Extensions {
87        mem::take(&mut self.exts)
88    }
89
90    /// Replace a new HeaderMap in current Context.
91    #[inline]
92    pub fn replace_headers(&mut self, headers: HeaderMap) {
93        debug_assert!(headers.is_empty());
94        self.header = Some(headers);
95    }
96
97    /// Replace a new Extensions in current Context.
98    #[inline]
99    pub fn replace_extensions(&mut self, extensions: Extensions) {
100        debug_assert!(extensions.is_empty());
101        self.exts = extensions;
102    }
103
104    /// Reset Context's state to partial default state.
105    #[inline]
106    pub fn reset(&mut self) {
107        self.state = ContextState::new();
108    }
109
110    /// Set Context's state to EXPECT header received.
111    #[inline]
112    pub fn set_expect_header(&mut self) {
113        self.state.insert(ContextState::EXPECT)
114    }
115
116    /// Set Context's state to CONNECT method received.
117    #[inline]
118    pub fn set_connect_method(&mut self) {
119        self.state.insert(ContextState::CONNECT)
120    }
121
122    /// Set Context's state to HEAD method received.
123    #[inline]
124    pub fn set_head_method(&mut self) {
125        self.state.insert(ContextState::HEAD)
126    }
127
128    /// Set Context's state to Close.
129    #[inline]
130    pub fn set_close(&mut self) {
131        self.state.insert(ContextState::CLOSE)
132    }
133
134    /// Remove Context's Close state.
135    #[inline]
136    pub fn remove_close(&mut self) {
137        self.state.remove(ContextState::CLOSE)
138    }
139
140    /// Get expect header state.
141    #[inline]
142    pub const fn is_expect_header(&self) -> bool {
143        self.state.contains(ContextState::EXPECT)
144    }
145
146    /// Get CONNECT method state.
147    #[inline]
148    pub const fn is_connect_method(&self) -> bool {
149        self.state.contains(ContextState::CONNECT)
150    }
151
152    /// Get HEAD method state.
153    #[inline]
154    pub const fn is_head_method(&self) -> bool {
155        self.state.contains(ContextState::HEAD)
156    }
157
158    /// Return true if connection type is `Connection: Close`.
159    #[inline]
160    pub const fn is_connection_closed(&self) -> bool {
161        self.state.contains(ContextState::CLOSE)
162    }
163
164    /// Get remote socket address context associated with.
165    #[inline]
166    pub fn socket_addr(&self) -> &SocketAddr {
167        &self.addr
168    }
169}