actix_http/requests/
head.rs1use 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 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 pub fn headers(&self) -> &HeaderMap {
56 &self.headers
57 }
58
59 pub fn headers_mut(&mut self) -> &mut HeaderMap {
61 &mut self.headers
62 }
63
64 #[inline]
68 pub fn camel_case_headers(&self) -> bool {
69 self.flags.contains(Flags::CAMEL_CASE)
70 }
71
72 #[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 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 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 pub fn upgrade(&self) -> bool {
110 let mut upgrade = false;
111
112 for conn in self.headers().get_all(header::CONNECTION) {
113 if let Ok(conn) = conn.to_str() {
114 for option in conn.split(',').map(str::trim) {
115 if option.eq_ignore_ascii_case("close") {
116 return false;
117 } else if option.eq_ignore_ascii_case("upgrade") {
118 upgrade = true;
119 }
120 }
121 }
122 }
123
124 upgrade
125 }
126
127 #[inline]
128 pub fn chunked(&self) -> bool {
130 !self.flags.contains(Flags::NO_CHUNKING)
131 }
132
133 #[inline]
134 pub fn no_chunking(&mut self, val: bool) {
135 if val {
136 self.flags.insert(Flags::NO_CHUNKING);
137 } else {
138 self.flags.remove(Flags::NO_CHUNKING);
139 }
140 }
141
142 #[inline]
144 pub fn expect(&self) -> bool {
145 self.flags.contains(Flags::EXPECT)
146 }
147
148 #[inline]
149 pub(crate) fn set_expect(&mut self) {
150 self.flags.insert(Flags::EXPECT);
151 }
152}
153
154#[allow(clippy::large_enum_variant)]
155#[derive(Debug)]
156pub enum RequestHeadType {
157 Owned(RequestHead),
158 Rc(Rc<RequestHead>, Option<HeaderMap>),
159}
160
161impl RequestHeadType {
162 pub fn extra_headers(&self) -> Option<&HeaderMap> {
163 match self {
164 RequestHeadType::Owned(_) => None,
165 RequestHeadType::Rc(_, headers) => headers.as_ref(),
166 }
167 }
168}
169
170impl AsRef<RequestHead> for RequestHeadType {
171 fn as_ref(&self) -> &RequestHead {
172 match self {
173 RequestHeadType::Owned(head) => head,
174 RequestHeadType::Rc(head, _) => head.as_ref(),
175 }
176 }
177}
178
179impl From<RequestHead> for RequestHeadType {
180 fn from(head: RequestHead) -> Self {
181 RequestHeadType::Owned(head)
182 }
183}