1use std::convert::TryFrom;
2use std::fmt;
3use std::time::Duration;
4
5use http::{request::Parts, Request as HttpRequest, Version};
6use serde::Serialize;
7#[cfg(feature = "json")]
8use serde_json;
9use serde_urlencoded;
10
11use super::body::{self, Body};
12#[cfg(feature = "multipart")]
13use super::multipart;
14use super::Client;
15use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
16use crate::{async_impl, Method, Url};
17
18pub struct Request {
20 body: Option<Body>,
21 inner: async_impl::Request,
22}
23
24#[derive(Debug)]
28#[must_use = "RequestBuilder does nothing until you 'send' it"]
29pub struct RequestBuilder {
30 client: Client,
31 request: crate::Result<Request>,
32}
33
34impl Request {
35 #[inline]
37 pub fn new(method: Method, url: Url) -> Self {
38 Request {
39 body: None,
40 inner: async_impl::Request::new(method, url),
41 }
42 }
43
44 #[inline]
46 pub fn method(&self) -> &Method {
47 self.inner.method()
48 }
49
50 #[inline]
52 pub fn method_mut(&mut self) -> &mut Method {
53 self.inner.method_mut()
54 }
55
56 #[inline]
58 pub fn url(&self) -> &Url {
59 self.inner.url()
60 }
61
62 #[inline]
64 pub fn url_mut(&mut self) -> &mut Url {
65 self.inner.url_mut()
66 }
67
68 #[inline]
70 pub fn headers(&self) -> &HeaderMap {
71 self.inner.headers()
72 }
73
74 #[inline]
76 pub fn headers_mut(&mut self) -> &mut HeaderMap {
77 self.inner.headers_mut()
78 }
79
80 #[inline]
82 pub fn version(&self) -> Version {
83 self.inner.version()
84 }
85
86 #[inline]
88 pub fn version_mut(&mut self) -> &mut Version {
89 self.inner.version_mut()
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 fn timeout(&self) -> Option<&Duration> {
107 self.inner.timeout()
108 }
109
110 #[inline]
112 pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
113 self.inner.timeout_mut()
114 }
115
116 pub fn try_clone(&self) -> Option<Request> {
121 let body = if let Some(ref body) = self.body.as_ref() {
122 if let Some(body) = body.try_clone() {
123 Some(body)
124 } else {
125 return None;
126 }
127 } else {
128 None
129 };
130 let mut req = Request::new(self.method().clone(), self.url().clone());
131 *req.headers_mut() = self.headers().clone();
132 *req.version_mut() = self.version().clone();
133 req.body = body;
134 Some(req)
135 }
136
137 pub(crate) fn into_async(self) -> (async_impl::Request, Option<body::Sender>) {
138 use crate::header::CONTENT_LENGTH;
139
140 let mut req_async = self.inner;
141 let body = self.body.and_then(|body| {
142 let (tx, body, len) = body.into_async();
143 if let Some(len) = len {
144 req_async.headers_mut().insert(CONTENT_LENGTH, len.into());
145 }
146 *req_async.body_mut() = Some(body);
147 tx
148 });
149 (req_async, body)
150 }
151}
152
153impl RequestBuilder {
154 pub(crate) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
155 let mut builder = RequestBuilder { client, request };
156
157 let auth = builder
158 .request
159 .as_mut()
160 .ok()
161 .and_then(|req| async_impl::request::extract_authority(req.url_mut()));
162
163 if let Some((username, password)) = auth {
164 builder.basic_auth(username, password)
165 } else {
166 builder
167 }
168 }
169
170 pub fn from_parts(client: Client, request: Request) -> RequestBuilder {
172 RequestBuilder {
173 client,
174 request: crate::Result::Ok(request),
175 }
176 }
177
178 pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
192 where
193 HeaderName: TryFrom<K>,
194 HeaderValue: TryFrom<V>,
195 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
196 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
197 {
198 self.header_sensitive(key, value, false)
199 }
200
201 fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
203 where
204 HeaderName: TryFrom<K>,
205 HeaderValue: TryFrom<V>,
206 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
207 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
208 {
209 let mut error = None;
210 if let Ok(ref mut req) = self.request {
211 match <HeaderName as TryFrom<K>>::try_from(key) {
212 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
213 Ok(mut value) => {
214 value.set_sensitive(sensitive);
215 req.headers_mut().append(key, value);
216 }
217 Err(e) => error = Some(crate::error::builder(e.into())),
218 },
219 Err(e) => error = Some(crate::error::builder(e.into())),
220 };
221 }
222 if let Some(err) = error {
223 self.request = Err(err);
224 }
225 self
226 }
227
228 pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
254 if let Ok(ref mut req) = self.request {
255 crate::util::replace_headers(req.headers_mut(), headers);
256 }
257 self
258 }
259
260 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
272 where
273 U: fmt::Display,
274 P: fmt::Display,
275 {
276 let header_value = crate::util::basic_auth(username, password);
277 self.header_sensitive(crate::header::AUTHORIZATION, header_value, true)
278 }
279
280 pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
292 where
293 T: fmt::Display,
294 {
295 let header_value = format!("Bearer {token}");
296 self.header_sensitive(crate::header::AUTHORIZATION, &*header_value, true)
297 }
298
299 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
343 if let Ok(ref mut req) = self.request {
344 *req.body_mut() = Some(body.into());
345 }
346 self
347 }
348
349 pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
355 if let Ok(ref mut req) = self.request {
356 *req.timeout_mut() = Some(timeout);
357 }
358 self
359 }
360
361 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
392 let mut error = None;
393 if let Ok(ref mut req) = self.request {
394 let url = req.url_mut();
395 let mut pairs = url.query_pairs_mut();
396 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
397
398 if let Err(err) = query.serialize(serializer) {
399 error = Some(crate::error::builder(err));
400 }
401 }
402 if let Ok(ref mut req) = self.request {
403 if let Some("") = req.url().query() {
404 req.url_mut().set_query(None);
405 }
406 }
407 if let Some(err) = error {
408 self.request = Err(err);
409 }
410 self
411 }
412
413 pub fn version(mut self, version: Version) -> RequestBuilder {
415 if let Ok(ref mut req) = self.request {
416 *req.version_mut() = version;
417 }
418 self
419 }
420
421 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
448 let mut error = None;
449 if let Ok(ref mut req) = self.request {
450 match serde_urlencoded::to_string(form) {
451 Ok(body) => {
452 req.headers_mut().insert(
453 CONTENT_TYPE,
454 HeaderValue::from_static("application/x-www-form-urlencoded"),
455 );
456 *req.body_mut() = Some(body.into());
457 }
458 Err(err) => error = Some(crate::error::builder(err)),
459 }
460 }
461 if let Some(err) = error {
462 self.request = Err(err);
463 }
464 self
465 }
466
467 #[cfg(feature = "json")]
499 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
500 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
501 let mut error = None;
502 if let Ok(ref mut req) = self.request {
503 match serde_json::to_vec(json) {
504 Ok(body) => {
505 if !req.headers().contains_key(CONTENT_TYPE) {
506 req.headers_mut()
507 .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
508 }
509 *req.body_mut() = Some(body.into());
510 }
511 Err(err) => error = Some(crate::error::builder(err)),
512 }
513 }
514 if let Some(err) = error {
515 self.request = Err(err);
516 }
517 self
518 }
519
520 #[cfg(feature = "multipart")]
540 #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
541 pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
542 let mut builder = self.header(
543 CONTENT_TYPE,
544 format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
545 );
546 if let Ok(ref mut req) = builder.request {
547 *req.body_mut() = Some(match multipart.compute_length() {
548 Some(length) => Body::sized(multipart.reader(), length),
549 None => Body::new(multipart.reader()),
550 })
551 }
552 builder
553 }
554
555 pub fn build(self) -> crate::Result<Request> {
558 self.request
559 }
560
561 pub fn build_split(self) -> (Client, crate::Result<Request>) {
567 (self.client, self.request)
568 }
569
570 pub fn send(self) -> crate::Result<super::Response> {
577 self.client.execute(self.request?)
578 }
579
580 pub fn try_clone(&self) -> Option<RequestBuilder> {
625 self.request
626 .as_ref()
627 .ok()
628 .and_then(|req| req.try_clone())
629 .map(|req| RequestBuilder {
630 client: self.client.clone(),
631 request: Ok(req),
632 })
633 }
634}
635
636impl<T> TryFrom<HttpRequest<T>> for Request
637where
638 T: Into<Body>,
639{
640 type Error = crate::Error;
641
642 fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
643 let (parts, body) = req.into_parts();
644 let Parts {
645 method,
646 uri,
647 headers,
648 ..
649 } = parts;
650 let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
651 let mut inner = async_impl::Request::new(method, url);
652 crate::util::replace_headers(inner.headers_mut(), headers);
653 Ok(Request {
654 body: Some(body.into()),
655 inner,
656 })
657 }
658}
659
660impl fmt::Debug for Request {
661 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
662 fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
663 }
664}
665
666fn fmt_request_fields<'a, 'b>(
667 f: &'a mut fmt::DebugStruct<'a, 'b>,
668 req: &Request,
669) -> &'a mut fmt::DebugStruct<'a, 'b> {
670 f.field("method", req.method())
671 .field("url", req.url())
672 .field("headers", req.headers())
673}
674
675#[cfg(test)]
676mod tests {
677 use super::super::{body, Client};
678 use super::{HttpRequest, Request, Version};
679 use crate::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, HOST};
680 use crate::Method;
681 use serde::Serialize;
682 #[cfg(feature = "json")]
683 use serde_json;
684 use serde_urlencoded;
685 use std::collections::{BTreeMap, HashMap};
686 use std::convert::TryFrom;
687
688 #[test]
689 fn basic_get_request() {
690 let client = Client::new();
691 let some_url = "https://google.com/";
692 let r = client.get(some_url).build().unwrap();
693
694 assert_eq!(r.method(), &Method::GET);
695 assert_eq!(r.url().as_str(), some_url);
696 }
697
698 #[test]
699 fn basic_head_request() {
700 let client = Client::new();
701 let some_url = "https://google.com/";
702 let r = client.head(some_url).build().unwrap();
703
704 assert_eq!(r.method(), &Method::HEAD);
705 assert_eq!(r.url().as_str(), some_url);
706 }
707
708 #[test]
709 fn basic_post_request() {
710 let client = Client::new();
711 let some_url = "https://google.com/";
712 let r = client.post(some_url).build().unwrap();
713
714 assert_eq!(r.method(), &Method::POST);
715 assert_eq!(r.url().as_str(), some_url);
716 }
717
718 #[test]
719 fn basic_put_request() {
720 let client = Client::new();
721 let some_url = "https://google.com/";
722 let r = client.put(some_url).build().unwrap();
723
724 assert_eq!(r.method(), &Method::PUT);
725 assert_eq!(r.url().as_str(), some_url);
726 }
727
728 #[test]
729 fn basic_patch_request() {
730 let client = Client::new();
731 let some_url = "https://google.com/";
732 let r = client.patch(some_url).build().unwrap();
733
734 assert_eq!(r.method(), &Method::PATCH);
735 assert_eq!(r.url().as_str(), some_url);
736 }
737
738 #[test]
739 fn basic_delete_request() {
740 let client = Client::new();
741 let some_url = "https://google.com/";
742 let r = client.delete(some_url).build().unwrap();
743
744 assert_eq!(r.method(), &Method::DELETE);
745 assert_eq!(r.url().as_str(), some_url);
746 }
747
748 #[test]
749 fn add_header() {
750 let client = Client::new();
751 let some_url = "https://google.com/";
752 let r = client.post(some_url);
753
754 let header = HeaderValue::from_static("google.com");
755
756 let r = r.header(HOST, header.clone()).build().unwrap();
758
759 assert_eq!(r.headers().get(HOST), Some(&header));
761 }
762
763 #[test]
764 fn add_headers() {
765 let client = Client::new();
766 let some_url = "https://google.com/";
767 let r = client.post(some_url);
768
769 let header = HeaderValue::from_static("google.com");
770
771 let mut headers = HeaderMap::new();
772 headers.insert(HOST, header);
773
774 let r = r.headers(headers.clone()).build().unwrap();
776
777 assert_eq!(r.headers(), &headers);
779 }
780
781 #[test]
782 fn add_headers_multi() {
783 let client = Client::new();
784 let some_url = "https://google.com/";
785 let r = client.post(some_url);
786
787 let header_json = HeaderValue::from_static("application/json");
788 let header_xml = HeaderValue::from_static("application/xml");
789
790 let mut headers = HeaderMap::new();
791 headers.append(ACCEPT, header_json);
792 headers.append(ACCEPT, header_xml);
793
794 let r = r.headers(headers.clone()).build().unwrap();
796
797 assert_eq!(r.headers(), &headers);
799 let mut all_values = r.headers().get_all(ACCEPT).iter();
800 assert_eq!(all_values.next().unwrap(), &"application/json");
801 assert_eq!(all_values.next().unwrap(), &"application/xml");
802 assert_eq!(all_values.next(), None);
803 }
804
805 #[test]
806 fn add_body() {
807 let client = Client::new();
808 let some_url = "https://google.com/";
809 let r = client.post(some_url);
810
811 let body = "Some interesting content";
812
813 let mut r = r.body(body).build().unwrap();
814
815 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
816
817 assert_eq!(buf, body);
818 }
819
820 #[test]
821 fn add_query_append() {
822 let client = Client::new();
823 let some_url = "https://google.com/";
824 let mut r = client.get(some_url);
825
826 r = r.query(&[("foo", "bar")]);
827 r = r.query(&[("qux", 3)]);
828
829 let req = r.build().expect("request is valid");
830 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
831 }
832
833 #[test]
834 fn add_query_append_same() {
835 let client = Client::new();
836 let some_url = "https://google.com/";
837 let mut r = client.get(some_url);
838
839 r = r.query(&[("foo", "a"), ("foo", "b")]);
840
841 let req = r.build().expect("request is valid");
842 assert_eq!(req.url().query(), Some("foo=a&foo=b"));
843 }
844
845 #[test]
846 fn add_query_struct() {
847 #[derive(Serialize)]
848 struct Params {
849 foo: String,
850 qux: i32,
851 }
852
853 let client = Client::new();
854 let some_url = "https://google.com/";
855 let mut r = client.get(some_url);
856
857 let params = Params {
858 foo: "bar".into(),
859 qux: 3,
860 };
861
862 r = r.query(¶ms);
863
864 let req = r.build().expect("request is valid");
865 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
866 }
867
868 #[test]
869 fn add_query_map() {
870 let mut params = BTreeMap::new();
871 params.insert("foo", "bar");
872 params.insert("qux", "three");
873
874 let client = Client::new();
875 let some_url = "https://google.com/";
876 let mut r = client.get(some_url);
877
878 r = r.query(¶ms);
879
880 let req = r.build().expect("request is valid");
881 assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
882 }
883
884 #[test]
885 fn add_form() {
886 let client = Client::new();
887 let some_url = "https://google.com/";
888 let r = client.post(some_url);
889
890 let mut form_data = HashMap::new();
891 form_data.insert("foo", "bar");
892
893 let mut r = r.form(&form_data).build().unwrap();
894
895 assert_eq!(
897 r.headers().get(CONTENT_TYPE).unwrap(),
898 &"application/x-www-form-urlencoded"
899 );
900
901 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
902
903 let body_should_be = serde_urlencoded::to_string(&form_data).unwrap();
904 assert_eq!(buf, body_should_be);
905 }
906
907 #[test]
908 #[cfg(feature = "json")]
909 fn add_json() {
910 let client = Client::new();
911 let some_url = "https://google.com/";
912 let r = client.post(some_url);
913
914 let mut json_data = HashMap::new();
915 json_data.insert("foo", "bar");
916
917 let mut r = r.json(&json_data).build().unwrap();
918
919 assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/json");
921
922 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
923
924 let body_should_be = serde_json::to_string(&json_data).unwrap();
925 assert_eq!(buf, body_should_be);
926 }
927
928 #[test]
929 #[cfg(feature = "json")]
930 fn add_json_fail() {
931 use serde::ser::Error as _;
932 use serde::{Serialize, Serializer};
933 use std::error::Error as _;
934 struct MyStruct;
935 impl Serialize for MyStruct {
936 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
937 where
938 S: Serializer,
939 {
940 Err(S::Error::custom("nope"))
941 }
942 }
943
944 let client = Client::new();
945 let some_url = "https://google.com/";
946 let r = client.post(some_url);
947 let json_data = MyStruct;
948 let err = r.json(&json_data).build().unwrap_err();
949 assert!(err.is_builder()); assert!(err.source().unwrap().is::<serde_json::Error>());
951 }
952
953 #[test]
954 fn test_replace_headers() {
955 use http::HeaderMap;
956
957 let mut headers = HeaderMap::new();
958 headers.insert("foo", "bar".parse().unwrap());
959 headers.append("foo", "baz".parse().unwrap());
960
961 let client = Client::new();
962 let req = client
963 .get("https://hyper.rs")
964 .header("im-a", "keeper")
965 .header("foo", "pop me")
966 .headers(headers)
967 .build()
968 .expect("request build");
969
970 assert_eq!(req.headers()["im-a"], "keeper");
971
972 let foo = req.headers().get_all("foo").iter().collect::<Vec<_>>();
973 assert_eq!(foo.len(), 2);
974 assert_eq!(foo[0], "bar");
975 assert_eq!(foo[1], "baz");
976 }
977
978 #[test]
979 fn normalize_empty_query() {
980 let client = Client::new();
981 let some_url = "https://google.com/";
982 let empty_query: &[(&str, &str)] = &[];
983
984 let req = client
985 .get(some_url)
986 .query(empty_query)
987 .build()
988 .expect("request build");
989
990 assert_eq!(req.url().query(), None);
991 assert_eq!(req.url().as_str(), "https://google.com/");
992 }
993
994 #[test]
995 fn convert_url_authority_into_basic_auth() {
996 let client = Client::new();
997 let some_url = "https://Aladdin:open sesame@localhost/";
998
999 let req = client.get(some_url).build().expect("request build");
1000
1001 assert_eq!(req.url().as_str(), "https://localhost/");
1002 assert_eq!(
1003 req.headers()["authorization"],
1004 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
1005 );
1006 }
1007
1008 #[test]
1009 fn convert_from_http_request() {
1010 let http_request = HttpRequest::builder()
1011 .method("GET")
1012 .uri("http://localhost/")
1013 .header("User-Agent", "my-awesome-agent/1.0")
1014 .body("test test test")
1015 .unwrap();
1016 let req: Request = Request::try_from(http_request).unwrap();
1017 assert_eq!(req.body().is_none(), false);
1018 let test_data = b"test test test";
1019 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
1020 let headers = req.headers();
1021 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
1022 assert_eq!(req.method(), Method::GET);
1023 assert_eq!(req.url().as_str(), "http://localhost/");
1024 }
1025
1026 #[test]
1027 fn set_http_request_version() {
1028 let http_request = HttpRequest::builder()
1029 .method("GET")
1030 .uri("http://localhost/")
1031 .header("User-Agent", "my-awesome-agent/1.0")
1032 .version(Version::HTTP_11)
1033 .body("test test test")
1034 .unwrap();
1035 let req: Request = Request::try_from(http_request).unwrap();
1036 assert_eq!(req.body().is_none(), false);
1037 let test_data = b"test test test";
1038 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
1039 let headers = req.headers();
1040 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
1041 assert_eq!(req.method(), Method::GET);
1042 assert_eq!(req.url().as_str(), "http://localhost/");
1043 assert_eq!(req.version(), Version::HTTP_11);
1044 }
1045
1046 #[test]
1047 fn test_basic_auth_sensitive_header() {
1048 let client = Client::new();
1049 let some_url = "https://localhost/";
1050
1051 let req = client
1052 .get(some_url)
1053 .basic_auth("Aladdin", Some("open sesame"))
1054 .build()
1055 .expect("request build");
1056
1057 assert_eq!(req.url().as_str(), "https://localhost/");
1058 assert_eq!(
1059 req.headers()["authorization"],
1060 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
1061 );
1062 assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1063 }
1064
1065 #[test]
1066 fn test_bearer_auth_sensitive_header() {
1067 let client = Client::new();
1068 let some_url = "https://localhost/";
1069
1070 let req = client
1071 .get(some_url)
1072 .bearer_auth("Hold my bear")
1073 .build()
1074 .expect("request build");
1075
1076 assert_eq!(req.url().as_str(), "https://localhost/");
1077 assert_eq!(req.headers()["authorization"], "Bearer Hold my bear");
1078 assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1079 }
1080}