1use std::convert::TryFrom;
2use std::fmt;
3use std::time::Duration;
4
5use base64::encode;
6use http::{request::Parts, Request as HttpRequest, Version};
7use serde::Serialize;
8#[cfg(feature = "json")]
9use serde_json;
10use serde_urlencoded;
11
12use super::body::{self, Body};
13#[cfg(feature = "multipart")]
14use super::multipart;
15use super::Client;
16use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
17use crate::{async_impl, Method, Url};
18
19pub struct Request {
21 body: Option<Body>,
22 inner: async_impl::Request,
23}
24
25#[derive(Debug)]
29#[must_use = "RequestBuilder does nothing until you 'send' it"]
30pub struct RequestBuilder {
31 client: Client,
32 request: crate::Result<Request>,
33}
34
35impl Request {
36 #[inline]
38 pub fn new(method: Method, url: Url) -> Self {
39 Request {
40 body: None,
41 inner: async_impl::Request::new(method, url),
42 }
43 }
44
45 #[inline]
47 pub fn method(&self) -> &Method {
48 self.inner.method()
49 }
50
51 #[inline]
53 pub fn method_mut(&mut self) -> &mut Method {
54 self.inner.method_mut()
55 }
56
57 #[inline]
59 pub fn url(&self) -> &Url {
60 self.inner.url()
61 }
62
63 #[inline]
65 pub fn url_mut(&mut self) -> &mut Url {
66 self.inner.url_mut()
67 }
68
69 #[inline]
71 pub fn headers(&self) -> &HeaderMap {
72 self.inner.headers()
73 }
74
75 #[inline]
77 pub fn headers_mut(&mut self) -> &mut HeaderMap {
78 self.inner.headers_mut()
79 }
80
81 #[inline]
83 pub fn version(&self) -> Version {
84 self.inner.version()
85 }
86
87 #[inline]
89 pub fn version_mut(&mut self) -> &mut Version {
90 self.inner.version_mut()
91 }
92
93 #[inline]
95 pub fn body(&self) -> Option<&Body> {
96 self.body.as_ref()
97 }
98
99 #[inline]
101 pub fn body_mut(&mut self) -> &mut Option<Body> {
102 &mut self.body
103 }
104
105 #[inline]
107 pub fn timeout(&self) -> Option<&Duration> {
108 self.inner.timeout()
109 }
110
111 #[inline]
113 pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
114 self.inner.timeout_mut()
115 }
116
117 pub fn try_clone(&self) -> Option<Request> {
122 let body = if let Some(ref body) = self.body.as_ref() {
123 if let Some(body) = body.try_clone() {
124 Some(body)
125 } else {
126 return None;
127 }
128 } else {
129 None
130 };
131 let mut req = Request::new(self.method().clone(), self.url().clone());
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 header<K, V>(self, key: K, value: V) -> RequestBuilder
185 where
186 HeaderName: TryFrom<K>,
187 HeaderValue: TryFrom<V>,
188 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
189 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
190 {
191 self.header_sensitive(key, value, false)
192 }
193
194 fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
196 where
197 HeaderName: TryFrom<K>,
198 HeaderValue: TryFrom<V>,
199 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
200 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
201 {
202 let mut error = None;
203 if let Ok(ref mut req) = self.request {
204 match <HeaderName as TryFrom<K>>::try_from(key) {
205 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
206 Ok(mut value) => {
207 value.set_sensitive(sensitive);
208 req.headers_mut().append(key, value);
209 }
210 Err(e) => error = Some(crate::error::builder(e.into())),
211 },
212 Err(e) => error = Some(crate::error::builder(e.into())),
213 };
214 }
215 if let Some(err) = error {
216 self.request = Err(err);
217 }
218 self
219 }
220
221 pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
247 if let Ok(ref mut req) = self.request {
248 crate::util::replace_headers(req.headers_mut(), headers);
249 }
250 self
251 }
252
253 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
265 where
266 U: fmt::Display,
267 P: fmt::Display,
268 {
269 let auth = match password {
270 Some(password) => format!("{}:{}", username, password),
271 None => format!("{}:", username),
272 };
273 let header_value = format!("Basic {}", encode(&auth));
274 self.header_sensitive(crate::header::AUTHORIZATION, &*header_value, true)
275 }
276
277 pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
289 where
290 T: fmt::Display,
291 {
292 let header_value = format!("Bearer {}", token);
293 self.header_sensitive(crate::header::AUTHORIZATION, &*header_value, true)
294 }
295
296 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
340 if let Ok(ref mut req) = self.request {
341 *req.body_mut() = Some(body.into());
342 }
343 self
344 }
345
346 pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
352 if let Ok(ref mut req) = self.request {
353 *req.timeout_mut() = Some(timeout);
354 }
355 self
356 }
357
358 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
389 let mut error = None;
390 if let Ok(ref mut req) = self.request {
391 let url = req.url_mut();
392 let mut pairs = url.query_pairs_mut();
393 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
394
395 if let Err(err) = query.serialize(serializer) {
396 error = Some(crate::error::builder(err));
397 }
398 }
399 if let Ok(ref mut req) = self.request {
400 if let Some("") = req.url().query() {
401 req.url_mut().set_query(None);
402 }
403 }
404 if let Some(err) = error {
405 self.request = Err(err);
406 }
407 self
408 }
409
410 pub fn version(mut self, version: Version) -> RequestBuilder {
412 if let Ok(ref mut req) = self.request {
413 *req.version_mut() = version;
414 }
415 self
416 }
417
418 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
445 let mut error = None;
446 if let Ok(ref mut req) = self.request {
447 match serde_urlencoded::to_string(form) {
448 Ok(body) => {
449 req.headers_mut().insert(
450 CONTENT_TYPE,
451 HeaderValue::from_static("application/x-www-form-urlencoded"),
452 );
453 *req.body_mut() = Some(body.into());
454 }
455 Err(err) => error = Some(crate::error::builder(err)),
456 }
457 }
458 if let Some(err) = error {
459 self.request = Err(err);
460 }
461 self
462 }
463
464 #[cfg(feature = "json")]
496 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
497 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
498 let mut error = None;
499 if let Ok(ref mut req) = self.request {
500 match serde_json::to_vec(json) {
501 Ok(body) => {
502 req.headers_mut()
503 .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
504 *req.body_mut() = Some(body.into());
505 }
506 Err(err) => error = Some(crate::error::builder(err)),
507 }
508 }
509 if let Some(err) = error {
510 self.request = Err(err);
511 }
512 self
513 }
514
515 #[cfg(feature = "multipart")]
535 #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
536 pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
537 let mut builder = self.header(
538 CONTENT_TYPE,
539 format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
540 );
541 if let Ok(ref mut req) = builder.request {
542 *req.body_mut() = Some(match multipart.compute_length() {
543 Some(length) => Body::sized(multipart.reader(), length),
544 None => Body::new(multipart.reader()),
545 })
546 }
547 builder
548 }
549
550 pub fn build(self) -> crate::Result<Request> {
553 self.request
554 }
555
556 pub fn send(self) -> crate::Result<super::Response> {
563 self.client.execute(self.request?)
564 }
565
566 pub fn try_clone(&self) -> Option<RequestBuilder> {
611 self.request
612 .as_ref()
613 .ok()
614 .and_then(|req| req.try_clone())
615 .map(|req| RequestBuilder {
616 client: self.client.clone(),
617 request: Ok(req),
618 })
619 }
620}
621
622impl<T> TryFrom<HttpRequest<T>> for Request
623where
624 T: Into<Body>,
625{
626 type Error = crate::Error;
627
628 fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
629 let (parts, body) = req.into_parts();
630 let Parts {
631 method,
632 uri,
633 headers,
634 ..
635 } = parts;
636 let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
637 let mut inner = async_impl::Request::new(method, url);
638 crate::util::replace_headers(inner.headers_mut(), headers);
639 Ok(Request {
640 body: Some(body.into()),
641 inner,
642 })
643 }
644}
645
646impl fmt::Debug for Request {
647 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
648 fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
649 }
650}
651
652fn fmt_request_fields<'a, 'b>(
653 f: &'a mut fmt::DebugStruct<'a, 'b>,
654 req: &Request,
655) -> &'a mut fmt::DebugStruct<'a, 'b> {
656 f.field("method", req.method())
657 .field("url", req.url())
658 .field("headers", req.headers())
659}
660
661#[cfg(test)]
662mod tests {
663 use super::super::{body, Client};
664 use super::{HttpRequest, Request, Version};
665 use crate::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, HOST};
666 use crate::Method;
667 use serde::Serialize;
668 #[cfg(feature = "json")]
669 use serde_json;
670 use serde_urlencoded;
671 use std::collections::{BTreeMap, HashMap};
672 use std::convert::TryFrom;
673
674 #[test]
675 fn basic_get_request() {
676 let client = Client::new();
677 let some_url = "https://google.com/";
678 let r = client.get(some_url).build().unwrap();
679
680 assert_eq!(r.method(), &Method::GET);
681 assert_eq!(r.url().as_str(), some_url);
682 }
683
684 #[test]
685 fn basic_head_request() {
686 let client = Client::new();
687 let some_url = "https://google.com/";
688 let r = client.head(some_url).build().unwrap();
689
690 assert_eq!(r.method(), &Method::HEAD);
691 assert_eq!(r.url().as_str(), some_url);
692 }
693
694 #[test]
695 fn basic_post_request() {
696 let client = Client::new();
697 let some_url = "https://google.com/";
698 let r = client.post(some_url).build().unwrap();
699
700 assert_eq!(r.method(), &Method::POST);
701 assert_eq!(r.url().as_str(), some_url);
702 }
703
704 #[test]
705 fn basic_put_request() {
706 let client = Client::new();
707 let some_url = "https://google.com/";
708 let r = client.put(some_url).build().unwrap();
709
710 assert_eq!(r.method(), &Method::PUT);
711 assert_eq!(r.url().as_str(), some_url);
712 }
713
714 #[test]
715 fn basic_patch_request() {
716 let client = Client::new();
717 let some_url = "https://google.com/";
718 let r = client.patch(some_url).build().unwrap();
719
720 assert_eq!(r.method(), &Method::PATCH);
721 assert_eq!(r.url().as_str(), some_url);
722 }
723
724 #[test]
725 fn basic_delete_request() {
726 let client = Client::new();
727 let some_url = "https://google.com/";
728 let r = client.delete(some_url).build().unwrap();
729
730 assert_eq!(r.method(), &Method::DELETE);
731 assert_eq!(r.url().as_str(), some_url);
732 }
733
734 #[test]
735 fn add_header() {
736 let client = Client::new();
737 let some_url = "https://google.com/";
738 let r = client.post(some_url);
739
740 let header = HeaderValue::from_static("google.com");
741
742 let r = r.header(HOST, header.clone()).build().unwrap();
744
745 assert_eq!(r.headers().get(HOST), Some(&header));
747 }
748
749 #[test]
750 fn add_headers() {
751 let client = Client::new();
752 let some_url = "https://google.com/";
753 let r = client.post(some_url);
754
755 let header = HeaderValue::from_static("google.com");
756
757 let mut headers = HeaderMap::new();
758 headers.insert(HOST, header);
759
760 let r = r.headers(headers.clone()).build().unwrap();
762
763 assert_eq!(r.headers(), &headers);
765 }
766
767 #[test]
768 fn add_headers_multi() {
769 let client = Client::new();
770 let some_url = "https://google.com/";
771 let r = client.post(some_url);
772
773 let header_json = HeaderValue::from_static("application/json");
774 let header_xml = HeaderValue::from_static("application/xml");
775
776 let mut headers = HeaderMap::new();
777 headers.append(ACCEPT, header_json);
778 headers.append(ACCEPT, header_xml);
779
780 let r = r.headers(headers.clone()).build().unwrap();
782
783 assert_eq!(r.headers(), &headers);
785 let mut all_values = r.headers().get_all(ACCEPT).iter();
786 assert_eq!(all_values.next().unwrap(), &"application/json");
787 assert_eq!(all_values.next().unwrap(), &"application/xml");
788 assert_eq!(all_values.next(), None);
789 }
790
791 #[test]
792 fn add_body() {
793 let client = Client::new();
794 let some_url = "https://google.com/";
795 let r = client.post(some_url);
796
797 let body = "Some interesting content";
798
799 let mut r = r.body(body).build().unwrap();
800
801 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
802
803 assert_eq!(buf, body);
804 }
805
806 #[test]
807 fn add_query_append() {
808 let client = Client::new();
809 let some_url = "https://google.com/";
810 let mut r = client.get(some_url);
811
812 r = r.query(&[("foo", "bar")]);
813 r = r.query(&[("qux", 3)]);
814
815 let req = r.build().expect("request is valid");
816 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
817 }
818
819 #[test]
820 fn add_query_append_same() {
821 let client = Client::new();
822 let some_url = "https://google.com/";
823 let mut r = client.get(some_url);
824
825 r = r.query(&[("foo", "a"), ("foo", "b")]);
826
827 let req = r.build().expect("request is valid");
828 assert_eq!(req.url().query(), Some("foo=a&foo=b"));
829 }
830
831 #[test]
832 fn add_query_struct() {
833 #[derive(Serialize)]
834 struct Params {
835 foo: String,
836 qux: i32,
837 }
838
839 let client = Client::new();
840 let some_url = "https://google.com/";
841 let mut r = client.get(some_url);
842
843 let params = Params {
844 foo: "bar".into(),
845 qux: 3,
846 };
847
848 r = r.query(¶ms);
849
850 let req = r.build().expect("request is valid");
851 assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
852 }
853
854 #[test]
855 fn add_query_map() {
856 let mut params = BTreeMap::new();
857 params.insert("foo", "bar");
858 params.insert("qux", "three");
859
860 let client = Client::new();
861 let some_url = "https://google.com/";
862 let mut r = client.get(some_url);
863
864 r = r.query(¶ms);
865
866 let req = r.build().expect("request is valid");
867 assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
868 }
869
870 #[test]
871 fn add_form() {
872 let client = Client::new();
873 let some_url = "https://google.com/";
874 let r = client.post(some_url);
875
876 let mut form_data = HashMap::new();
877 form_data.insert("foo", "bar");
878
879 let mut r = r.form(&form_data).build().unwrap();
880
881 assert_eq!(
883 r.headers().get(CONTENT_TYPE).unwrap(),
884 &"application/x-www-form-urlencoded"
885 );
886
887 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
888
889 let body_should_be = serde_urlencoded::to_string(&form_data).unwrap();
890 assert_eq!(buf, body_should_be);
891 }
892
893 #[test]
894 #[cfg(feature = "json")]
895 fn add_json() {
896 let client = Client::new();
897 let some_url = "https://google.com/";
898 let r = client.post(some_url);
899
900 let mut json_data = HashMap::new();
901 json_data.insert("foo", "bar");
902
903 let mut r = r.json(&json_data).build().unwrap();
904
905 assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/json");
907
908 let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
909
910 let body_should_be = serde_json::to_string(&json_data).unwrap();
911 assert_eq!(buf, body_should_be);
912 }
913
914 #[test]
915 #[cfg(feature = "json")]
916 fn add_json_fail() {
917 use serde::ser::Error as _;
918 use serde::{Serialize, Serializer};
919 use std::error::Error as _;
920 struct MyStruct;
921 impl Serialize for MyStruct {
922 fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
923 where
924 S: Serializer,
925 {
926 Err(S::Error::custom("nope"))
927 }
928 }
929
930 let client = Client::new();
931 let some_url = "https://google.com/";
932 let r = client.post(some_url);
933 let json_data = MyStruct;
934 let err = r.json(&json_data).build().unwrap_err();
935 assert!(err.is_builder()); assert!(err.source().unwrap().is::<serde_json::Error>());
937 }
938
939 #[test]
940 fn test_replace_headers() {
941 use http::HeaderMap;
942
943 let mut headers = HeaderMap::new();
944 headers.insert("foo", "bar".parse().unwrap());
945 headers.append("foo", "baz".parse().unwrap());
946
947 let client = Client::new();
948 let req = client
949 .get("https://hyper.rs")
950 .header("im-a", "keeper")
951 .header("foo", "pop me")
952 .headers(headers)
953 .build()
954 .expect("request build");
955
956 assert_eq!(req.headers()["im-a"], "keeper");
957
958 let foo = req.headers().get_all("foo").iter().collect::<Vec<_>>();
959 assert_eq!(foo.len(), 2);
960 assert_eq!(foo[0], "bar");
961 assert_eq!(foo[1], "baz");
962 }
963
964 #[test]
965 fn normalize_empty_query() {
966 let client = Client::new();
967 let some_url = "https://google.com/";
968 let empty_query: &[(&str, &str)] = &[];
969
970 let req = client
971 .get(some_url)
972 .query(empty_query)
973 .build()
974 .expect("request build");
975
976 assert_eq!(req.url().query(), None);
977 assert_eq!(req.url().as_str(), "https://google.com/");
978 }
979
980 #[test]
981 fn convert_url_authority_into_basic_auth() {
982 let client = Client::new();
983 let some_url = "https://Aladdin:open sesame@localhost/";
984
985 let req = client.get(some_url).build().expect("request build");
986
987 assert_eq!(req.url().as_str(), "https://localhost/");
988 assert_eq!(
989 req.headers()["authorization"],
990 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
991 );
992 }
993
994 #[test]
995 fn convert_from_http_request() {
996 let http_request = HttpRequest::builder()
997 .method("GET")
998 .uri("http://localhost/")
999 .header("User-Agent", "my-awesome-agent/1.0")
1000 .body("test test test")
1001 .unwrap();
1002 let req: Request = Request::try_from(http_request).unwrap();
1003 assert_eq!(req.body().is_none(), false);
1004 let test_data = b"test test test";
1005 assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
1006 let headers = req.headers();
1007 assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
1008 assert_eq!(req.method(), Method::GET);
1009 assert_eq!(req.url().as_str(), "http://localhost/");
1010 }
1011
1012 #[test]
1013 fn set_http_request_version() {
1014 let http_request = HttpRequest::builder()
1015 .method("GET")
1016 .uri("http://localhost/")
1017 .header("User-Agent", "my-awesome-agent/1.0")
1018 .version(Version::HTTP_11)
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 assert_eq!(req.version(), Version::HTTP_11);
1030 }
1031
1032 #[test]
1033 fn test_basic_auth_sensitive_header() {
1034 let client = Client::new();
1035 let some_url = "https://localhost/";
1036
1037 let req = client
1038 .get(some_url)
1039 .basic_auth("Aladdin", Some("open sesame"))
1040 .build()
1041 .expect("request build");
1042
1043 assert_eq!(req.url().as_str(), "https://localhost/");
1044 assert_eq!(
1045 req.headers()["authorization"],
1046 "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=="
1047 );
1048 assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1049 }
1050
1051 #[test]
1052 fn test_bearer_auth_sensitive_header() {
1053 let client = Client::new();
1054 let some_url = "https://localhost/";
1055
1056 let req = client
1057 .get(some_url)
1058 .bearer_auth("Hold my bear")
1059 .build()
1060 .expect("request build");
1061
1062 assert_eq!(req.url().as_str(), "https://localhost/");
1063 assert_eq!(req.headers()["authorization"], "Bearer Hold my bear");
1064 assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1065 }
1066}