http_types_rs/request.rs
1use futures::{io, prelude::*};
2
3use std::convert::{Into, TryInto};
4use std::mem;
5use std::ops::Index;
6use std::pin::Pin;
7use std::task::{Context, Poll};
8
9#[cfg(feature = "serde")]
10use crate::convert::{DeserializeOwned, Serialize};
11use crate::headers::{self, HeaderName, HeaderValue, HeaderValues, Headers, Names, ToHeaderValues, Values, CONTENT_TYPE};
12use crate::mime::Mime;
13
14use crate::transfer::{trailers, Trailers};
15use crate::{Body, Extensions, Method, Url, Version};
16
17pin_project_lite::pin_project! {
18 /// An HTTP request.
19 ///
20 /// # Examples
21 ///
22 /// ```
23 /// use http_types_rs::Request;
24 ///
25 /// let mut req = Request::get("https://example.com");
26 /// req.set_body("Hello, Nori!");
27 /// ```
28 #[derive(Debug)]
29 pub struct Request {
30 method: Method,
31 url: Url,
32 headers: Headers,
33 version: Option<Version>,
34 #[pin]
35 body: Body,
36 local_addr: Option<String>,
37 peer_addr: Option<String>,
38 ext: Extensions,
39 trailers_sender: Option<async_channel::Sender<Trailers>>,
40 trailers_receiver: Option<async_channel::Receiver<Trailers>>,
41 has_trailers: bool,
42 }
43}
44
45impl Request {
46 /// Create a new request.
47 pub fn new<U>(method: Method, url: U) -> Self
48 where
49 U: TryInto<Url>,
50 U::Error: std::fmt::Debug,
51 {
52 let url = url.try_into().expect("Could not convert into a valid url");
53 let (trailers_sender, trailers_receiver) = async_channel::bounded(1);
54 Self {
55 method,
56 url,
57 headers: Headers::new(),
58 version: None,
59 body: Body::empty(),
60 ext: Extensions::new(),
61 peer_addr: None,
62 local_addr: None,
63 trailers_receiver: Some(trailers_receiver),
64 trailers_sender: Some(trailers_sender),
65 has_trailers: false,
66 }
67 }
68
69 /// Sets a string representation of the peer address of this
70 /// request. This might take the form of an ip/fqdn and port or a
71 /// local socket address.
72 pub fn set_peer_addr(&mut self, peer_addr: Option<impl std::string::ToString>) {
73 self.peer_addr = peer_addr.map(|addr| addr.to_string());
74 }
75
76 /// Sets a string representation of the local address that this
77 /// request was received on. This might take the form of an ip/fqdn and
78 /// port, or a local socket address.
79 pub fn set_local_addr(&mut self, local_addr: Option<impl std::string::ToString>) {
80 self.local_addr = local_addr.map(|addr| addr.to_string());
81 }
82
83 /// Get the peer socket address for the underlying transport, if
84 /// that information is available for this request.
85 pub fn peer_addr(&self) -> Option<&str> {
86 self.peer_addr.as_deref()
87 }
88
89 /// Get the local socket address for the underlying transport, if
90 /// that information is available for this request.
91 pub fn local_addr(&self) -> Option<&str> {
92 self.local_addr.as_deref()
93 }
94
95 /// Get the remote address for this request.
96 ///
97 /// This is determined in the following priority:
98 /// 1. `Forwarded` header `for` key
99 /// 2. The first `X-Forwarded-For` header
100 /// 3. Peer address of the transport
101 pub fn remote(&self) -> Option<&str> {
102 self.forwarded_for().or_else(|| self.peer_addr())
103 }
104
105 /// Get the destination host for this request.
106 ///
107 /// This is determined in the following priority:
108 /// 1. `Forwarded` header `host` key
109 /// 2. The first `X-Forwarded-Host` header
110 /// 3. `Host` header
111 /// 4. URL domain, if any
112 pub fn host(&self) -> Option<&str> {
113 self.forwarded_header_part("host")
114 .or_else(|| self.header("X-Forwarded-Host").and_then(|h| h.as_str().split(',').next()))
115 .or_else(|| self.header(&headers::HOST).map(|h| h.as_str()))
116 .or_else(|| self.url().host_str())
117 }
118
119 fn forwarded_header_part(&self, part: &str) -> Option<&str> {
120 self.header("Forwarded").and_then(|header| {
121 header.as_str().split(';').find_map(|key_equals_value| {
122 let parts = key_equals_value.split('=').collect::<Vec<_>>();
123 if parts.len() == 2 && parts[0].eq_ignore_ascii_case(part) {
124 Some(parts[1])
125 } else {
126 None
127 }
128 })
129 })
130 }
131
132 fn forwarded_for(&self) -> Option<&str> {
133 self.forwarded_header_part("for")
134 .or_else(|| self.header("X-Forwarded-For").and_then(|header| header.as_str().split(',').next()))
135 }
136
137 /// Get the HTTP method
138 pub fn method(&self) -> Method {
139 self.method
140 }
141
142 /// Set the HTTP method.
143 pub fn set_method(&mut self, method: Method) {
144 self.method = method;
145 }
146
147 /// Get a reference to the url.
148 ///
149 /// # Examples
150 ///
151 /// ```
152 /// # fn main() -> Result<(), http_types_rs::Error> {
153 /// #
154 /// use http_types_rs::{Request, Response, StatusCode};
155 /// let mut req = Request::get("https://example.com");
156 /// assert_eq!(req.url().scheme(), "https");
157 /// #
158 /// # Ok(()) }
159 /// ```
160 pub fn url(&self) -> &Url {
161 &self.url
162 }
163
164 /// Get a mutable reference to the url.
165 ///
166 /// # Examples
167 ///
168 /// ```
169 /// # fn main() -> Result<(), http_types_rs::Error> {
170 /// #
171 /// use http_types_rs::{Method, Request, Response, StatusCode, Url};
172 /// let mut req = Request::get("https://example.com");
173 /// req.url_mut().set_scheme("http");
174 /// assert_eq!(req.url().scheme(), "http");
175 /// #
176 /// # Ok(()) }
177 /// ```
178 pub fn url_mut(&mut self) -> &mut Url {
179 &mut self.url
180 }
181
182 /// Set the request body.
183 ///
184 /// # Examples
185 ///
186 /// ```
187 /// use http_types_rs::{Method, Request};
188 ///
189 /// let mut req = Request::get("https://example.com");
190 /// req.set_body("Hello, Nori!");
191 /// ```
192 pub fn set_body(&mut self, body: impl Into<Body>) {
193 self.replace_body(body);
194 }
195
196 /// Swaps the value of the body with another body, without deinitializing
197 /// either one.
198 ///
199 /// # Examples
200 ///
201 /// ```
202 /// # use async_std::io::prelude::*;
203 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
204 /// #
205 /// use http_types_rs::{Body, Method, Request};
206 ///
207 /// let mut req = Request::get("https://example.com");
208 /// req.set_body("Hello, Nori!");
209 /// let mut body: Body = req.replace_body("Hello, Chashu!");
210 ///
211 /// let mut string = String::new();
212 /// body.read_to_string(&mut string).await?;
213 /// assert_eq!(&string, "Hello, Nori!");
214 /// #
215 /// # Ok(()) }) }
216 /// ```
217 pub fn replace_body(&mut self, body: impl Into<Body>) -> Body {
218 let body = mem::replace(&mut self.body, body.into());
219 self.copy_content_type_from_body();
220 body
221 }
222
223 /// Replace the request body with a new body, and return the old body.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// # use async_std::io::prelude::*;
229 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
230 /// #
231 /// use http_types_rs::{Body, Request};
232 ///
233 /// let mut req = Request::get("https://example.com");
234 /// req.set_body("Hello, Nori!");
235 /// let mut body = "Hello, Chashu!".into();
236 /// req.swap_body(&mut body);
237 ///
238 /// let mut string = String::new();
239 /// body.read_to_string(&mut string).await?;
240 /// assert_eq!(&string, "Hello, Nori!");
241 /// #
242 /// # Ok(()) }) }
243 /// ```
244 pub fn swap_body(&mut self, body: &mut Body) {
245 mem::swap(&mut self.body, body);
246 self.copy_content_type_from_body();
247 }
248
249 /// Take the request body, replacing it with an empty body.
250 ///
251 /// # Examples
252 ///
253 /// ```
254 /// # use async_std::io::prelude::*;
255 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
256 /// #
257 /// use http_types_rs::{Body, Request};
258 ///
259 /// let mut req = Request::get("https://example.com");
260 /// req.set_body("Hello, Nori!");
261 /// let mut body: Body = req.take_body();
262 ///
263 /// let mut string = String::new();
264 /// body.read_to_string(&mut string).await?;
265 /// assert_eq!(&string, "Hello, Nori!");
266 ///
267 /// # let mut string = String::new();
268 /// # req.read_to_string(&mut string).await?;
269 /// # assert_eq!(&string, "");
270 /// #
271 /// # Ok(()) }) }
272 /// ```
273 pub fn take_body(&mut self) -> Body {
274 self.replace_body(Body::empty())
275 }
276
277 /// Read the body as a string.
278 ///
279 /// This consumes the request. If you want to read the body without
280 /// consuming the request, consider using the `take_body` method and
281 /// then calling `Body::into_string` or using the Request's AsyncRead
282 /// implementation to read the body.
283 ///
284 /// # Examples
285 ///
286 /// ```
287 /// # use std::io::prelude::*;
288 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
289 /// use async_std::io::Cursor;
290 /// use http_types_rs::{Body, Request};
291 ///
292 /// let mut req = Request::get("https://example.com");
293 ///
294 /// let cursor = Cursor::new("Hello Nori");
295 /// let body = Body::from_reader(cursor, None);
296 /// req.set_body(body);
297 /// assert_eq!(&req.body_string().await.unwrap(), "Hello Nori");
298 /// # Ok(()) }) }
299 /// ```
300 pub async fn body_string(&mut self) -> crate::Result<String> {
301 let body = self.take_body();
302 body.into_string().await
303 }
304
305 /// Read the body as bytes.
306 ///
307 /// This consumes the `Request`. If you want to read the body without
308 /// consuming the request, consider using the `take_body` method and
309 /// then calling `Body::into_bytes` or using the Request's AsyncRead
310 /// implementation to read the body.
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
316 /// use http_types_rs::{Body, Request};
317 ///
318 /// let bytes = vec![1, 2, 3];
319 /// let mut req = Request::get("https://example.com");
320 /// req.set_body(Body::from_bytes(bytes));
321 ///
322 /// let bytes = req.body_bytes().await?;
323 /// assert_eq!(bytes, vec![1, 2, 3]);
324 /// # Ok(()) }) }
325 /// ```
326 pub async fn body_bytes(&mut self) -> crate::Result<Vec<u8>> {
327 let body = self.take_body();
328 body.into_bytes().await
329 }
330
331 /// Read the body as JSON.
332 ///
333 /// This consumes the request. If you want to read the body without
334 /// consuming the request, consider using the `take_body` method and
335 /// then calling `Body::into_json` or using the Request's AsyncRead
336 /// implementation to read the body.
337 ///
338 /// # Examples
339 ///
340 /// ```
341 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
342 /// use http_types_rs::convert::{Deserialize, Serialize};
343 /// use http_types_rs::{Body, Request};
344 ///
345 /// #[derive(Debug, Serialize, Deserialize)]
346 /// # #[serde(crate = "serde")]
347 /// struct Cat {
348 /// name: String,
349 /// }
350 ///
351 /// let cat = Cat {
352 /// name: String::from("chashu"),
353 /// };
354 /// let mut req = Request::get("https://example.com");
355 /// req.set_body(Body::from_json(&cat)?);
356 ///
357 /// let cat: Cat = req.body_json().await?;
358 /// assert_eq!(&cat.name, "chashu");
359 /// # Ok(()) }) }
360 /// ```
361 #[cfg(feature = "serde")]
362 pub async fn body_json<T: DeserializeOwned>(&mut self) -> crate::Result<T> {
363 let body = self.take_body();
364 body.into_json().await
365 }
366
367 /// Read the body as `x-www-form-urlencoded`.
368 ///
369 /// This consumes the request. If you want to read the body without
370 /// consuming the request, consider using the `take_body` method and
371 /// then calling `Body::into_json` or using the Request's AsyncRead
372 /// implementation to read the body.
373 ///
374 /// # Examples
375 ///
376 /// ```
377 /// # fn main() -> http_types_rs::Result<()> { async_std::task::block_on(async {
378 /// use http_types_rs::convert::{Deserialize, Serialize};
379 /// use http_types_rs::{Body, Request};
380 ///
381 /// #[derive(Debug, Serialize, Deserialize)]
382 /// # #[serde(crate = "serde")]
383 /// struct Cat {
384 /// name: String,
385 /// }
386 ///
387 /// let cat = Cat {
388 /// name: String::from("chashu"),
389 /// };
390 /// let mut req = Request::get("https://example.com");
391 /// req.set_body(Body::from_form(&cat)?);
392 ///
393 /// let cat: Cat = req.body_form().await?;
394 /// assert_eq!(&cat.name, "chashu");
395 /// # Ok(()) }) }
396 /// ```
397 #[cfg(feature = "serde")]
398 pub async fn body_form<T: DeserializeOwned>(&mut self) -> crate::Result<T> {
399 let body = self.take_body();
400 body.into_form().await
401 }
402
403 /// Get an HTTP header.
404 pub fn header(&self, name: impl Into<HeaderName>) -> Option<&HeaderValues> {
405 self.headers.get(name)
406 }
407
408 /// Get a mutable reference to a header.
409 pub fn header_mut(&mut self, name: impl Into<HeaderName>) -> Option<&mut HeaderValues> {
410 self.headers.get_mut(name.into())
411 }
412
413 /// Remove a header.
414 pub fn remove_header(&mut self, name: impl Into<HeaderName>) -> Option<HeaderValues> {
415 self.headers.remove(name.into())
416 }
417
418 /// Set an HTTP header.
419 ///
420 /// # Examples
421 ///
422 /// ```
423 /// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
424 /// #
425 /// use http_types_rs::Request;
426 ///
427 /// let mut req = Request::get("https://example.com");
428 /// req.insert_header("Content-Type", "text/plain");
429 /// #
430 /// # Ok(()) }
431 /// ```
432 pub fn insert_header(&mut self, name: impl Into<HeaderName>, values: impl ToHeaderValues) -> crate::Result<Option<HeaderValues>> {
433 self.headers.insert(name, values)
434 }
435
436 /// Append a header to the headers.
437 ///
438 /// Unlike `insert` this function will not override the contents of a
439 /// header, but insert a header if there aren't any. Or else append to
440 /// the existing list of headers.
441 ///
442 /// # Examples
443 ///
444 /// ```
445 /// # fn main() -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
446 /// #
447 /// use http_types_rs::Request;
448 ///
449 /// let mut req = Request::get("https://example.com");
450 /// req.append_header("Content-Type", "text/plain");
451 /// #
452 /// # Ok(()) }
453 /// ```
454 pub fn append_header(&mut self, name: impl Into<HeaderName>, values: impl ToHeaderValues) -> crate::Result<()> {
455 self.headers.append(name, values)
456 }
457
458 /// Set the response MIME.
459 // TODO: return a parsed MIME
460 pub fn set_content_type(&mut self, mime: Mime) -> Option<HeaderValues> {
461 let value: HeaderValue = mime.into();
462
463 // A Mime instance is guaranteed to be valid header name.
464 self.insert_header(CONTENT_TYPE, value).unwrap()
465 }
466
467 /// Copy MIME data from the body.
468 fn copy_content_type_from_body(&mut self) {
469 if self.header(CONTENT_TYPE).is_none() {
470 if let Some(mime) = self.body.mime().cloned() {
471 self.set_content_type(mime);
472 }
473 }
474 }
475
476 /// Get the current content type
477 pub fn content_type(&self) -> Option<Mime> {
478 self.header(CONTENT_TYPE)?.last().as_str().parse().ok()
479 }
480
481 /// Get the length of the body stream, if it has been set.
482 ///
483 /// This value is set when passing a fixed-size object into as the body.
484 /// E.g. a string, or a buffer. Consumers of this API should check this
485 /// value to decide whether to use `Chunked` encoding, or set the
486 /// response length.
487 pub fn len(&self) -> Option<u64> {
488 self.body.len()
489 }
490
491 /// Returns `true` if the request has a set body stream length of zero,
492 /// `false` otherwise.
493 pub fn is_empty(&self) -> Option<bool> {
494 self.body.is_empty()
495 }
496
497 /// Get the HTTP version, if one has been set.
498 ///
499 /// # Examples
500 ///
501 /// ```
502 /// use http_types_rs::{Request, Version};
503 ///
504 /// # fn main() -> Result<(), http_types_rs::Error> {
505 /// #
506 /// let mut req = Request::get("https://example.com");
507 /// assert_eq!(req.version(), None);
508 ///
509 /// req.set_version(Some(Version::Http2_0));
510 /// assert_eq!(req.version(), Some(Version::Http2_0));
511 /// #
512 /// # Ok(()) }
513 /// ```
514 pub fn version(&self) -> Option<Version> {
515 self.version
516 }
517
518 /// Set the HTTP version.
519 ///
520 /// # Examples
521 ///
522 /// ```
523 /// use http_types_rs::{Request, Version};
524 ///
525 /// # fn main() -> Result<(), http_types_rs::Error> {
526 /// #
527 /// let mut req = Request::get("https://example.com");
528 /// req.set_version(Some(Version::Http2_0));
529 /// #
530 /// # Ok(()) }
531 /// ```
532 pub fn set_version(&mut self, version: Option<Version>) {
533 self.version = version;
534 }
535
536 /// Sends trailers to the receiver.
537 pub fn send_trailers(&mut self) -> trailers::Sender {
538 self.has_trailers = true;
539 let sender = self.trailers_sender.take().expect("Trailers sender can only be constructed once");
540 trailers::Sender::new(sender)
541 }
542
543 /// Receive trailers from a sender.
544 pub fn recv_trailers(&mut self) -> trailers::Receiver {
545 let receiver = self.trailers_receiver.take().expect("Trailers receiver can only be constructed once");
546 trailers::Receiver::new(receiver)
547 }
548
549 /// Returns `true` if sending trailers is in progress.
550 pub fn has_trailers(&self) -> bool {
551 self.has_trailers
552 }
553
554 /// An iterator visiting all header pairs in arbitrary order.
555 pub fn iter(&self) -> headers::Iter<'_> {
556 self.headers.iter()
557 }
558
559 /// An iterator visiting all header pairs in arbitrary order, with mutable
560 /// references to the values.
561 pub fn iter_mut(&mut self) -> headers::IterMut<'_> {
562 self.headers.iter_mut()
563 }
564
565 /// An iterator visiting all header names in arbitrary order.
566 pub fn header_names(&self) -> Names<'_> {
567 self.headers.names()
568 }
569
570 /// An iterator visiting all header values in arbitrary order.
571 pub fn header_values(&self) -> Values<'_> {
572 self.headers.values()
573 }
574
575 /// Returns a reference to the existing local state.
576 pub fn ext(&self) -> &Extensions {
577 &self.ext
578 }
579
580 /// Returns a mutuable reference to the existing local state.
581 ///
582 /// # Examples
583 ///
584 /// ```
585 /// # fn main() -> Result<(), http_types_rs::Error> {
586 /// #
587 /// use http_types_rs::{Request, Version};
588 ///
589 /// let mut req = Request::get("https://example.com");
590 /// req.ext_mut().insert("hello from the extension");
591 /// assert_eq!(req.ext().get(), Some(&"hello from the extension"));
592 /// #
593 /// # Ok(()) }
594 /// ```
595 pub fn ext_mut(&mut self) -> &mut Extensions {
596 &mut self.ext
597 }
598
599 /// Get the URL querystring.
600 ///
601 /// # Examples
602 ///
603 /// ```
604 /// use http_types_rs::convert::Deserialize;
605 /// use http_types_rs::Request;
606 /// use std::collections::HashMap;
607 ///
608 /// // An owned structure:
609 ///
610 /// #[derive(Deserialize)]
611 /// # #[serde(crate = "serde")]
612 /// struct Index {
613 /// page: u32,
614 /// selections: HashMap<String, String>,
615 /// }
616 ///
617 /// let mut req = Request::get("https://httpbin.org/get?page=2&selections[width]=narrow&selections[height]=tall");
618 /// let Index { page, selections } = req.query().unwrap();
619 /// assert_eq!(page, 2);
620 /// assert_eq!(selections["width"], "narrow");
621 /// assert_eq!(selections["height"], "tall");
622 ///
623 /// // Using borrows:
624 ///
625 /// #[derive(Deserialize)]
626 /// # #[serde(crate = "serde")]
627 /// struct Query<'q> {
628 /// format: &'q str,
629 /// }
630 ///
631 /// let mut req = Request::get("https://httpbin.org/get?format=bananna");
632 /// let Query { format } = req.query().unwrap();
633 /// assert_eq!(format, "bananna");
634 /// ```
635 #[cfg(feature = "serde")]
636 pub fn query<'de, T: serde::de::Deserialize<'de>>(&'de self) -> crate::Result<T> {
637 // Default to an empty query string if no query parameter has beserde_crateen specified.
638 // This allows successful deserialisation of structs where all fielserde_crateds are optional
639 // when none of those fields has actually been passed by the caller.
640 let query = self.url().query().unwrap_or("");
641 serde_qs::from_str(query).map_err(|e| {
642 // Return the displayable version of the deserialisation error to the caller
643 // for easier debugging.
644 crate::Error::from_str(crate::StatusCode::BadRequest, format!("{}", e))
645 })
646 }
647
648 /// Set the URL querystring.
649 ///
650 /// # Examples
651 ///
652 /// ```
653 /// use http_types_rs::convert::Serialize;
654 /// use http_types_rs::{Method, Request};
655 /// use std::collections::HashMap;
656 ///
657 /// #[derive(Serialize)]
658 /// # #[serde(crate = "serde")]
659 /// struct Index {
660 /// page: u32,
661 /// topics: Vec<&'static str>,
662 /// }
663 ///
664 /// let query = Index { page: 2, topics: vec!["rust", "crabs", "crustaceans"] };
665 /// let mut req = Request::get("https://httpbin.org/get");
666 /// req.set_query(&query).unwrap();
667 /// assert_eq!(req.url().query(), Some("page=2&topics[0]=rust&topics[1]=crabs&topics[2]=crustaceans"));
668 /// ```
669 #[cfg(feature = "serde")]
670 pub fn set_query(&mut self, query: &impl Serialize) -> crate::Result<()> {
671 let query = serde_qs::to_string(query).map_err(|e| crate::Error::from_str(crate::StatusCode::BadRequest, format!("{}", e)))?;
672 self.url.set_query(Some(&query));
673 Ok(())
674 }
675
676 /// Create a `GET` request.
677 ///
678 /// The `GET` method requests a representation of the specified resource.
679 /// Requests using `GET` should only retrieve data.
680 ///
681 /// # Examples
682 ///
683 /// ```
684 /// use http_types_rs::{Method, Request};
685 ///
686 /// let mut req = Request::get("https://example.com");
687 /// req.set_body("Hello, Nori!");
688 /// assert_eq!(req.method(), Method::Get);
689 /// ```
690 pub fn get<U>(url: U) -> Self
691 where
692 U: TryInto<Url>,
693 U::Error: std::fmt::Debug,
694 {
695 Request::new(Method::Get, url)
696 }
697
698 /// Create a `HEAD` request.
699 ///
700 /// The `HEAD` method asks for a response identical to that of a `GET`
701 /// request, but without the response body.
702 ///
703 /// # Examples
704 ///
705 /// ```
706 /// use http_types_rs::{Method, Request};
707 ///
708 /// let mut req = Request::head("https://example.com");
709 /// assert_eq!(req.method(), Method::Head);
710 /// ```
711 pub fn head<U>(url: U) -> Self
712 where
713 U: TryInto<Url>,
714 U::Error: std::fmt::Debug,
715 {
716 Request::new(Method::Head, url)
717 }
718
719 /// Create a `POST` request.
720 ///
721 /// The `POST` method is used to submit an entity to the specified resource,
722 /// often causing a change in state or side effects on the server.
723 ///
724 /// # Examples
725 ///
726 /// ```
727 /// use http_types_rs::{Method, Request};
728 ///
729 /// let mut req = Request::post("https://example.com");
730 /// assert_eq!(req.method(), Method::Post);
731 /// ```
732 pub fn post<U>(url: U) -> Self
733 where
734 U: TryInto<Url>,
735 U::Error: std::fmt::Debug,
736 {
737 Request::new(Method::Post, url)
738 }
739
740 /// Create a `PUT` request.
741 ///
742 /// The `PUT` method replaces all current representations of the target
743 /// resource with the request payload.
744 ///
745 /// # Examples
746 ///
747 /// ```
748 /// use http_types_rs::{Method, Request};
749 ///
750 /// let mut req = Request::put("https://example.com");
751 /// assert_eq!(req.method(), Method::Put);
752 /// ```
753 pub fn put<U>(url: U) -> Self
754 where
755 U: TryInto<Url>,
756 U::Error: std::fmt::Debug,
757 {
758 Request::new(Method::Put, url)
759 }
760
761 /// Create a `DELETE` request.
762 ///
763 /// The `DELETE` method deletes the specified resource.
764 ///
765 /// # Examples
766 ///
767 /// ```
768 /// use http_types_rs::{Method, Request};
769 ///
770 /// let mut req = Request::delete("https://example.com");
771 /// assert_eq!(req.method(), Method::Delete);
772 /// ```
773 pub fn delete<U>(url: U) -> Self
774 where
775 U: TryInto<Url>,
776 U::Error: std::fmt::Debug,
777 {
778 Request::new(Method::Delete, url)
779 }
780
781 /// Create a `CONNECT` request.
782 ///
783 /// The `CONNECT` method establishes a tunnel to the server identified by
784 /// the target resource.
785 ///
786 /// # Examples
787 ///
788 /// ```
789 /// use http_types_rs::{Method, Request};
790 ///
791 /// let mut req = Request::connect("https://example.com");
792 /// assert_eq!(req.method(), Method::Connect);
793 /// ```
794 pub fn connect<U>(url: U) -> Self
795 where
796 U: TryInto<Url>,
797 U::Error: std::fmt::Debug,
798 {
799 Request::new(Method::Connect, url)
800 }
801
802 /// Create a `OPTIONS` request.
803 ///
804 /// The `OPTIONS` method is used to describe the communication options for
805 /// the target resource.
806 ///
807 /// # Examples
808 ///
809 /// ```
810 /// use http_types_rs::{Method, Request};
811 ///
812 /// let mut req = Request::options("https://example.com");
813 /// assert_eq!(req.method(), Method::Options);
814 /// ```
815 pub fn options<U>(url: U) -> Self
816 where
817 U: TryInto<Url>,
818 U::Error: std::fmt::Debug,
819 {
820 Request::new(Method::Options, url)
821 }
822
823 /// Create a `TRACE` request.
824 ///
825 /// The `TRACE` method performs a message loop-back test along the path to
826 /// the target resource.
827 ///
828 /// # Examples
829 ///
830 /// ```
831 /// use http_types_rs::{Method, Request};
832 ///
833 /// let mut req = Request::trace("https://example.com");
834 /// assert_eq!(req.method(), Method::Trace);
835 /// ```
836 pub fn trace<U>(url: U) -> Self
837 where
838 U: TryInto<Url>,
839 U::Error: std::fmt::Debug,
840 {
841 Request::new(Method::Trace, url)
842 }
843
844 /// Create a `PATCH` request.
845 ///
846 /// The `PATCH` method is used to apply partial modifications to a resource.
847 ///
848 /// # Examples
849 ///
850 /// ```
851 /// use http_types_rs::{Method, Request};
852 ///
853 /// let mut req = Request::patch("https://example.com");
854 /// assert_eq!(req.method(), Method::Patch);
855 /// ```
856 pub fn patch<U>(url: U) -> Self
857 where
858 U: TryInto<Url>,
859 U::Error: std::fmt::Debug,
860 {
861 Request::new(Method::Patch, url)
862 }
863}
864
865impl Clone for Request {
866 /// Clone the request, resolving the body to `Body::empty()` and removing
867 /// extensions.
868 fn clone(&self) -> Self {
869 Request {
870 method: self.method,
871 url: self.url.clone(),
872 headers: self.headers.clone(),
873 version: self.version,
874 trailers_sender: None,
875 trailers_receiver: None,
876 body: Body::empty(),
877 ext: Extensions::new(),
878 peer_addr: self.peer_addr.clone(),
879 local_addr: self.local_addr.clone(),
880 has_trailers: false,
881 }
882 }
883}
884
885impl AsyncRead for Request {
886 fn poll_read(mut self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut [u8]) -> Poll<io::Result<usize>> {
887 Pin::new(&mut self.body).poll_read(cx, buf)
888 }
889}
890
891impl AsyncBufRead for Request {
892 fn poll_fill_buf(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<&'_ [u8]>> {
893 let this = self.project();
894 this.body.poll_fill_buf(cx)
895 }
896
897 fn consume(mut self: Pin<&mut Self>, amt: usize) {
898 Pin::new(&mut self.body).consume(amt)
899 }
900}
901
902impl AsRef<Headers> for Request {
903 fn as_ref(&self) -> &Headers {
904 &self.headers
905 }
906}
907
908impl AsMut<Headers> for Request {
909 fn as_mut(&mut self) -> &mut Headers {
910 &mut self.headers
911 }
912}
913
914impl From<Request> for Body {
915 fn from(req: Request) -> Body {
916 req.body
917 }
918}
919
920impl Index<HeaderName> for Request {
921 type Output = HeaderValues;
922
923 /// Returns a reference to the value corresponding to the supplied name.
924 ///
925 /// # Panics
926 ///
927 /// Panics if the name is not present in `Request`.
928 #[inline]
929 fn index(&self, name: HeaderName) -> &HeaderValues {
930 self.headers.index(name)
931 }
932}
933
934impl Index<&str> for Request {
935 type Output = HeaderValues;
936
937 /// Returns a reference to the value corresponding to the supplied name.
938 ///
939 /// # Panics
940 ///
941 /// Panics if the name is not present in `Request`.
942 #[inline]
943 fn index(&self, name: &str) -> &HeaderValues {
944 self.headers.index(name)
945 }
946}
947
948impl IntoIterator for Request {
949 type Item = (HeaderName, HeaderValues);
950 type IntoIter = headers::IntoIter;
951
952 /// Returns a iterator of references over the remaining items.
953 #[inline]
954 fn into_iter(self) -> Self::IntoIter {
955 self.headers.into_iter()
956 }
957}
958
959impl<'a> IntoIterator for &'a Request {
960 type Item = (&'a HeaderName, &'a HeaderValues);
961 type IntoIter = headers::Iter<'a>;
962
963 #[inline]
964 fn into_iter(self) -> Self::IntoIter {
965 self.headers.iter()
966 }
967}
968
969impl<'a> IntoIterator for &'a mut Request {
970 type Item = (&'a HeaderName, &'a mut HeaderValues);
971 type IntoIter = headers::IterMut<'a>;
972
973 #[inline]
974 fn into_iter(self) -> Self::IntoIter {
975 self.headers.iter_mut()
976 }
977}
978
979#[cfg(test)]
980mod tests {
981 use super::*;
982 mod host {
983 use super::*;
984
985 #[test]
986 fn when_forwarded_header_is_set() {
987 let mut request = build_test_request();
988 set_forwarded(&mut request, "-");
989 set_x_forwarded_host(&mut request, "this will not be used");
990 assert_eq!(request.forwarded_header_part("host"), Some("host.com"));
991 assert_eq!(request.host(), Some("host.com"));
992 }
993
994 #[test]
995 fn when_several_x_forwarded_hosts_exist() {
996 let mut request = build_test_request();
997 set_x_forwarded_host(&mut request, "expected.host");
998
999 assert_eq!(request.forwarded_header_part("host"), None);
1000 assert_eq!(request.host(), Some("expected.host"));
1001 }
1002
1003 #[test]
1004 fn when_only_one_x_forwarded_hosts_exist() {
1005 let mut request = build_test_request();
1006 request.insert_header("x-forwarded-host", "expected.host").unwrap();
1007 assert_eq!(request.host(), Some("expected.host"));
1008 }
1009
1010 #[test]
1011 fn when_host_header_is_set() {
1012 let mut request = build_test_request();
1013 request.insert_header("host", "host.header").unwrap();
1014 assert_eq!(request.host(), Some("host.header"));
1015 }
1016
1017 #[test]
1018 fn when_there_are_no_headers() {
1019 let request = build_test_request();
1020 assert_eq!(request.host(), Some("async.rs"));
1021 }
1022
1023 #[test]
1024 fn when_url_has_no_domain() {
1025 let mut request = build_test_request();
1026 *request.url_mut() = Url::parse("x:").unwrap();
1027 assert_eq!(request.host(), None);
1028 }
1029
1030 #[test]
1031 fn when_using_shorthand_with_valid_url_to_create_request_get() {
1032 let url = Url::parse("https://example.com").unwrap();
1033 let req = Request::get(url);
1034 assert_eq!(req.method(), Method::Get);
1035 }
1036
1037 #[test]
1038 fn when_using_shorthand_with_valid_url_to_create_request_head() {
1039 let url = Url::parse("https://example.com").unwrap();
1040 let req = Request::head(url);
1041 assert_eq!(req.method(), Method::Head);
1042 }
1043
1044 #[test]
1045 fn when_using_shorthand_with_valid_url_to_create_request_post() {
1046 let url = Url::parse("https://example.com").unwrap();
1047 let req = Request::post(url);
1048 assert_eq!(req.method(), Method::Post);
1049 }
1050
1051 #[test]
1052 fn when_using_shorthand_with_valid_url_to_create_request_put() {
1053 let url = Url::parse("https://example.com").unwrap();
1054 let req = Request::put(url);
1055 assert_eq!(req.method(), Method::Put);
1056 }
1057
1058 #[test]
1059 fn when_using_shorthand_with_valid_url_to_create_request_delete() {
1060 let url = Url::parse("https://example.com").unwrap();
1061 let req = Request::delete(url);
1062 assert_eq!(req.method(), Method::Delete);
1063 }
1064
1065 #[test]
1066 fn when_using_shorthand_with_valid_url_to_create_request_connect() {
1067 let url = Url::parse("https://example.com").unwrap();
1068 let req = Request::connect(url);
1069 assert_eq!(req.method(), Method::Connect);
1070 }
1071
1072 #[test]
1073 fn when_using_shorthand_with_valid_url_to_create_request_options() {
1074 let url = Url::parse("https://example.com").unwrap();
1075 let req = Request::options(url);
1076 assert_eq!(req.method(), Method::Options);
1077 }
1078
1079 #[test]
1080 fn when_using_shorthand_with_valid_url_to_create_request_trace() {
1081 let url = Url::parse("https://example.com").unwrap();
1082 let req = Request::trace(url);
1083 assert_eq!(req.method(), Method::Trace);
1084 }
1085
1086 #[test]
1087 fn when_using_shorthand_with_valid_url_to_create_request_patch() {
1088 let url = Url::parse("https://example.com").unwrap();
1089 let req = Request::patch(url);
1090 assert_eq!(req.method(), Method::Patch);
1091 }
1092 }
1093
1094 mod remote {
1095 use super::*;
1096 #[test]
1097 fn when_forwarded_is_properly_formatted() {
1098 let mut request = build_test_request();
1099 request.set_peer_addr(Some("127.0.0.1:8000"));
1100 set_forwarded(&mut request, "127.0.0.1:8001");
1101
1102 assert_eq!(request.forwarded_for(), Some("127.0.0.1:8001"));
1103 assert_eq!(request.remote(), Some("127.0.0.1:8001"));
1104 }
1105
1106 #[test]
1107 fn when_forwarded_is_improperly_formatted() {
1108 let mut request = build_test_request();
1109 request.set_peer_addr(Some("127.0.0.1:8000".parse::<std::net::SocketAddr>().unwrap()));
1110
1111 request.insert_header("Forwarded", "this is an improperly ;;; formatted header").unwrap();
1112
1113 assert_eq!(request.forwarded_for(), None);
1114 assert_eq!(request.remote(), Some("127.0.0.1:8000"));
1115 }
1116
1117 #[test]
1118 fn when_x_forwarded_for_is_set() {
1119 let mut request = build_test_request();
1120 request.set_peer_addr(Some(std::path::PathBuf::from("/dev/random").to_str().unwrap()));
1121 set_x_forwarded_for(&mut request, "forwarded-host.com");
1122
1123 assert_eq!(request.forwarded_for(), Some("forwarded-host.com"));
1124 assert_eq!(request.remote(), Some("forwarded-host.com"));
1125 }
1126
1127 #[test]
1128 fn when_both_forwarding_headers_are_set() {
1129 let mut request = build_test_request();
1130 set_forwarded(&mut request, "forwarded.com");
1131 set_x_forwarded_for(&mut request, "forwarded-for-client.com");
1132 request.peer_addr = Some("127.0.0.1:8000".into());
1133
1134 assert_eq!(request.forwarded_for(), Some("forwarded.com"));
1135 assert_eq!(request.remote(), Some("forwarded.com"));
1136 }
1137
1138 #[test]
1139 fn falling_back_to_peer_addr() {
1140 let mut request = build_test_request();
1141 request.peer_addr = Some("127.0.0.1:8000".into());
1142
1143 assert_eq!(request.forwarded_for(), None);
1144 assert_eq!(request.remote(), Some("127.0.0.1:8000"));
1145 }
1146
1147 #[test]
1148 fn when_no_remote_available() {
1149 let request = build_test_request();
1150 assert_eq!(request.forwarded_for(), None);
1151 assert_eq!(request.remote(), None);
1152 }
1153 }
1154
1155 fn build_test_request() -> Request {
1156 let url = Url::parse("http://async.rs/").unwrap();
1157 Request::new(Method::Get, url)
1158 }
1159
1160 fn set_x_forwarded_for(request: &mut Request, client: &'static str) {
1161 request
1162 .insert_header("x-forwarded-for", format!("{},proxy.com,other-proxy.com", client))
1163 .unwrap();
1164 }
1165
1166 fn set_x_forwarded_host(request: &mut Request, host: &'static str) {
1167 request
1168 .insert_header("x-forwarded-host", format!("{},proxy.com,other-proxy.com", host))
1169 .unwrap();
1170 }
1171
1172 fn set_forwarded(request: &mut Request, client: &'static str) {
1173 request
1174 .insert_header("Forwarded", format!("by=something.com;for={};host=host.com;proto=http", client))
1175 .unwrap();
1176 }
1177}