1 use std::fmt;
2 use std::convert::TryFrom;
3 use std::time::Duration;
4 
5 use base64::encode;
6 use http::{Request as HttpRequest, request::Parts};
7 use serde::Serialize;
8 #[cfg(feature = "json")]
9 use serde_json;
10 use serde_urlencoded;
11 
12 use super::body::{self, Body};
13 use super::multipart;
14 use super::Client;
15 use crate::header::{HeaderMap, HeaderName, HeaderValue, CONTENT_TYPE};
16 use crate::{async_impl, Method, Url};
17 
18 /// A request which can be executed with `Client::execute()`.
19 pub struct Request {
20     body: Option<Body>,
21     inner: async_impl::Request,
22 }
23 
24 /// A builder to construct the properties of a `Request`.
25 #[derive(Debug)]
26 pub struct RequestBuilder {
27     client: Client,
28     request: crate::Result<Request>,
29 }
30 
31 impl Request {
32     /// Constructs a new request.
33     #[inline]
new(method: Method, url: Url) -> Self34     pub fn new(method: Method, url: Url) -> Self {
35         Request {
36             body: None,
37             inner: async_impl::Request::new(method, url),
38         }
39     }
40 
41     /// Get the method.
42     #[inline]
method(&self) -> &Method43     pub fn method(&self) -> &Method {
44         self.inner.method()
45     }
46 
47     /// Get a mutable reference to the method.
48     #[inline]
method_mut(&mut self) -> &mut Method49     pub fn method_mut(&mut self) -> &mut Method {
50         self.inner.method_mut()
51     }
52 
53     /// Get the url.
54     #[inline]
url(&self) -> &Url55     pub fn url(&self) -> &Url {
56         self.inner.url()
57     }
58 
59     /// Get a mutable reference to the url.
60     #[inline]
url_mut(&mut self) -> &mut Url61     pub fn url_mut(&mut self) -> &mut Url {
62         self.inner.url_mut()
63     }
64 
65     /// Get the headers.
66     #[inline]
headers(&self) -> &HeaderMap67     pub fn headers(&self) -> &HeaderMap {
68         self.inner.headers()
69     }
70 
71     /// Get a mutable reference to the headers.
72     #[inline]
headers_mut(&mut self) -> &mut HeaderMap73     pub fn headers_mut(&mut self) -> &mut HeaderMap {
74         self.inner.headers_mut()
75     }
76 
77     /// Get the body.
78     #[inline]
body(&self) -> Option<&Body>79     pub fn body(&self) -> Option<&Body> {
80         self.body.as_ref()
81     }
82 
83     /// Get a mutable reference to the body.
84     #[inline]
body_mut(&mut self) -> &mut Option<Body>85     pub fn body_mut(&mut self) -> &mut Option<Body> {
86         &mut self.body
87     }
88 
89     /// Get the timeout.
90     #[inline]
timeout(&self) -> Option<&Duration>91     pub fn timeout(&self) -> Option<&Duration> {
92         self.inner.timeout()
93     }
94 
95     /// Get a mutable reference to the timeout.
96     #[inline]
timeout_mut(&mut self) -> &mut Option<Duration>97     pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
98         self.inner.timeout_mut()
99     }
100 
101     /// Attempts to clone the `Request`.
102     ///
103     /// None is returned if a body is which can not be cloned. This can be because the body is a
104     /// stream.
try_clone(&self) -> Option<Request>105     pub fn try_clone(&self) -> Option<Request> {
106         let body = if let Some(ref body) = self.body.as_ref() {
107             if let Some(body) = body.try_clone() {
108                 Some(body)
109             } else {
110                 return None;
111             }
112         } else {
113             None
114         };
115         let mut req = Request::new(self.method().clone(), self.url().clone());
116         *req.headers_mut() = self.headers().clone();
117         req.body = body;
118         Some(req)
119     }
120 
into_async(self) -> (async_impl::Request, Option<body::Sender>)121     pub(crate) fn into_async(self) -> (async_impl::Request, Option<body::Sender>) {
122         use crate::header::CONTENT_LENGTH;
123 
124         let mut req_async = self.inner;
125         let body = self.body.and_then(|body| {
126             let (tx, body, len) = body.into_async();
127             if let Some(len) = len {
128                 req_async.headers_mut().insert(CONTENT_LENGTH, len.into());
129             }
130             *req_async.body_mut() = Some(body);
131             tx
132         });
133         (req_async, body)
134     }
135 }
136 
137 impl RequestBuilder {
new(client: Client, request: crate::Result<Request>) -> RequestBuilder138     pub(crate) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
139         let mut builder = RequestBuilder { client, request };
140 
141         let auth = builder
142             .request
143             .as_mut()
144             .ok()
145             .and_then(|req| async_impl::request::extract_authority(req.url_mut()));
146 
147         if let Some((username, password)) = auth {
148             builder.basic_auth(username, password)
149         } else {
150             builder
151         }
152     }
153 
154     /// Add a `Header` to this Request.
155     ///
156     /// ```rust
157     /// use reqwest::header::USER_AGENT;
158     ///
159     /// # fn run() -> Result<(), Box<std::error::Error>> {
160     /// let client = reqwest::blocking::Client::new();
161     /// let res = client.get("https://www.rust-lang.org")
162     ///     .header(USER_AGENT, "foo")
163     ///     .send()?;
164     /// # Ok(())
165     /// # }
166     /// ```
header<K, V>(self, key: K, value: V) -> RequestBuilder where HeaderName: TryFrom<K>, HeaderValue: TryFrom<V>, <HeaderName as TryFrom<K>>::Error: Into<http::Error>, <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,167     pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
168     where
169         HeaderName: TryFrom<K>,
170         HeaderValue: TryFrom<V>,
171         <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
172         <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
173     {
174         self.header_sensitive(key, value, false)
175     }
176 
177     /// Add a `Header` to this Request with ability to define if header_value is sensitive.
header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder where HeaderName: TryFrom<K>, HeaderValue: TryFrom<V>, <HeaderName as TryFrom<K>>::Error: Into<http::Error>, <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,178     fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
179     where
180         HeaderName: TryFrom<K>,
181         HeaderValue: TryFrom<V>,
182         <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
183         <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
184     {
185         let mut error = None;
186         if let Ok(ref mut req) = self.request {
187             match <HeaderName as TryFrom<K>>::try_from(key) {
188                 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
189                     Ok(mut value) => {
190                         value.set_sensitive(sensitive);
191                         req.headers_mut().append(key, value);
192                     }
193                     Err(e) => error = Some(crate::error::builder(e.into())),
194                 },
195                 Err(e) => error = Some(crate::error::builder(e.into())),
196             };
197         }
198         if let Some(err) = error {
199             self.request = Err(err);
200         }
201         self
202     }
203 
204     /// Add a set of Headers to the existing ones on this Request.
205     ///
206     /// The headers will be merged in to any already set.
207     ///
208     /// ```rust
209     /// use reqwest::header::{HeaderMap, HeaderValue, USER_AGENT, CONTENT_TYPE};
210     /// # use std::fs;
211     ///
212     /// fn construct_headers() -> HeaderMap {
213     ///     let mut headers = HeaderMap::new();
214     ///     headers.insert(USER_AGENT, HeaderValue::from_static("reqwest"));
215     ///     headers.insert(CONTENT_TYPE, HeaderValue::from_static("image/png"));
216     ///     headers
217     /// }
218     ///
219     /// # fn run() -> Result<(), Box<std::error::Error>> {
220     /// let file = fs::File::open("much_beauty.png")?;
221     /// let client = reqwest::blocking::Client::new();
222     /// let res = client.post("http://httpbin.org/post")
223     ///     .headers(construct_headers())
224     ///     .body(file)
225     ///     .send()?;
226     /// # Ok(())
227     /// # }
228     /// ```
headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder229     pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
230         if let Ok(ref mut req) = self.request {
231             async_impl::request::replace_headers(req.headers_mut(), headers);
232         }
233         self
234     }
235 
236     /// Enable HTTP basic authentication.
237     ///
238     /// ```rust
239     /// # fn run() -> Result<(), Box<std::error::Error>> {
240     /// let client = reqwest::blocking::Client::new();
241     /// let resp = client.delete("http://httpbin.org/delete")
242     ///     .basic_auth("admin", Some("good password"))
243     ///     .send()?;
244     /// # Ok(())
245     /// # }
246     /// ```
basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder where U: fmt::Display, P: fmt::Display,247     pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
248     where
249         U: fmt::Display,
250         P: fmt::Display,
251     {
252         let auth = match password {
253             Some(password) => format!("{}:{}", username, password),
254             None => format!("{}:", username),
255         };
256         let header_value = format!("Basic {}", encode(&auth));
257         self.header_sensitive(crate::header::AUTHORIZATION, &*header_value, true)
258     }
259 
260     /// Enable HTTP bearer authentication.
261     ///
262     /// ```rust
263     /// # fn run() -> Result<(), Box<std::error::Error>> {
264     /// let client = reqwest::blocking::Client::new();
265     /// let resp = client.delete("http://httpbin.org/delete")
266     ///     .bearer_auth("token")
267     ///     .send()?;
268     /// # Ok(())
269     /// # }
270     /// ```
bearer_auth<T>(self, token: T) -> RequestBuilder where T: fmt::Display,271     pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
272     where
273         T: fmt::Display,
274     {
275         let header_value = format!("Bearer {}", token);
276         self.header_sensitive(crate::header::AUTHORIZATION, &*header_value, true)
277     }
278 
279     /// Set the request body.
280     ///
281     /// # Examples
282     ///
283     /// Using a string:
284     ///
285     /// ```rust
286     /// # fn run() -> Result<(), Box<std::error::Error>> {
287     /// let client = reqwest::blocking::Client::new();
288     /// let res = client.post("http://httpbin.org/post")
289     ///     .body("from a &str!")
290     ///     .send()?;
291     /// # Ok(())
292     /// # }
293     /// ```
294     ///
295     /// Using a `File`:
296     ///
297     /// ```rust
298     /// # fn run() -> Result<(), Box<std::error::Error>> {
299     /// let file = std::fs::File::open("from_a_file.txt")?;
300     /// let client = reqwest::blocking::Client::new();
301     /// let res = client.post("http://httpbin.org/post")
302     ///     .body(file)
303     ///     .send()?;
304     /// # Ok(())
305     /// # }
306     /// ```
307     ///
308     /// Using arbitrary bytes:
309     ///
310     /// ```rust
311     /// # use std::fs;
312     /// # fn run() -> Result<(), Box<std::error::Error>> {
313     /// // from bytes!
314     /// let bytes: Vec<u8> = vec![1, 10, 100];
315     /// let client = reqwest::blocking::Client::new();
316     /// let res = client.post("http://httpbin.org/post")
317     ///     .body(bytes)
318     ///     .send()?;
319     /// # Ok(())
320     /// # }
321     /// ```
body<T: Into<Body>>(mut self, body: T) -> RequestBuilder322     pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
323         if let Ok(ref mut req) = self.request {
324             *req.body_mut() = Some(body.into());
325         }
326         self
327     }
328 
329     /// Enables a request timeout.
330     ///
331     /// The timeout is applied from the when the request starts connecting
332     /// until the response body has finished. It affects only this request
333     /// and overrides the timeout configured using `ClientBuilder::timeout()`.
timeout(mut self, timeout: Duration) -> RequestBuilder334     pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
335         if let Ok(ref mut req) = self.request {
336             *req.timeout_mut() = Some(timeout);
337         }
338         self
339     }
340 
341     /// Modify the query string of the URL.
342     ///
343     /// Modifies the URL of this request, adding the parameters provided.
344     /// This method appends and does not overwrite. This means that it can
345     /// be called multiple times and that existing query parameters are not
346     /// overwritten if the same key is used. The key will simply show up
347     /// twice in the query string.
348     /// Calling `.query(&[("foo", "a"), ("foo", "b")])` gives `"foo=a&foo=b"`.
349     ///
350     /// ```rust
351     /// # use reqwest::Error;
352     /// #
353     /// # fn run() -> Result<(), Error> {
354     /// let client = reqwest::blocking::Client::new();
355     /// let res = client.get("http://httpbin.org")
356     ///     .query(&[("lang", "rust")])
357     ///     .send()?;
358     /// # Ok(())
359     /// # }
360     /// ```
361     ///
362     /// # Note
363     /// This method does not support serializing a single key-value
364     /// pair. Instead of using `.query(("key", "val"))`, use a sequence, such
365     /// as `.query(&[("key", "val")])`. It's also possible to serialize structs
366     /// and maps into a key-value pair.
367     ///
368     /// # Errors
369     /// This method will fail if the object you provide cannot be serialized
370     /// into a query string.
query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder371     pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
372         let mut error = None;
373         if let Ok(ref mut req) = self.request {
374             let url = req.url_mut();
375             let mut pairs = url.query_pairs_mut();
376             let serializer = serde_urlencoded::Serializer::new(&mut pairs);
377 
378             if let Err(err) = query.serialize(serializer) {
379                 error = Some(crate::error::builder(err));
380             }
381         }
382         if let Ok(ref mut req) = self.request {
383             if let Some("") = req.url().query() {
384                 req.url_mut().set_query(None);
385             }
386         }
387         if let Some(err) = error {
388             self.request = Err(err);
389         }
390         self
391     }
392 
393     /// Send a form body.
394     ///
395     /// Sets the body to the url encoded serialization of the passed value,
396     /// and also sets the `Content-Type: application/x-www-form-urlencoded`
397     /// header.
398     ///
399     /// ```rust
400     /// # use reqwest::Error;
401     /// # use std::collections::HashMap;
402     /// #
403     /// # fn run() -> Result<(), Error> {
404     /// let mut params = HashMap::new();
405     /// params.insert("lang", "rust");
406     ///
407     /// let client = reqwest::blocking::Client::new();
408     /// let res = client.post("http://httpbin.org")
409     ///     .form(&params)
410     ///     .send()?;
411     /// # Ok(())
412     /// # }
413     /// ```
414     ///
415     /// # Errors
416     ///
417     /// This method fails if the passed value cannot be serialized into
418     /// url encoded format
form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder419     pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
420         let mut error = None;
421         if let Ok(ref mut req) = self.request {
422             match serde_urlencoded::to_string(form) {
423                 Ok(body) => {
424                     req.headers_mut().insert(
425                         CONTENT_TYPE,
426                         HeaderValue::from_static("application/x-www-form-urlencoded"),
427                     );
428                     *req.body_mut() = Some(body.into());
429                 }
430                 Err(err) => error = Some(crate::error::builder(err)),
431             }
432         }
433         if let Some(err) = error {
434             self.request = Err(err);
435         }
436         self
437     }
438 
439     /// Send a JSON body.
440     ///
441     /// Sets the body to the JSON serialization of the passed value, and
442     /// also sets the `Content-Type: application/json` header.
443     ///
444     /// # Optional
445     ///
446     /// This requires the optional `json` feature enabled.
447     ///
448     /// # Examples
449     ///
450     /// ```rust
451     /// # use reqwest::Error;
452     /// # use std::collections::HashMap;
453     /// #
454     /// # fn run() -> Result<(), Error> {
455     /// let mut map = HashMap::new();
456     /// map.insert("lang", "rust");
457     ///
458     /// let client = reqwest::blocking::Client::new();
459     /// let res = client.post("http://httpbin.org")
460     ///     .json(&map)
461     ///     .send()?;
462     /// # Ok(())
463     /// # }
464     /// ```
465     ///
466     /// # Errors
467     ///
468     /// Serialization can fail if `T`'s implementation of `Serialize` decides to
469     /// fail, or if `T` contains a map with non-string keys.
470     #[cfg(feature = "json")]
json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder471     pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
472         let mut error = None;
473         if let Ok(ref mut req) = self.request {
474             match serde_json::to_vec(json) {
475                 Ok(body) => {
476                     req.headers_mut()
477                         .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
478                     *req.body_mut() = Some(body.into());
479                 }
480                 Err(err) => error = Some(crate::error::builder(err)),
481             }
482         }
483         if let Some(err) = error {
484             self.request = Err(err);
485         }
486         self
487     }
488 
489     /// Sends a multipart/form-data body.
490     ///
491     /// ```
492     /// # use reqwest::Error;
493     ///
494     /// # fn run() -> Result<(), Box<std::error::Error>> {
495     /// let client = reqwest::blocking::Client::new();
496     /// let form = reqwest::blocking::multipart::Form::new()
497     ///     .text("key3", "value3")
498     ///     .file("file", "/path/to/field")?;
499     ///
500     /// let response = client.post("your url")
501     ///     .multipart(form)
502     ///     .send()?;
503     /// # Ok(())
504     /// # }
505     /// ```
506     ///
507     /// See [`multipart`](multipart/) for more examples.
multipart(self, mut multipart: multipart::Form) -> RequestBuilder508     pub fn multipart(self, mut multipart: multipart::Form) -> RequestBuilder {
509         let mut builder = self.header(
510             CONTENT_TYPE,
511             format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
512         );
513         if let Ok(ref mut req) = builder.request {
514             *req.body_mut() = Some(match multipart.compute_length() {
515                 Some(length) => Body::sized(multipart.reader(), length),
516                 None => Body::new(multipart.reader()),
517             })
518         }
519         builder
520     }
521 
522     /// Build a `Request`, which can be inspected, modified and executed with
523     /// `Client::execute()`.
build(self) -> crate::Result<Request>524     pub fn build(self) -> crate::Result<Request> {
525         self.request
526     }
527 
528     /// Constructs the Request and sends it the target URL, returning a Response.
529     ///
530     /// # Errors
531     ///
532     /// This method fails if there was an error while sending request,
533     /// redirect loop was detected or redirect limit was exhausted.
send(self) -> crate::Result<super::Response>534     pub fn send(self) -> crate::Result<super::Response> {
535         self.client.execute(self.request?)
536     }
537 
538     /// Attempts to clone the `RequestBuilder`.
539     ///
540     /// None is returned if a body is which can not be cloned. This can be because the body is a
541     /// stream.
542     ///
543     /// # Examples
544     ///
545     /// With a static body
546     ///
547     /// ```rust
548     /// # fn run() -> Result<(), Box<std::error::Error>> {
549     /// let client = reqwest::blocking::Client::new();
550     /// let builder = client.post("http://httpbin.org/post")
551     ///     .body("from a &str!");
552     /// let clone = builder.try_clone();
553     /// assert!(clone.is_some());
554     /// # Ok(())
555     /// # }
556     /// ```
557     ///
558     /// Without a body
559     ///
560     /// ```rust
561     /// # fn run() -> Result<(), Box<std::error::Error>> {
562     /// let client = reqwest::blocking::Client::new();
563     /// let builder = client.get("http://httpbin.org/get");
564     /// let clone = builder.try_clone();
565     /// assert!(clone.is_some());
566     /// # Ok(())
567     /// # }
568     /// ```
569     ///
570     /// With a non-clonable body
571     ///
572     /// ```rust
573     /// # fn run() -> Result<(), Box<std::error::Error>> {
574     /// let client = reqwest::blocking::Client::new();
575     /// let builder = client.get("http://httpbin.org/get")
576     ///     .body(reqwest::blocking::Body::new(std::io::empty()));
577     /// let clone = builder.try_clone();
578     /// assert!(clone.is_none());
579     /// # Ok(())
580     /// # }
581     /// ```
try_clone(&self) -> Option<RequestBuilder>582     pub fn try_clone(&self) -> Option<RequestBuilder> {
583         self.request
584             .as_ref()
585             .ok()
586             .and_then(|req| req.try_clone())
587             .map(|req| RequestBuilder {
588                 client: self.client.clone(),
589                 request: Ok(req),
590             })
591     }
592 }
593 
594 impl<T> TryFrom<HttpRequest<T>> for Request where T:Into<Body> {
595     type Error = crate::Error;
596 
try_from(req: HttpRequest<T>) -> crate::Result<Self>597     fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
598         let (parts, body) = req.into_parts();
599         let Parts {
600             method,
601             uri,
602             headers,
603             ..
604         } = parts;
605         let url = Url::parse(&uri.to_string())
606             .map_err(crate::error::builder)?;
607         let mut inner = async_impl::Request::new(method, url);
608         async_impl::request::replace_headers(inner.headers_mut(), headers);
609         Ok(Request {
610             body: Some(body.into()),
611             inner,
612         })
613     }
614 }
615 
616 impl fmt::Debug for Request {
fmt(&self, f: &mut fmt::Formatter) -> fmt::Result617     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
618         fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
619     }
620 }
621 
fmt_request_fields<'a, 'b>( f: &'a mut fmt::DebugStruct<'a, 'b>, req: &Request, ) -> &'a mut fmt::DebugStruct<'a, 'b>622 fn fmt_request_fields<'a, 'b>(
623     f: &'a mut fmt::DebugStruct<'a, 'b>,
624     req: &Request,
625 ) -> &'a mut fmt::DebugStruct<'a, 'b> {
626     f.field("method", req.method())
627         .field("url", req.url())
628         .field("headers", req.headers())
629 }
630 
631 #[cfg(test)]
632 mod tests {
633     use super::{HttpRequest, Request};
634     use super::super::{body, Client};
635     use crate::header::{HeaderMap, HeaderValue, ACCEPT, CONTENT_TYPE, HOST};
636     use crate::Method;
637     use serde::Serialize;
638     #[cfg(feature = "json")]
639     use serde_json;
640     use serde_urlencoded;
641     use std::collections::{BTreeMap, HashMap};
642     use std::convert::TryFrom;
643 
644     #[test]
basic_get_request()645     fn basic_get_request() {
646         let client = Client::new();
647         let some_url = "https://google.com/";
648         let r = client.get(some_url).build().unwrap();
649 
650         assert_eq!(r.method(), &Method::GET);
651         assert_eq!(r.url().as_str(), some_url);
652     }
653 
654     #[test]
basic_head_request()655     fn basic_head_request() {
656         let client = Client::new();
657         let some_url = "https://google.com/";
658         let r = client.head(some_url).build().unwrap();
659 
660         assert_eq!(r.method(), &Method::HEAD);
661         assert_eq!(r.url().as_str(), some_url);
662     }
663 
664     #[test]
basic_post_request()665     fn basic_post_request() {
666         let client = Client::new();
667         let some_url = "https://google.com/";
668         let r = client.post(some_url).build().unwrap();
669 
670         assert_eq!(r.method(), &Method::POST);
671         assert_eq!(r.url().as_str(), some_url);
672     }
673 
674     #[test]
basic_put_request()675     fn basic_put_request() {
676         let client = Client::new();
677         let some_url = "https://google.com/";
678         let r = client.put(some_url).build().unwrap();
679 
680         assert_eq!(r.method(), &Method::PUT);
681         assert_eq!(r.url().as_str(), some_url);
682     }
683 
684     #[test]
basic_patch_request()685     fn basic_patch_request() {
686         let client = Client::new();
687         let some_url = "https://google.com/";
688         let r = client.patch(some_url).build().unwrap();
689 
690         assert_eq!(r.method(), &Method::PATCH);
691         assert_eq!(r.url().as_str(), some_url);
692     }
693 
694     #[test]
basic_delete_request()695     fn basic_delete_request() {
696         let client = Client::new();
697         let some_url = "https://google.com/";
698         let r = client.delete(some_url).build().unwrap();
699 
700         assert_eq!(r.method(), &Method::DELETE);
701         assert_eq!(r.url().as_str(), some_url);
702     }
703 
704     #[test]
add_header()705     fn add_header() {
706         let client = Client::new();
707         let some_url = "https://google.com/";
708         let r = client.post(some_url);
709 
710         let header = HeaderValue::from_static("google.com");
711 
712         // Add a copy of the header to the request builder
713         let r = r.header(HOST, header.clone()).build().unwrap();
714 
715         // then check it was actually added
716         assert_eq!(r.headers().get(HOST), Some(&header));
717     }
718 
719     #[test]
add_headers()720     fn add_headers() {
721         let client = Client::new();
722         let some_url = "https://google.com/";
723         let r = client.post(some_url);
724 
725         let header = HeaderValue::from_static("google.com");
726 
727         let mut headers = HeaderMap::new();
728         headers.insert(HOST, header);
729 
730         // Add a copy of the headers to the request builder
731         let r = r.headers(headers.clone()).build().unwrap();
732 
733         // then make sure they were added correctly
734         assert_eq!(r.headers(), &headers);
735     }
736 
737     #[test]
add_headers_multi()738     fn add_headers_multi() {
739         let client = Client::new();
740         let some_url = "https://google.com/";
741         let r = client.post(some_url);
742 
743         let header_json = HeaderValue::from_static("application/json");
744         let header_xml = HeaderValue::from_static("application/xml");
745 
746         let mut headers = HeaderMap::new();
747         headers.append(ACCEPT, header_json);
748         headers.append(ACCEPT, header_xml);
749 
750         // Add a copy of the headers to the request builder
751         let r = r.headers(headers.clone()).build().unwrap();
752 
753         // then make sure they were added correctly
754         assert_eq!(r.headers(), &headers);
755         let mut all_values = r.headers().get_all(ACCEPT).iter();
756         assert_eq!(all_values.next().unwrap(), &"application/json");
757         assert_eq!(all_values.next().unwrap(), &"application/xml");
758         assert_eq!(all_values.next(), None);
759     }
760 
761     #[test]
add_body()762     fn add_body() {
763         let client = Client::new();
764         let some_url = "https://google.com/";
765         let r = client.post(some_url);
766 
767         let body = "Some interesting content";
768 
769         let mut r = r.body(body).build().unwrap();
770 
771         let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
772 
773         assert_eq!(buf, body);
774     }
775 
776     #[test]
add_query_append()777     fn add_query_append() {
778         let client = Client::new();
779         let some_url = "https://google.com/";
780         let mut r = client.get(some_url);
781 
782         r = r.query(&[("foo", "bar")]);
783         r = r.query(&[("qux", 3)]);
784 
785         let req = r.build().expect("request is valid");
786         assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
787     }
788 
789     #[test]
add_query_append_same()790     fn add_query_append_same() {
791         let client = Client::new();
792         let some_url = "https://google.com/";
793         let mut r = client.get(some_url);
794 
795         r = r.query(&[("foo", "a"), ("foo", "b")]);
796 
797         let req = r.build().expect("request is valid");
798         assert_eq!(req.url().query(), Some("foo=a&foo=b"));
799     }
800 
801     #[test]
add_query_struct()802     fn add_query_struct() {
803         #[derive(Serialize)]
804         struct Params {
805             foo: String,
806             qux: i32,
807         }
808 
809         let client = Client::new();
810         let some_url = "https://google.com/";
811         let mut r = client.get(some_url);
812 
813         let params = Params {
814             foo: "bar".into(),
815             qux: 3,
816         };
817 
818         r = r.query(&params);
819 
820         let req = r.build().expect("request is valid");
821         assert_eq!(req.url().query(), Some("foo=bar&qux=3"));
822     }
823 
824     #[test]
add_query_map()825     fn add_query_map() {
826         let mut params = BTreeMap::new();
827         params.insert("foo", "bar");
828         params.insert("qux", "three");
829 
830         let client = Client::new();
831         let some_url = "https://google.com/";
832         let mut r = client.get(some_url);
833 
834         r = r.query(&params);
835 
836         let req = r.build().expect("request is valid");
837         assert_eq!(req.url().query(), Some("foo=bar&qux=three"));
838     }
839 
840     #[test]
add_form()841     fn add_form() {
842         let client = Client::new();
843         let some_url = "https://google.com/";
844         let r = client.post(some_url);
845 
846         let mut form_data = HashMap::new();
847         form_data.insert("foo", "bar");
848 
849         let mut r = r.form(&form_data).build().unwrap();
850 
851         // Make sure the content type was set
852         assert_eq!(
853             r.headers().get(CONTENT_TYPE).unwrap(),
854             &"application/x-www-form-urlencoded"
855         );
856 
857         let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
858 
859         let body_should_be = serde_urlencoded::to_string(&form_data).unwrap();
860         assert_eq!(buf, body_should_be);
861     }
862 
863     #[test]
864     #[cfg(feature = "json")]
add_json()865     fn add_json() {
866         let client = Client::new();
867         let some_url = "https://google.com/";
868         let r = client.post(some_url);
869 
870         let mut json_data = HashMap::new();
871         json_data.insert("foo", "bar");
872 
873         let mut r = r.json(&json_data).build().unwrap();
874 
875         // Make sure the content type was set
876         assert_eq!(r.headers().get(CONTENT_TYPE).unwrap(), &"application/json");
877 
878         let buf = body::read_to_string(r.body_mut().take().unwrap()).unwrap();
879 
880         let body_should_be = serde_json::to_string(&json_data).unwrap();
881         assert_eq!(buf, body_should_be);
882     }
883 
884     #[test]
885     #[cfg(feature = "json")]
add_json_fail()886     fn add_json_fail() {
887         use serde::ser::Error as _;
888         use serde::{Serialize, Serializer};
889         use std::error::Error as _;
890         struct MyStruct;
891         impl Serialize for MyStruct {
892             fn serialize<S>(&self, _serializer: S) -> Result<S::Ok, S::Error>
893             where
894                 S: Serializer,
895             {
896                 Err(S::Error::custom("nope"))
897             }
898         }
899 
900         let client = Client::new();
901         let some_url = "https://google.com/";
902         let r = client.post(some_url);
903         let json_data = MyStruct;
904         let err = r.json(&json_data).build().unwrap_err();
905         assert!(err.is_builder()); // well, duh ;)
906         assert!(err.source().unwrap().is::<serde_json::Error>());
907     }
908 
909     #[test]
test_replace_headers()910     fn test_replace_headers() {
911         use http::HeaderMap;
912 
913         let mut headers = HeaderMap::new();
914         headers.insert("foo", "bar".parse().unwrap());
915         headers.append("foo", "baz".parse().unwrap());
916 
917         let client = Client::new();
918         let req = client
919             .get("https://hyper.rs")
920             .header("im-a", "keeper")
921             .header("foo", "pop me")
922             .headers(headers)
923             .build()
924             .expect("request build");
925 
926         assert_eq!(req.headers()["im-a"], "keeper");
927 
928         let foo = req.headers().get_all("foo").iter().collect::<Vec<_>>();
929         assert_eq!(foo.len(), 2);
930         assert_eq!(foo[0], "bar");
931         assert_eq!(foo[1], "baz");
932     }
933 
934     #[test]
normalize_empty_query()935     fn normalize_empty_query() {
936         let client = Client::new();
937         let some_url = "https://google.com/";
938         let empty_query: &[(&str, &str)] = &[];
939 
940         let req = client
941             .get(some_url)
942             .query(empty_query)
943             .build()
944             .expect("request build");
945 
946         assert_eq!(req.url().query(), None);
947         assert_eq!(req.url().as_str(), "https://google.com/");
948     }
949 
950     #[test]
convert_url_authority_into_basic_auth()951     fn convert_url_authority_into_basic_auth() {
952         let client = Client::new();
953         let some_url = "https://Aladdin:open sesame@localhost/";
954 
955         let req = client
956             .get(some_url)
957             .build()
958             .expect("request build");
959 
960         assert_eq!(req.url().as_str(), "https://localhost/");
961         assert_eq!(req.headers()["authorization"], "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
962     }
963 
964     #[test]
convert_from_http_request()965     fn convert_from_http_request() {
966         let http_request = HttpRequest::builder().method("GET")
967             .uri("http://localhost/")
968             .header("User-Agent", "my-awesome-agent/1.0")
969             .body("test test test")
970             .unwrap();
971         let req: Request = Request::try_from(http_request).unwrap();
972         assert_eq!(req.body().is_none(), false);
973         let test_data = b"test test test";
974         assert_eq!(req.body().unwrap().as_bytes(), Some(&test_data[..]));
975         let headers = req.headers();
976         assert_eq!(headers.get("User-Agent").unwrap(), "my-awesome-agent/1.0");
977         assert_eq!(req.method(), Method::GET);
978         assert_eq!(req.url().as_str(), "http://localhost/");
979     }
980 
981     #[test]
test_basic_auth_sensitive_header()982     fn test_basic_auth_sensitive_header() {
983         let client = Client::new();
984         let some_url = "https://localhost/";
985 
986         let req = client
987             .get(some_url)
988             .basic_auth("Aladdin", Some("open sesame"))
989             .build()
990             .expect("request build");
991 
992         assert_eq!(req.url().as_str(), "https://localhost/");
993         assert_eq!(req.headers()["authorization"], "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==");
994         assert_eq!(req.headers()["authorization"].is_sensitive(), true);
995     }
996 
997     #[test]
test_bearer_auth_sensitive_header()998     fn test_bearer_auth_sensitive_header() {
999         let client = Client::new();
1000         let some_url = "https://localhost/";
1001 
1002         let req = client
1003             .get(some_url)
1004             .bearer_auth("Hold my bear")
1005             .build()
1006             .expect("request build");
1007 
1008         assert_eq!(req.url().as_str(), "https://localhost/");
1009         assert_eq!(req.headers()["authorization"], "Bearer Hold my bear");
1010         assert_eq!(req.headers()["authorization"].is_sensitive(), true);
1011     }
1012 }
1013