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