Skip to main content

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    /// Returns whether headers should be sent in Camel-Case.
65    ///
66    /// Default is `false`.
67    #[inline]
68    pub fn camel_case_headers(&self) -> bool {
69        self.flags.contains(Flags::CAMEL_CASE)
70    }
71
72    /// Sets whether to send headers formatted as Camel-Case.
73    #[inline]
74    pub fn set_camel_case_headers(&mut self, val: bool) {
75        if val {
76            self.flags.insert(Flags::CAMEL_CASE);
77        } else {
78            self.flags.remove(Flags::CAMEL_CASE);
79        }
80    }
81
82    #[inline]
83    /// Set connection type of the message
84    pub fn set_connection_type(&mut self, ctype: ConnectionType) {
85        match ctype {
86            ConnectionType::Close => self.flags.insert(Flags::CLOSE),
87            ConnectionType::KeepAlive => self.flags.insert(Flags::KEEP_ALIVE),
88            ConnectionType::Upgrade => self.flags.insert(Flags::UPGRADE),
89        }
90    }
91
92    #[inline]
93    /// Connection type
94    pub fn connection_type(&self) -> ConnectionType {
95        if self.flags.contains(Flags::CLOSE) {
96            ConnectionType::Close
97        } else if self.flags.contains(Flags::KEEP_ALIVE) {
98            ConnectionType::KeepAlive
99        } else if self.flags.contains(Flags::UPGRADE) {
100            ConnectionType::Upgrade
101        } else if self.version < Version::HTTP_11 {
102            ConnectionType::Close
103        } else {
104            ConnectionType::KeepAlive
105        }
106    }
107
108    /// Connection upgrade status
109    pub fn upgrade(&self) -> bool {
110        self.headers()
111            .get(header::CONNECTION)
112            .map(|hdr| {
113                if let Ok(s) = hdr.to_str() {
114                    s.to_ascii_lowercase().contains("upgrade")
115                } else {
116                    false
117                }
118            })
119            .unwrap_or(false)
120    }
121
122    #[inline]
123    /// Get response body chunking state
124    pub fn chunked(&self) -> bool {
125        !self.flags.contains(Flags::NO_CHUNKING)
126    }
127
128    #[inline]
129    pub fn no_chunking(&mut self, val: bool) {
130        if val {
131            self.flags.insert(Flags::NO_CHUNKING);
132        } else {
133            self.flags.remove(Flags::NO_CHUNKING);
134        }
135    }
136
137    /// Request contains `EXPECT` header.
138    #[inline]
139    pub fn expect(&self) -> bool {
140        self.flags.contains(Flags::EXPECT)
141    }
142
143    #[inline]
144    pub(crate) fn set_expect(&mut self) {
145        self.flags.insert(Flags::EXPECT);
146    }
147}
148
149#[allow(clippy::large_enum_variant)]
150#[derive(Debug)]
151pub enum RequestHeadType {
152    Owned(RequestHead),
153    Rc(Rc<RequestHead>, Option<HeaderMap>),
154}
155
156impl RequestHeadType {
157    pub fn extra_headers(&self) -> Option<&HeaderMap> {
158        match self {
159            RequestHeadType::Owned(_) => None,
160            RequestHeadType::Rc(_, headers) => headers.as_ref(),
161        }
162    }
163}
164
165impl AsRef<RequestHead> for RequestHeadType {
166    fn as_ref(&self) -> &RequestHead {
167        match self {
168            RequestHeadType::Owned(head) => head,
169            RequestHeadType::Rc(head, _) => head.as_ref(),
170        }
171    }
172}
173
174impl From<RequestHead> for RequestHeadType {
175    fn from(head: RequestHead) -> Self {
176        RequestHeadType::Owned(head)
177    }
178}