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]
67 pub fn camel_case_headers(&self) -> bool {
68 self.flags.contains(Flags::CAMEL_CASE)
69 }
70
71 #[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 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 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 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 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 #[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}