1use std::convert::TryFrom;
2use std::fmt;
3use std::future::Future;
4use std::time::Duration;
5
6#[cfg(any(feature = "query", feature = "form", feature = "json"))]
7use serde::Serialize;
8
9use super::body::Body;
10use super::client::{Client, Pending};
11#[cfg(feature = "multipart")]
12use super::multipart;
13use super::response::Response;
14use crate::config::{ReadTimeout, RequestConfig, TotalTimeout};
15#[cfg(feature = "multipart")]
16use crate::header::CONTENT_LENGTH;
17#[cfg(any(feature = "multipart", feature = "form", feature = "json"))]
18use crate::header::CONTENT_TYPE;
19use crate::header::{HeaderMap, HeaderName, HeaderValue};
20use crate::{Method, Url};
21use http::{request::Parts, Extensions, Request as HttpRequest, Version};
22
23pub struct Request {
25 method: Method,
26 url: Url,
27 headers: HeaderMap,
28 body: Option<Body>,
29 version: Version,
30 extensions: Extensions,
31}
32
33#[must_use = "RequestBuilder does nothing until you 'send' it"]
37pub struct RequestBuilder {
38 client: Client,
39 request: crate::Result<Request>,
40}
41
42impl Request {
43 #[inline]
45 pub fn new(method: Method, url: Url) -> Self {
46 Request {
47 method,
48 url,
49 headers: HeaderMap::new(),
50 body: None,
51 version: Version::default(),
52 extensions: Extensions::new(),
53 }
54 }
55
56 #[inline]
58 pub fn method(&self) -> &Method {
59 &self.method
60 }
61
62 #[inline]
64 pub fn method_mut(&mut self) -> &mut Method {
65 &mut self.method
66 }
67
68 #[inline]
70 pub fn url(&self) -> &Url {
71 &self.url
72 }
73
74 #[inline]
76 pub fn url_mut(&mut self) -> &mut Url {
77 &mut self.url
78 }
79
80 #[inline]
82 pub fn headers(&self) -> &HeaderMap {
83 &self.headers
84 }
85
86 #[inline]
88 pub fn headers_mut(&mut self) -> &mut HeaderMap {
89 &mut self.headers
90 }
91
92 #[inline]
94 pub fn body(&self) -> Option<&Body> {
95 self.body.as_ref()
96 }
97
98 #[inline]
100 pub fn body_mut(&mut self) -> &mut Option<Body> {
101 &mut self.body
102 }
103
104 #[inline]
106 pub(crate) fn extensions(&self) -> &Extensions {
107 &self.extensions
108 }
109
110 #[inline]
112 pub(crate) fn extensions_mut(&mut self) -> &mut Extensions {
113 &mut self.extensions
114 }
115
116 #[inline]
118 pub fn timeout(&self) -> Option<&Duration> {
119 RequestConfig::<TotalTimeout>::get(&self.extensions)
120 }
121
122 #[inline]
124 pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
125 RequestConfig::<TotalTimeout>::get_mut(&mut self.extensions)
126 }
127
128 #[inline]
130 pub fn read_timeout(&self) -> Option<&Duration> {
131 RequestConfig::<ReadTimeout>::get(&self.extensions)
132 }
133
134 #[inline]
136 pub fn read_timeout_mut(&mut self) -> &mut Option<Duration> {
137 RequestConfig::<ReadTimeout>::get_mut(&mut self.extensions)
138 }
139
140 #[inline]
142 pub fn version(&self) -> Version {
143 self.version
144 }
145
146 #[inline]
148 pub fn version_mut(&mut self) -> &mut Version {
149 &mut self.version
150 }
151
152 pub fn try_clone(&self) -> Option<Request> {
156 let body = match self.body.as_ref() {
157 Some(body) => Some(body.try_clone()?),
158 None => None,
159 };
160 let mut req = Request::new(self.method().clone(), self.url().clone());
161 *req.timeout_mut() = self.timeout().copied();
162 *req.headers_mut() = self.headers().clone();
163 *req.version_mut() = self.version();
164 *req.extensions_mut() = self.extensions().clone();
165 req.body = body;
166 Some(req)
167 }
168
169 pub(super) fn pieces(self) -> (Method, Url, HeaderMap, Option<Body>, Version, Extensions) {
170 (
171 self.method,
172 self.url,
173 self.headers,
174 self.body,
175 self.version,
176 self.extensions,
177 )
178 }
179}
180
181impl RequestBuilder {
182 pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
183 let mut builder = RequestBuilder { client, request };
184
185 let auth = builder
186 .request
187 .as_mut()
188 .ok()
189 .and_then(|req| extract_authority(&mut req.url));
190
191 if let Some((username, password)) = auth {
192 builder.basic_auth(username, password)
193 } else {
194 builder
195 }
196 }
197
198 pub fn from_parts(client: Client, request: Request) -> RequestBuilder {
200 RequestBuilder {
201 client,
202 request: crate::Result::Ok(request),
203 }
204 }
205
206 pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
208 where
209 HeaderName: TryFrom<K>,
210 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
211 HeaderValue: TryFrom<V>,
212 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
213 {
214 self.header_sensitive(key, value, false)
215 }
216
217 fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
219 where
220 HeaderName: TryFrom<K>,
221 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
222 HeaderValue: TryFrom<V>,
223 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
224 {
225 let mut error = None;
226 if let Ok(ref mut req) = self.request {
227 match <HeaderName as TryFrom<K>>::try_from(key) {
228 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
229 Ok(mut value) => {
230 if sensitive {
234 value.set_sensitive(true);
235 }
236 req.headers_mut().append(key, value);
237 }
238 Err(e) => error = Some(crate::error::builder(e.into())),
239 },
240 Err(e) => error = Some(crate::error::builder(e.into())),
241 };
242 }
243 if let Some(err) = error {
244 self.request = Err(err);
245 }
246 self
247 }
248
249 pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
253 if let Ok(ref mut req) = self.request {
254 crate::util::replace_headers(req.headers_mut(), headers);
255 }
256 self
257 }
258
259 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
274 where
275 U: fmt::Display,
276 P: fmt::Display,
277 {
278 let header_value = crate::util::basic_auth(username, password);
279 self.header_sensitive(crate::header::AUTHORIZATION, header_value, true)
280 }
281
282 pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
284 where
285 T: fmt::Display,
286 {
287 let header_value = format!("Bearer {token}");
288 self.header_sensitive(crate::header::AUTHORIZATION, header_value, true)
289 }
290
291 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
293 if let Ok(ref mut req) = self.request {
294 *req.body_mut() = Some(body.into());
295 }
296 self
297 }
298
299 pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
305 if let Ok(ref mut req) = self.request {
306 *req.timeout_mut() = Some(timeout);
307 }
308 self
309 }
310
311 pub fn read_timeout(mut self, timeout: Duration) -> RequestBuilder {
318 if let Ok(ref mut req) = self.request {
319 *req.read_timeout_mut() = Some(timeout);
320 }
321 self
322 }
323
324 #[cfg(feature = "multipart")]
347 #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
348 pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
349 let mut builder = self.header(
350 CONTENT_TYPE,
351 format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
352 );
353
354 builder = match multipart.compute_length() {
355 Some(length) => builder.header(CONTENT_LENGTH, length),
356 None => builder,
357 };
358
359 if let Ok(ref mut req) = builder.request {
360 *req.body_mut() = Some(multipart.stream())
361 }
362 builder
363 }
364
365 #[cfg(feature = "query")]
388 #[cfg_attr(docsrs, doc(cfg(feature = "query")))]
389 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
390 let mut error = None;
391 if let Ok(ref mut req) = self.request {
392 let url = req.url_mut();
393 let mut pairs = url.query_pairs_mut();
394 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
395
396 if let Err(err) = query.serialize(serializer) {
397 error = Some(crate::error::builder(err));
398 }
399 }
400 if let Ok(ref mut req) = self.request {
401 if let Some("") = req.url().query() {
402 req.url_mut().set_query(None);
403 }
404 }
405 if let Some(err) = error {
406 self.request = Err(err);
407 }
408 self
409 }
410
411 pub fn version(mut self, version: Version) -> RequestBuilder {
413 if let Ok(ref mut req) = self.request {
414 req.version = version;
415 }
416 self
417 }
418
419 #[cfg(feature = "form")]
451 #[cfg_attr(docsrs, doc(cfg(feature = "form")))]
452 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
453 let mut error = None;
454 if let Ok(ref mut req) = self.request {
455 match serde_urlencoded::to_string(form) {
456 Ok(body) => {
457 req.headers_mut()
458 .entry(CONTENT_TYPE)
459 .or_insert(HeaderValue::from_static(
460 "application/x-www-form-urlencoded",
461 ));
462 *req.body_mut() = Some(body.into());
463 }
464 Err(err) => error = Some(crate::error::builder(err)),
465 }
466 }
467 if let Some(err) = error {
468 self.request = Err(err);
469 }
470 self
471 }
472
473 #[cfg(feature = "json")]
484 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
485 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
486 let mut error = None;
487 if let Ok(ref mut req) = self.request {
488 match serde_json::to_vec(json) {
489 Ok(body) => {
490 req.headers_mut()
491 .entry(CONTENT_TYPE)
492 .or_insert_with(|| HeaderValue::from_static("application/json"));
493 *req.body_mut() = Some(body.into());
494 }
495 Err(err) => error = Some(crate::error::builder(err)),
496 }
497 }
498 if let Some(err) = error {
499 self.request = Err(err);
500 }
501 self
502 }
503
504 pub fn build(self) -> crate::Result<Request> {
507 self.request
508 }
509
510 pub fn build_split(self) -> (Client, crate::Result<Request>) {
516 (self.client, self.request)
517 }
518
519 pub fn send(self) -> impl Future<Output = Result<Response, crate::Error>> {
541 match self.request {
542 Ok(req) => self.client.execute_request(req),
543 Err(err) => Pending::new_err(err),
544 }
545 }
546
547 pub fn try_clone(&self) -> Option<RequestBuilder> {
567 self.request
568 .as_ref()
569 .ok()
570 .and_then(|req| req.try_clone())
571 .map(|req| RequestBuilder {
572 client: self.client.clone(),
573 request: Ok(req),
574 })
575 }
576}
577
578impl fmt::Debug for Request {
579 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
580 fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
581 }
582}
583
584impl fmt::Debug for RequestBuilder {
585 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
586 let mut builder = f.debug_struct("RequestBuilder");
587 match self.request {
588 Ok(ref req) => fmt_request_fields(&mut builder, req).finish(),
589 Err(ref err) => builder.field("error", err).finish(),
590 }
591 }
592}
593
594fn fmt_request_fields<'a, 'b>(
595 f: &'a mut fmt::DebugStruct<'a, 'b>,
596 req: &Request,
597) -> &'a mut fmt::DebugStruct<'a, 'b> {
598 f.field("method", &req.method)
599 .field("url", &req.url)
600 .field("headers", &req.headers)
601}
602
603pub(crate) fn extract_authority(url: &mut Url) -> Option<(String, Option<String>)> {
606 use percent_encoding::percent_decode;
607
608 if url.has_authority() {
609 let username: String = percent_decode(url.username().as_bytes())
610 .decode_utf8()
611 .ok()?
612 .into();
613 let password = url.password().and_then(|pass| {
614 percent_decode(pass.as_bytes())
615 .decode_utf8()
616 .ok()
617 .map(String::from)
618 });
619 if !username.is_empty() || password.is_some() {
620 url.set_username("")
621 .expect("has_authority means set_username shouldn't fail");
622 url.set_password(None)
623 .expect("has_authority means set_password shouldn't fail");
624 return Some((username, password));
625 }
626 }
627
628 None
629}
630
631impl<T> TryFrom<HttpRequest<T>> for Request
632where
633 T: Into<Body>,
634{
635 type Error = crate::Error;
636
637 fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
638 let (parts, body) = req.into_parts();
639 let Parts {
640 method,
641 uri,
642 headers,
643 version,
644 extensions,
645 ..
646 } = parts;
647 let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
648 Ok(Request {
649 method,
650 url,
651 headers,
652 body: Some(body.into()),
653 version,
654 extensions,
655 })
656 }
657}
658
659impl TryFrom<Request> for HttpRequest<Body> {
660 type Error = crate::Error;
661
662 fn try_from(req: Request) -> crate::Result<Self> {
663 let Request {
664 method,
665 url,
666 headers,
667 body,
668 version,
669 extensions,
670 ..
671 } = req;
672
673 let mut req = HttpRequest::builder()
674 .version(version)
675 .method(method)
676 .uri(url.as_str())
677 .body(body.unwrap_or_else(Body::empty))
678 .map_err(crate::error::builder)?;
679
680 *req.headers_mut() = headers;
681 *req.extensions_mut() = extensions;
682 Ok(req)
683 }
684}
685
686#[cfg(test)]
687#[cfg(not(feature = "rustls-no-provider"))]
688mod tests {
689
690 use super::*;
691 #[cfg(feature = "query")]
692 use std::collections::BTreeMap;
693
694 #[test]
695 #[cfg(feature = "query")]
696 fn add_query_append() {
697 let client = Client::new();
698 let some_url = "https://www.google.com/";
699 let r = client.get(some_url);
700
701 let r = r.query(&[("foo", "bar")]);
702 let r = r.query(&[("qux", 3)]);
703
704 let req = r.build().expect("request is valid");
705 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
706 }
707
708 #[test]
709 #[cfg(feature = "query")]
710 fn add_query_append_same() {
711 let client = Client::new();
712 let some_url = "https://www.google.com/";
713 let r = client.get(some_url);
714
715 let r = r.query(&[("foo", "a"), ("foo", "b")]);
716
717 let req = r.build().expect("request is valid");
718 assert_eq!(req.url().query(), Some("foo=a&foo=b"));
719 }
720
721 #[test]
722 #[cfg(feature = "query")]
723 fn add_query_struct() {
724 #[derive(Serialize)]
725 struct Params {
726 foo: String,
727 qux: i32,
728 }
729
730 let client = Client::new();
731 let some_url = "https://www.google.com/";
732 let r = client.get(some_url);
733
734 let params = Params {
735 foo: "bar".into(),
736 qux: 3,
737 };
738
739 let r = r.query(¶ms);
740
741 let req = r.build().expect("request is valid");
742 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
743 }
744
745 #[test]
746 #[cfg(feature = "query")]
747 fn add_query_map() {
748 let mut params = BTreeMap::new();
749 params.insert("foo", "bar");
750 params.insert("qux", "three");
751
752 let client = Client::new();
753 let some_url = "https://www.google.com/";
754 let r = client.get(some_url);
755
756 let r = r.query(¶ms);
757
758 let req = r.build().expect("request is valid");
759 assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
760 }
761
762 #[test]
763 fn test_replace_headers() {
764 use http::HeaderMap;
765
766 let mut headers = HeaderMap::new();
767 headers.insert("foo", "bar".parse().unwrap());
768 headers.append("foo", "baz".parse().unwrap());
769
770 let client = Client::new();
771 let req = client
772 .get("https://hyper.rs")
773 .header("im-a", "keeper")
774 .header("foo", "pop me")
775 .headers(headers)
776 .build()
777 .expect("request build");
778
779 assert_eq!(req.headers()["im-a"], "keeper");
780
781 let foo = req.headers().get_all("foo").iter().collect::<Vec<_>>();
782 assert_eq!(foo.len(), 2);
783 assert_eq!(foo[0], "bar");
784 assert_eq!(foo[1], "baz");
785 }
786
787 #[test]
788 #[cfg(feature = "query")]
789 fn normalize_empty_query() {
790 let client = Client::new();
791 let some_url = "https://www.google.com/";
792 let empty_query: &[(&str, &str)] = &[];
793
794 let req = client
795 .get(some_url)
796 .query(empty_query)
797 .build()
798 .expect("request build");
799
800 assert_eq!(req.url().query(), None);
801 assert_eq!(req.url().as_str(), "https://www.google.com/");
802 }
803
804 #[test]
805 fn try_clone_reusable() {
806 let client = Client::new();
807 let builder = client
808 .post("http://httpbin.org/post")
809 .header("foo", "bar")
810 .body("from a &str!");
811 let req = builder
812 .try_clone()
813 .expect("clone successful")
814 .build()
815 .expect("request is valid");
816 assert_eq!(req.url().as_str(), "http://httpbin.org/post");
817 assert_eq!(req.method(), Method::POST);
818 assert_eq!(req.headers()["foo"], "bar");
819 }
820
821 #[test]
822 fn try_clone_no_body() {
823 let client = Client::new();
824 let builder = client.get("http://httpbin.org/get");
825 let req = builder
826 .try_clone()
827 .expect("clone successful")
828 .build()
829 .expect("request is valid");
830 assert_eq!(req.url().as_str(), "http://httpbin.org/get");
831 assert_eq!(req.method(), Method::GET);
832 assert!(req.body().is_none());
833 }
834
835 #[test]
836 #[cfg(feature = "stream")]
837 fn try_clone_stream() {
838 let chunks: Vec<Result<_, ::std::io::Error>> = vec![Ok("hello"), Ok(" "), Ok("world")];
839 let stream = futures_util::stream::iter(chunks);
840 let client = Client::new();
841 let builder = client
842 .get("http://httpbin.org/get")
843 .body(super::Body::wrap_stream(stream));
844 let clone = builder.try_clone();
845 assert!(clone.is_none());
846 }
847
848 #[test]
849 fn convert_url_authority_into_basic_auth() {
850 let client = Client::new();
851 let some_url = "https://Aladdin:open sesame@localhost/";
852
853 let req = client.get(some_url).build().expect("request build");
854
855 assert_eq!(req.url().as_str(), "https://localhost/");
856 assert_eq!(
857 req.headers()["authorization"],
858 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
859 );
860 }
861
862 #[test]
863 fn test_basic_auth_sensitive_header() {
864 let client = Client::new();
865 let some_url = "https://localhost/";
866
867 let req = client
868 .get(some_url)
869 .basic_auth("Aladdin", Some("open sesame"))
870 .build()
871 .expect("request build");
872
873 assert_eq!(req.url().as_str(), "https://localhost/");
874 assert_eq!(
875 req.headers()["authorization"],
876 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
877 );
878 assert!(req.headers()["authorization"].is_sensitive());
879 }
880
881 #[test]
882 fn test_bearer_auth_sensitive_header() {
883 let client = Client::new();
884 let some_url = "https://localhost/";
885
886 let req = client
887 .get(some_url)
888 .bearer_auth("Hold my bear")
889 .build()
890 .expect("request build");
891
892 assert_eq!(req.url().as_str(), "https://localhost/");
893 assert_eq!(req.headers()["authorization"], "Bearer Hold my bear");
894 assert!(req.headers()["authorization"].is_sensitive());
895 }
896
897 #[test]
898 fn test_explicit_sensitive_header() {
899 let client = Client::new();
900 let some_url = "https://localhost/";
901
902 let mut header = http::HeaderValue::from_static("in plain sight");
903 header.set_sensitive(true);
904
905 let req = client
906 .get(some_url)
907 .header("hiding", header)
908 .build()
909 .expect("request build");
910
911 assert_eq!(req.url().as_str(), "https://localhost/");
912 assert_eq!(req.headers()["hiding"], "in plain sight");
913 assert!(req.headers()["hiding"].is_sensitive());
914 }
915
916 #[test]
917 fn convert_from_http_request() {
918 let http_request = HttpRequest::builder()
919 .method("GET")
920 .uri("http://localhost/")
921 .header("User-Agent", "my-awesome-agent/1.0")
922 .body("test test test")
923 .unwrap();
924 let req: Request = Request::try_from(http_request).unwrap();
925 assert!(req.body().is_some());
926 let test_data = b"test test test";
927 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
928 let headers = req.headers();
929 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
930 assert_eq!(req.method(), Method::GET);
931 assert_eq!(req.url().as_str(), "http://localhost/");
932 }
933
934 #[test]
935 fn set_http_request_version() {
936 let http_request = HttpRequest::builder()
937 .method("GET")
938 .uri("http://localhost/")
939 .header("User-Agent", "my-awesome-agent/1.0")
940 .version(Version::HTTP_11)
941 .body("test test test")
942 .unwrap();
943 let req: Request = Request::try_from(http_request).unwrap();
944 assert!(req.body().is_some());
945 let test_data = b"test test test";
946 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
947 let headers = req.headers();
948 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
949 assert_eq!(req.method(), Method::GET);
950 assert_eq!(req.url().as_str(), "http://localhost/");
951 assert_eq!(req.version(), Version::HTTP_11);
952 }
953
954 #[test]
955 fn builder_split_reassemble() {
956 let builder = {
957 let client = Client::new();
958 client.get("http://example.com")
959 };
960 let (client, inner) = builder.build_split();
961 let request = inner.unwrap();
962 let builder = RequestBuilder::from_parts(client, request);
963 builder.build().unwrap();
964 }
965
966 }