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