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 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 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 #[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}