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.timeout_mut() = self.timeout().copied();
132 *req.headers_mut() = self.headers().clone();
133 *req.version_mut() = self.version().clone();
134 req.body = body;
135 Some(req)
136 }
137
138 pub(crate) fn into_async(self) -> (async_impl::Request, Option<body::Sender>) {
139 use crate::header::CONTENT_LENGTH;
140
141 let mut req_async = self.inner;
142 let body = self.body.and_then(|body| {
143 let (tx, body, len) = body.into_async();
144 if let Some(len) = len {
145 req_async.headers_mut().insert(CONTENT_LENGTH, len.into());
146 }
147 *req_async.body_mut() = Some(body);
148 tx
149 });
150 (req_async, body)
151 }
152}
153
154impl RequestBuilder {
155 pub(crate) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
156 let mut builder = RequestBuilder { client, request };
157
158 let auth = builder
159 .request
160 .as_mut()
161 .ok()
162 .and_then(|req| async_impl::request::extract_authority(req.url_mut()));
163
164 if let Some((username, password)) = auth {
165 builder.basic_auth(username, password)
166 } else {
167 builder
168 }
169 }
170
171 pub fn from_parts(client: Client, request: Request) -> RequestBuilder {
173 RequestBuilder {
174 client,
175 request: crate::Result::Ok(request),
176 }
177 }
178
179 pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
193 where
194 HeaderName: TryFrom<K>,
195 HeaderValue: TryFrom<V>,
196 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
197 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
198 {
199 self.header_sensitive(key, value, false)
200 }
201
202 fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
204 where
205 HeaderName: TryFrom<K>,
206 HeaderValue: TryFrom<V>,
207 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
208 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
209 {
210 let mut error = None;
211 if let Ok(ref mut req) = self.request {
212 match <HeaderName as TryFrom<K>>::try_from(key) {
213 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
214 Ok(mut value) => {
215 if sensitive {
219 value.set_sensitive(true);
220 }
221 req.headers_mut().append(key, value);
222 }
223 Err(e) => error = Some(crate::error::builder(e.into())),
224 },
225 Err(e) => error = Some(crate::error::builder(e.into())),
226 };
227 }
228 if let Some(err) = error {
229 self.request = Err(err);
230 }
231 self
232 }
233
234 pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
260 if let Ok(ref mut req) = self.request {
261 crate::util::replace_headers(req.headers_mut(), headers);
262 }
263 self
264 }
265
266 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
278 where
279 U: fmt::Display,
280 P: fmt::Display,
281 {
282 let header_value = crate::util::basic_auth(username, password);
283 self.header_sensitive(crate::header::AUTHORIZATION, header_value, true)
284 }
285
286 pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
298 where
299 T: fmt::Display,
300 {
301 let header_value = format!("Bearer {token}");
302 self.header_sensitive(crate::header::AUTHORIZATION, &*header_value, true)
303 }
304
305 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
349 if let Ok(ref mut req) = self.request {
350 *req.body_mut() = Some(body.into());
351 }
352 self
353 }
354
355 pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
361 if let Ok(ref mut req) = self.request {
362 *req.timeout_mut() = Some(timeout);
363 }
364 self
365 }
366
367 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
398 let mut error = None;
399 if let Ok(ref mut req) = self.request {
400 let url = req.url_mut();
401 let mut pairs = url.query_pairs_mut();
402 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
403
404 if let Err(err) = query.serialize(serializer) {
405 error = Some(crate::error::builder(err));
406 }
407 }
408 if let Ok(ref mut req) = self.request {
409 if let Some("") = req.url().query() {
410 req.url_mut().set_query(None);
411 }
412 }
413 if let Some(err) = error {
414 self.request = Err(err);
415 }
416 self
417 }
418
419 pub fn version(mut self, version: Version) -> RequestBuilder {
421 if let Ok(ref mut req) = self.request {
422 *req.version_mut() = version;
423 }
424 self
425 }
426
427 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
454 let mut error = None;
455 if let Ok(ref mut req) = self.request {
456 match serde_urlencoded::to_string(form) {
457 Ok(body) => {
458 req.headers_mut()
459 .entry(CONTENT_TYPE)
460 .or_insert(HeaderValue::from_static(
461 "application/x-www-form-urlencoded",
462 ));
463 *req.body_mut() = Some(body.into());
464 }
465 Err(err) => error = Some(crate::error::builder(err)),
466 }
467 }
468 if let Some(err) = error {
469 self.request = Err(err);
470 }
471 self
472 }
473
474 #[cfg(feature = "json")]
506 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
507 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
508 let mut error = None;
509 if let Ok(ref mut req) = self.request {
510 match serde_json::to_vec(json) {
511 Ok(body) => {
512 if !req.headers().contains_key(CONTENT_TYPE) {
513 req.headers_mut()
514 .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
515 }
516 *req.body_mut() = Some(body.into());
517 }
518 Err(err) => error = Some(crate::error::builder(err)),
519 }
520 }
521 if let Some(err) = error {
522 self.request = Err(err);
523 }
524 self
525 }
526
527 #[cfg(feature = "multipart")]
547 #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
548 pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
549 let mut builder = self.header(
550 CONTENT_TYPE,
551 format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
552 );
553 if let Ok(ref mut req) = builder.request {
554 *req.body_mut() = Some(match multipart.compute_length() {
555 Some(length) => Body::sized(multipart.reader(), length),
556 None => Body::new(multipart.reader()),
557 })
558 }
559 builder
560 }
561
562 pub fn build(self) -> crate::Result<Request> {
565 self.request
566 }
567
568 pub fn build_split(self) -> (Client, crate::Result<Request>) {
574 (self.client, self.request)
575 }
576
577 pub fn send(self) -> crate::Result<super::Response> {
584 self.client.execute(self.request?)
585 }
586
587 pub fn try_clone(&self) -> Option<RequestBuilder> {
632 self.request
633 .as_ref()
634 .ok()
635 .and_then(|req| req.try_clone())
636 .map(|req| RequestBuilder {
637 client: self.client.clone(),
638 request: Ok(req),
639 })
640 }
641}
642
643impl<T> TryFrom<HttpRequest<T>> for Request
644where
645 T: Into<Body>,
646{
647 type Error = crate::Error;
648
649 fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
650 let (parts, body) = req.into_parts();
651 let Parts {
652 method,
653 uri,
654 headers,
655 ..
656 } = parts;
657 let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
658 let mut inner = async_impl::Request::new(method, url);
659 crate::util::replace_headers(inner.headers_mut(), headers);
660 Ok(Request {
661 body: Some(body.into()),
662 inner,
663 })
664 }
665}
666
667impl fmt::Debug for Request {
668 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
669 fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
670 }
671}
672
673fn fmt_request_fields<'a, 'b>(
674 f: &'a mut fmt::DebugStruct<'a, 'b>,
675 req: &Request,
676) -> &'a mut fmt::DebugStruct<'a, 'b> {
677 f.field("method", req.method())
678 .field("url", req.url())
679 .field("headers", req.headers())
680}
681
682#[cfg(test)]
683mod tests {
684 use super::super::{body, Client};
685 use super::{HttpRequest, Request, Version};
686 use crate::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, HOST};
687 use crate::Method;
688 use serde::Serialize;
689 #[cfg(feature = "json")]
690 use serde_json;
691 use serde_urlencoded;
692 use std::collections::{BTreeMap, HashMap};
693 use std::time::Duration;
694
695 #[test]
696 fn basic_get_request() {
697 let client = Client::new();
698 let some_url = "https://google.com/";
699 let r = client.get(some_url).build().unwrap();
700
701 assert_eq!(r.method(), &Method::GET);
702 assert_eq!(r.url().as_str(), some_url);
703 }
704
705 #[test]
706 fn basic_head_request() {
707 let client = Client::new();
708 let some_url = "https://google.com/";
709 let r = client.head(some_url).build().unwrap();
710
711 assert_eq!(r.method(), &Method::HEAD);
712 assert_eq!(r.url().as_str(), some_url);
713 }
714
715 #[test]
716 fn basic_post_request() {
717 let client = Client::new();
718 let some_url = "https://google.com/";
719 let r = client.post(some_url).build().unwrap();
720
721 assert_eq!(r.method(), &Method::POST);
722 assert_eq!(r.url().as_str(), some_url);
723 }
724
725 #[test]
726 fn basic_put_request() {
727 let client = Client::new();
728 let some_url = "https://google.com/";
729 let r = client.put(some_url).build().unwrap();
730
731 assert_eq!(r.method(), &Method::PUT);
732 assert_eq!(r.url().as_str(), some_url);
733 }
734
735 #[test]
736 fn basic_patch_request() {
737 let client = Client::new();
738 let some_url = "https://google.com/";
739 let r = client.patch(some_url).build().unwrap();
740
741 assert_eq!(r.method(), &Method::PATCH);
742 assert_eq!(r.url().as_str(), some_url);
743 }
744
745 #[test]
746 fn basic_delete_request() {
747 let client = Client::new();
748 let some_url = "https://google.com/";
749 let r = client.delete(some_url).build().unwrap();
750
751 assert_eq!(r.method(), &Method::DELETE);
752 assert_eq!(r.url().as_str(), some_url);
753 }
754
755 #[test]
756 fn add_header() {
757 let client = Client::new();
758 let some_url = "https://google.com/";
759 let r = client.post(some_url);
760
761 let header = HeaderValue::from_static("google.com");
762
763 let r = r.header(HOST, header.clone()).build().unwrap();
765
766 assert_eq!(r.headers().get(HOST), Some(&header));
768 }
769
770 #[test]
771 fn add_headers() {
772 let client = Client::new();
773 let some_url = "https://google.com/";
774 let r = client.post(some_url);
775
776 let header = HeaderValue::from_static("google.com");
777
778 let mut headers = HeaderMap::new();
779 headers.insert(HOST, header);
780
781 let r = r.headers(headers.clone()).build().unwrap();
783
784 assert_eq!(r.headers(), &headers);
786 }
787
788 #[test]
789 fn add_headers_multi() {
790 let client = Client::new();
791 let some_url = "https://google.com/";
792 let r = client.post(some_url);
793
794 let header_json = HeaderValue::from_static("application/json");
795 let header_xml = HeaderValue::from_static("application/xml");
796
797 let mut headers = HeaderMap::new();
798 headers.append(ACCEPT, header_json);
799 headers.append(ACCEPT, header_xml);
800
801 let r = r.headers(headers.clone()).build().unwrap();
803
804 assert_eq!(r.headers(), &headers);
806 let mut all_values = r.headers().get_all(ACCEPT).iter();
807 assert_eq!(all_values.next().unwrap(), &"application/json");
808 assert_eq!(all_values.next().unwrap(), &"application/xml");
809 assert_eq!(all_values.next(), None);
810 }
811
812 #[test]
813 fn add_body() {
814 let client = Client::new();
815 let some_url = "https://google.com/";
816 let r = client.post(some_url);
817
818 let body = "Some interesting content";
819
820 let mut r = r.body(body).build().unwrap();
821
822 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
823
824 assert_eq!(buf, body);
825 }
826
827 #[test]
828 fn add_query_append() {
829 let client = Client::new();
830 let some_url = "https://google.com/";
831 let mut r = client.get(some_url);
832
833 r = r.query(&[("foo", "bar")]);
834 r = r.query(&[("qux", 3)]);
835
836 let req = r.build().expect("request is valid");
837 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
838 }
839
840 #[test]
841 fn add_query_append_same() {
842 let client = Client::new();
843 let some_url = "https://google.com/";
844 let mut r = client.get(some_url);
845
846 r = r.query(&[("foo", "a"), ("foo", "b")]);
847
848 let req = r.build().expect("request is valid");
849 assert_eq!(req.url().query(), Some("foo=a&foo=b"));
850 }
851
852 #[test]
853 fn add_query_struct() {
854 #[derive(Serialize)]
855 struct Params {
856 foo: String,
857 qux: i32,
858 }
859
860 let client = Client::new();
861 let some_url = "https://google.com/";
862 let mut r = client.get(some_url);
863
864 let params = Params {
865 foo: "bar".into(),
866 qux: 3,
867 };
868
869 r = r.query(¶ms);
870
871 let req = r.build().expect("request is valid");
872 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
873 }
874
875 #[test]
876 fn add_query_map() {
877 let mut params = BTreeMap::new();
878 params.insert("foo", "bar");
879 params.insert("qux", "three");
880
881 let client = Client::new();
882 let some_url = "https://google.com/";
883 let mut r = client.get(some_url);
884
885 r = r.query(¶ms);
886
887 let req = r.build().expect("request is valid");
888 assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
889 }
890
891 #[test]
892 fn add_form() {
893 let client = Client::new();
894 let some_url = "https://google.com/";
895 let r = client.post(some_url);
896
897 let mut form_data = HashMap::new();
898 form_data.insert("foo", "bar");
899
900 let mut r = r.form(&form_data).build().unwrap();
901
902 assert_eq!(
904 r.headers().get(CONTENT_TYPE).unwrap(),
905 &"application/x-www-form-urlencoded"
906 );
907
908 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
909
910 let body_should_be = serde_urlencoded::to_string(&form_data).unwrap();
911 assert_eq!(buf, body_should_be);
912 }
913
914 #[test]
915 #[cfg(feature = "json")]
916 fn add_json() {
917 let client = Client::new();
918 let some_url = "https://google.com/";
919 let r = client.post(some_url);
920
921 let mut json_data = HashMap::new();
922 json_data.insert("foo", "bar");
923
924 let mut r = r.json(&json_data).build().unwrap();
925
926 assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/json");
928
929 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
930
931 let body_should_be = serde_json::to_string(&json_data).unwrap();
932 assert_eq!(buf, body_should_be);
933 }
934
935 #[test]
936 #[cfg(feature = "json")]
937 fn add_json_fail() {
938 use serde::ser::Error as _;
939 use serde::{Serialize, Serializer};
940 use std::error::Error as _;
941 struct MyStruct;
942 impl Serialize for MyStruct {
943 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
944 where
945 S: Serializer,
946 {
947 Err(S::Error::custom("nope"))
948 }
949 }
950
951 let client = Client::new();
952 let some_url = "https://google.com/";
953 let r = client.post(some_url);
954 let json_data = MyStruct;
955 let err = r.json(&json_data).build().unwrap_err();
956 assert!(err.is_builder()); assert!(err.source().unwrap().is::<serde_json::Error>());
958 }
959
960 #[test]
961 fn test_replace_headers() {
962 use http::HeaderMap;
963
964 let mut headers = HeaderMap::new();
965 headers.insert("foo", "bar".parse().unwrap());
966 headers.append("foo", "baz".parse().unwrap());
967
968 let client = Client::new();
969 let req = client
970 .get("https://hyper.rs")
971 .header("im-a", "keeper")
972 .header("foo", "pop me")
973 .headers(headers)
974 .build()
975 .expect("request build");
976
977 assert_eq!(req.headers()["im-a"], "keeper");
978
979 let foo = req.headers().get_all("foo").iter().collect::<Vec<_>>();
980 assert_eq!(foo.len(), 2);
981 assert_eq!(foo[0], "bar");
982 assert_eq!(foo[1], "baz");
983 }
984
985 #[test]
986 fn normalize_empty_query() {
987 let client = Client::new();
988 let some_url = "https://google.com/";
989 let empty_query: &[(&str, &str)] = &[];
990
991 let req = client
992 .get(some_url)
993 .query(empty_query)
994 .build()
995 .expect("request build");
996
997 assert_eq!(req.url().query(), None);
998 assert_eq!(req.url().as_str(), "https://google.com/");
999 }
1000
1001 #[test]
1002 fn convert_url_authority_into_basic_auth() {
1003 let client = Client::new();
1004 let some_url = "https://Aladdin:open sesame@localhost/";
1005
1006 let req = client.get(some_url).build().expect("request build");
1007
1008 assert_eq!(req.url().as_str(), "https://localhost/");
1009 assert_eq!(
1010 req.headers()["authorization"],
1011 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
1012 );
1013 }
1014
1015 #[test]
1016 fn convert_from_http_request() {
1017 let http_request = HttpRequest::builder()
1018 .method("GET")
1019 .uri("http://localhost/")
1020 .header("User-Agent", "my-awesome-agent/1.0")
1021 .body("test test test")
1022 .unwrap();
1023 let req: Request = Request::try_from(http_request).unwrap();
1024 assert_eq!(req.body().is_none(), false);
1025 let test_data = b"test test test";
1026 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
1027 let headers = req.headers();
1028 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
1029 assert_eq!(req.method(), Method::GET);
1030 assert_eq!(req.url().as_str(), "http://localhost/");
1031 }
1032
1033 #[test]
1034 fn set_http_request_version() {
1035 let http_request = HttpRequest::builder()
1036 .method("GET")
1037 .uri("http://localhost/")
1038 .header("User-Agent", "my-awesome-agent/1.0")
1039 .version(Version::HTTP_11)
1040 .body("test test test")
1041 .unwrap();
1042 let req: Request = Request::try_from(http_request).unwrap();
1043 assert_eq!(req.body().is_none(), false);
1044 let test_data = b"test test test";
1045 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
1046 let headers = req.headers();
1047 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
1048 assert_eq!(req.method(), Method::GET);
1049 assert_eq!(req.url().as_str(), "http://localhost/");
1050 assert_eq!(req.version(), Version::HTTP_11);
1051 }
1052
1053 #[test]
1054 fn test_basic_auth_sensitive_header() {
1055 let client = Client::new();
1056 let some_url = "https://localhost/";
1057
1058 let req = client
1059 .get(some_url)
1060 .basic_auth("Aladdin", Some("open sesame"))
1061 .build()
1062 .expect("request build");
1063
1064 assert_eq!(req.url().as_str(), "https://localhost/");
1065 assert_eq!(
1066 req.headers()["authorization"],
1067 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
1068 );
1069 assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1070 }
1071
1072 #[test]
1073 fn test_bearer_auth_sensitive_header() {
1074 let client = Client::new();
1075 let some_url = "https://localhost/";
1076
1077 let req = client
1078 .get(some_url)
1079 .bearer_auth("Hold my bear")
1080 .build()
1081 .expect("request build");
1082
1083 assert_eq!(req.url().as_str(), "https://localhost/");
1084 assert_eq!(req.headers()["authorization"], "Bearer Hold my bear");
1085 assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1086 }
1087
1088 #[test]
1089 fn test_request_cloning() {
1090 let mut request = Request::new(Method::GET, "https://example.com".try_into().unwrap());
1091 *request.timeout_mut() = Some(Duration::from_secs(42));
1092 *request.version_mut() = Version::HTTP_11;
1093
1094 let clone = request.try_clone().unwrap();
1095 assert_eq!(request.version(), clone.version());
1096 assert_eq!(request.headers(), clone.headers());
1097 assert_eq!(request.timeout(), clone.timeout());
1098 }
1099}