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