goose_http/request/
mod.rs1use std::time::SystemTime;
8
9use bytes::Bytes;
10
11use crate::{
12 body::Body,
13 common::{HttpVersion, Method},
14 date,
15 headers::{HeaderName, Headers, header_keys},
16};
17
18#[derive(Debug, Clone, PartialEq, Eq)]
20pub enum RequestTarget {
21 Origin(String),
23 Absolute(String),
25 Authority(String),
27 Asterisk,
29}
30
31impl RequestTarget {
32 pub fn origin(path: impl Into<String>) -> Self {
34 RequestTarget::Origin(path.into())
35 }
36
37 pub fn as_str(&self) -> &str {
39 match self {
40 RequestTarget::Origin(s) | RequestTarget::Absolute(s) | RequestTarget::Authority(s) => {
41 s.as_str()
42 }
43 RequestTarget::Asterisk => "*",
44 }
45 }
46}
47
48#[derive(Debug, Clone)]
50pub struct Request {
51 method: Method,
52 target: RequestTarget,
53 version: HttpVersion,
54 headers: Headers,
55 body: Body,
56 payload: Bytes,
57}
58
59impl Request {
60 pub fn new(method: Method, target: RequestTarget) -> Self {
62 Self {
63 method,
64 target,
65 version: HttpVersion::HTTP_1_1,
66 headers: Headers::new(),
67 body: Body::Empty,
68 payload: Bytes::new(),
69 }
70 }
71
72 pub fn builder(method: Method, target: RequestTarget) -> RequestBuilder {
74 RequestBuilder::new(method, target)
75 }
76
77 pub fn method(&self) -> &Method {
79 &self.method
80 }
81
82 pub fn target(&self) -> &RequestTarget {
84 &self.target
85 }
86
87 pub fn version(&self) -> HttpVersion {
89 self.version
90 }
91
92 pub fn headers(&self) -> &Headers {
94 &self.headers
95 }
96
97 pub fn header(&self, name: impl Into<HeaderName>) -> Option<&str> {
99 self.headers.get(name)
100 }
101
102 pub fn contains_header(&self, name: impl Into<HeaderName>) -> bool {
104 self.headers.contains(name)
105 }
106
107 pub fn body(&self) -> &Body {
109 &self.body
110 }
111
112 pub fn body_bytes(&self) -> &Bytes {
114 &self.payload
115 }
116
117 pub fn headers_mut(&mut self) -> &mut Headers {
119 &mut self.headers
120 }
121
122 pub fn set_version(&mut self, version: HttpVersion) {
124 self.version = version;
125 }
126
127 pub fn set_body(&mut self, body: Body) {
129 self.body = body;
130 }
131
132 pub fn set_body_bytes(&mut self, bytes: impl Into<Bytes>) {
134 self.payload = bytes.into();
135 }
136
137 pub fn into_body_bytes(self) -> Bytes {
139 self.payload
140 }
141
142 pub fn take_body_bytes(&mut self) -> Bytes {
144 std::mem::take(&mut self.payload)
145 }
146
147 pub fn expect_100_continue(&self) -> bool {
149 self.header(header_keys::EXPECT)
150 .map(|value| {
151 value
152 .split(',')
153 .any(|token| token.trim().eq_ignore_ascii_case("100-continue"))
154 })
155 .unwrap_or(false)
156 }
157
158 pub fn wants_close(&self) -> bool {
160 self.header(header_keys::CONNECTION).map_or(false, |value| {
161 value
162 .split(',')
163 .any(|token| token.trim().eq_ignore_ascii_case("close"))
164 })
165 }
166
167 pub fn if_none_match(&self) -> Option<&str> {
169 self.header(header_keys::IF_NONE_MATCH)
170 .map(|value| value.trim())
171 }
172
173 pub fn if_match(&self) -> Option<&str> {
175 self.header(header_keys::IF_MATCH).map(|value| value.trim())
176 }
177
178 pub fn if_unmodified_since(&self) -> Option<SystemTime> {
180 self.header(header_keys::IF_UNMODIFIED_SINCE)
181 .and_then(|value| date::parse_http_date(value.trim()))
182 }
183
184 pub fn if_modified_since(&self) -> Option<SystemTime> {
186 self.header(header_keys::IF_MODIFIED_SINCE)
187 .and_then(|value| date::parse_http_date(value.trim()))
188 }
189}
190
191#[derive(Debug, Clone)]
193pub struct RequestBuilder {
194 method: Method,
195 target: RequestTarget,
196 version: HttpVersion,
197 headers: Headers,
198 body: Body,
199 payload: Bytes,
200}
201
202impl RequestBuilder {
203 fn new(method: Method, target: RequestTarget) -> Self {
204 Self {
205 method,
206 target,
207 version: HttpVersion::HTTP_1_1,
208 headers: Headers::new(),
209 body: Body::Empty,
210 payload: Bytes::new(),
211 }
212 }
213
214 pub fn version(mut self, version: HttpVersion) -> Self {
216 self.version = version;
217 self
218 }
219
220 pub fn header(mut self, name: impl Into<HeaderName>, value: impl Into<String>) -> Self {
222 self.headers.insert(name, value);
223 self
224 }
225
226 pub fn body(mut self, body: Body) -> Self {
228 self.body = body;
229 self
230 }
231
232 pub fn body_bytes(mut self, bytes: impl Into<Bytes>) -> Self {
234 self.payload = bytes.into();
235 self
236 }
237
238 pub fn build(self) -> Request {
240 Request {
241 method: self.method,
242 target: self.target,
243 version: self.version,
244 headers: self.headers,
245 body: self.body,
246 payload: self.payload,
247 }
248 }
249}