actix_http/requests/
head.rs

1use std::{net, rc::Rc};
2
3use crate::{
4    header::{self, HeaderMap},
5    message::{Flags, Head, MessagePool},
6    ConnectionType, Method, Uri, Version,
7};
8
9thread_local! {
10    static REQUEST_POOL: MessagePool<RequestHead> = MessagePool::<RequestHead>::create()
11}
12
13#[derive(Debug, Clone)]
14pub struct RequestHead {
15    pub method: Method,
16    pub uri: Uri,
17    pub version: Version,
18    pub headers: HeaderMap,
19
20    /// Will only be None when called in unit tests unless set manually.
21    pub peer_addr: Option<net::SocketAddr>,
22
23    flags: Flags,
24}
25
26impl Default for RequestHead {
27    fn default() -> RequestHead {
28        RequestHead {
29            method: Method::default(),
30            uri: Uri::default(),
31            version: Version::HTTP_11,
32            headers: HeaderMap::with_capacity(16),
33            peer_addr: None,
34            flags: Flags::empty(),
35        }
36    }
37}
38
39impl Head for RequestHead {
40    fn clear(&mut self) {
41        self.flags = Flags::empty();
42        self.headers.clear();
43    }
44
45    fn with_pool<F, R>(f: F) -> R
46    where
47        F: FnOnce(&MessagePool<Self>) -> R,
48    {
49        REQUEST_POOL.with(|p| f(p))
50    }
51}
52
53impl RequestHead {
54    /// Read the message headers.
55    pub fn headers(&self) -> &HeaderMap {
56        &self.headers
57    }
58
59    /// Mutable reference to the message headers.
60    pub fn headers_mut(&mut self) -> &mut HeaderMap {
61        &mut self.headers
62    }
63
64    /// Is to uppercase headers with Camel-Case.
65    /// Default is `false`
66    #[inline]
67    pub fn camel_case_headers(&self) -> bool {
68        self.flags.contains(Flags::CAMEL_CASE)
69    }
70
71    /// Set `true` to send headers which are formatted as Camel-Case.
72    #[inline]
73    pub fn set_camel_case_headers(&mut self, val: bool) {
74        if val {
75            self.flags.insert(Flags::CAMEL_CASE);
76        } else {
77            self.flags.remove(Flags::CAMEL_CASE);
78        }
79    }
80
81    #[inline]
82    /// Set connection type of the message
83    pub fn set_connection_type(&mut self, ctype: ConnectionType) {
84        match ctype {
85            ConnectionType::Close => self.flags.insert(Flags::CLOSE),
86            ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
87            ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
88        }
89    }
90
91    #[inline]
92    /// Connection type
93    pub fn connection_type(&self) -> ConnectionType {
94        if self.flags.contains(Flags::CLOSE) {
95            ConnectionType::Close
96        } else if self.flags.contains(Flags::KEEP_ALIVE) {
97            ConnectionType::KeepAlive
98        } else if self.flags.contains(Flags::UPGRADE) {
99            ConnectionType::Upgrade
100        } else if self.version < Version::HTTP_11 {
101            ConnectionType::Close
102        } else {
103            ConnectionType::KeepAlive
104        }
105    }
106
107    /// Connection upgrade status
108    pub fn upgrade(&self) -> bool {
109        self.headers()
110            .get(header::CONNECTION)
111            .map(|hdr| {
112                if let Ok(s) = hdr.to_str() {
113                    s.to_ascii_lowercase().contains("upgrade")
114                } else {
115                    false
116                }
117            })
118            .unwrap_or(false)
119    }
120
121    #[inline]
122    /// Get response body chunking state
123    pub fn chunked(&self) -> bool {
124        !self.flags.contains(Flags::NO_CHUNKING)
125    }
126
127    #[inline]
128    pub fn no_chunking(&mut self, val: bool) {
129        if val {
130            self.flags.insert(Flags::NO_CHUNKING);
131        } else {
132            self.flags.remove(Flags::NO_CHUNKING);
133        }
134    }
135
136    /// Request contains `EXPECT` header.
137    #[inline]
138    pub fn expect(&self) -> bool {
139        self.flags.contains(Flags::EXPECT)
140    }
141
142    #[inline]
143    pub(crate) fn set_expect(&mut self) {
144        self.flags.insert(Flags::EXPECT);
145    }
146}
147
148#[allow(clippy::large_enum_variant)]
149#[derive(Debug)]
150pub enum RequestHeadType {
151    Owned(RequestHead),
152    Rc(Rc<RequestHead>, Option<HeaderMap>),
153}
154
155impl RequestHeadType {
156    pub fn extra_headers(&self) -> Option<&HeaderMap> {
157        match self {
158            RequestHeadType::Owned(_) => None,
159            RequestHeadType::Rc(_, headers) => headers.as_ref(),
160        }
161    }
162}
163
164impl AsRef<RequestHead> for RequestHeadType {
165    fn as_ref(&self) -> &RequestHead {
166        match self {
167            RequestHeadType::Owned(head) => head,
168            RequestHeadType::Rc(head, _) => head.as_ref(),
169        }
170    }
171}
172
173impl From<RequestHead> for RequestHeadType {
174    fn from(head: RequestHead) -> Self {
175        RequestHeadType::Owned(head)
176    }
177}