1use http::header::CONTENT_TYPE;
2use http::{HeaderMap, HeaderName, HeaderValue, Method, Version};
3use serde::Serialize;
4#[cfg(feature = "json")]
5use serde_json;
6use std::convert::TryFrom;
7use std::fmt;
8use std::time::Duration;
9use url::Url;
10
11use super::body::Body;
12use super::client::Client;
13
14#[derive(Debug)]
16pub struct Request {
17 method: Method,
18 url: Url,
19 headers: HeaderMap,
20 body: Option<Body>,
21 timeout: Option<Duration>,
22 version: Version,
23}
24
25#[must_use = "RequestBuilder does nothing until you 'send' it"]
29#[derive(Debug)]
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 Self {
40 method,
41 url,
42 headers: HeaderMap::new(),
43 version: Version::default(),
44 timeout: None,
45 body: None,
46 }
47 }
48
49 #[inline]
51 pub fn method(&self) -> &Method {
52 &self.method
53 }
54
55 #[inline]
57 pub fn method_mut(&mut self) -> &mut Method {
58 &mut self.method
59 }
60
61 #[inline]
63 pub fn url(&self) -> &Url {
64 &self.url
65 }
66
67 #[inline]
69 pub fn url_mut(&mut self) -> &mut Url {
70 &mut self.url
71 }
72
73 #[inline]
75 pub fn headers(&self) -> &HeaderMap {
76 &self.headers
77 }
78
79 #[inline]
81 pub fn headers_mut(&mut self) -> &mut HeaderMap {
82 &mut self.headers
83 }
84
85 #[inline]
87 pub fn body(&self) -> Option<&Body> {
88 self.body.as_ref()
89 }
90
91 #[inline]
93 pub fn body_mut(&mut self) -> &mut Option<Body> {
94 &mut self.body
95 }
96
97 #[inline]
99 pub fn timeout(&self) -> Option<&Duration> {
100 self.timeout.as_ref()
101 }
102
103 #[inline]
105 pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
106 &mut self.timeout
107 }
108
109 #[inline]
111 pub fn version(&self) -> Version {
112 self.version
113 }
114
115 #[inline]
117 pub fn version_mut(&mut self) -> &mut Version {
118 &mut self.version
119 }
120
121 pub fn try_clone(&self) -> Option<Request> {
125 let body = match self.body.as_ref() {
126 Some(body) => Some(body.try_clone()?),
127 None => None,
128 };
129 let mut req = Request::new(self.method().clone(), self.url().clone());
130 *req.timeout_mut() = self.timeout().copied();
131 *req.headers_mut() = self.headers().clone();
132 *req.version_mut() = self.version();
133 req.body = body;
134 Some(req)
135 }
136
137 pub(crate) fn pieces(
138 self,
139 ) -> (
140 Method,
141 Url,
142 HeaderMap,
143 Option<Body>,
144 Option<Duration>,
145 Version,
146 ) {
147 (
148 self.method,
149 self.url,
150 self.headers,
151 self.body,
152 self.timeout,
153 self.version,
154 )
155 }
156}
157
158impl RequestBuilder {
159 pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
160 let mut builder = Self { client, request };
161
162 let auth = builder
163 .request
164 .as_mut()
165 .ok()
166 .and_then(|req| extract_authority(&mut req.url));
167
168 if let Some((username, password)) = auth {
169 builder.basic_auth(username, password)
170 } else {
171 builder
172 }
173 }
174
175 #[cfg(not(feature = "async"))]
182 pub fn send(self) -> crate::Result<super::Response> {
183 self.client.execute(self.request?)
184 }
185
186 #[cfg(feature = "async")]
193 pub async fn send(self) -> crate::Result<super::Response> {
194 self.client.execute(self.request?).await
195 }
196
197 pub fn from_parts(client: Client, request: Request) -> RequestBuilder {
199 RequestBuilder {
200 client,
201 request: Ok(request),
202 }
203 }
204
205 pub fn header<K, V>(self, key: K, value: V) -> RequestBuilder
207 where
208 HeaderName: TryFrom<K>,
209 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
210 HeaderValue: TryFrom<V>,
211 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
212 {
213 self.header_sensitive(key, value, false)
214 }
215
216 fn header_sensitive<K, V>(mut self, key: K, value: V, sensitive: bool) -> RequestBuilder
218 where
219 HeaderName: TryFrom<K>,
220 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
221 HeaderValue: TryFrom<V>,
222 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
223 {
224 let mut error = None;
225 if let Ok(ref mut req) = self.request {
226 match <HeaderName as TryFrom<K>>::try_from(key) {
227 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
228 Ok(mut value) => {
229 if sensitive {
233 value.set_sensitive(true);
234 }
235 req.headers_mut().append(key, value);
236 }
237 Err(e) => error = Some(crate::error::builder(e.into())),
238 },
239 Err(e) => error = Some(crate::error::builder(e.into())),
240 };
241 }
242 if let Some(err) = error {
243 self.request = Err(err);
244 }
245 self
246 }
247
248 pub fn headers(mut self, headers: HeaderMap) -> RequestBuilder {
252 if let Ok(ref mut req) = self.request {
253 crate::util::replace_headers(req.headers_mut(), headers);
254 }
255 self
256 }
257
258 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
260 where
261 U: fmt::Display,
262 P: fmt::Display,
263 {
264 let header_value = crate::util::basic_auth(username, password);
265 self.header_sensitive(crate::header::AUTHORIZATION, header_value, true)
266 }
267
268 pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
270 where
271 T: fmt::Display,
272 {
273 let header_value = format!("Bearer {}", token);
274 self.header_sensitive(crate::header::AUTHORIZATION, header_value, true)
275 }
276
277 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
279 if let Ok(ref mut req) = self.request {
280 *req.body_mut() = Some(body.into());
281 }
282 self
283 }
284
285 pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
291 if let Ok(ref mut req) = self.request {
292 *req.timeout_mut() = Some(timeout);
293 }
294 self
295 }
296
297 #[cfg(feature = "multipart")]
299 #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
300 pub fn multipart(self, mut multipart: crate::multipart::Form) -> RequestBuilder {
301 let mut builder = self.header(
302 CONTENT_TYPE,
303 format!("multipart/form-data; boundary={}", multipart.boundary()).as_str(),
304 );
305 if let Ok(ref mut req) = builder.request {
306 *req.body_mut() = Some(match multipart.compute_length() {
307 Some(length) => Body::sized(multipart.reader(), length),
308 None => Body::new(multipart.reader()),
309 })
310 }
311 builder
312 }
313
314 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
333 let mut error = None;
334 if let Ok(ref mut req) = self.request {
335 let url = req.url_mut();
336 let mut pairs = url.query_pairs_mut();
337 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
338
339 if let Err(err) = query.serialize(serializer) {
340 error = Some(crate::error::builder(err));
341 }
342 }
343 if let Ok(ref mut req) = self.request {
344 if let Some("") = req.url().query() {
345 req.url_mut().set_query(None);
346 }
347 }
348 if let Some(err) = error {
349 self.request = Err(err);
350 }
351 self
352 }
353
354 pub fn version(mut self, version: Version) -> RequestBuilder {
356 if let Ok(ref mut req) = self.request {
357 req.version = version;
358 }
359 self
360 }
361
362 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
373 let mut error = None;
374 if let Ok(ref mut req) = self.request {
375 match serde_urlencoded::to_string(form) {
376 Ok(body) => {
377 req.headers_mut().insert(
378 CONTENT_TYPE,
379 HeaderValue::from_static("application/x-www-form-urlencoded"),
380 );
381 *req.body_mut() = Some(body.into());
382 }
383 Err(err) => error = Some(crate::error::builder(err)),
384 }
385 }
386 if let Some(err) = error {
387 self.request = Err(err);
388 }
389 self
390 }
391
392 #[cfg(feature = "json")]
403 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
404 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
405 let mut error = None;
406 if let Ok(ref mut req) = self.request {
407 match serde_json::to_vec(json) {
408 Ok(body) => {
409 if !req.headers().contains_key(CONTENT_TYPE) {
410 req.headers_mut()
411 .insert(CONTENT_TYPE, HeaderValue::from_static("application/json"));
412 }
413 *req.body_mut() = Some(body.into());
414 }
415 Err(err) => error = Some(crate::error::builder(err)),
416 }
417 }
418 if let Some(err) = error {
419 self.request = Err(err);
420 }
421 self
422 }
423
424 pub fn fetch_mode_no_cors(self) -> RequestBuilder {
434 self
435 }
436
437 pub fn build(self) -> crate::Result<Request> {
440 self.request
441 }
442
443 pub fn build_split(self) -> (Client, crate::Result<Request>) {
449 (self.client, self.request)
450 }
451
452 pub fn try_clone(&self) -> Option<RequestBuilder> {
458 self.request
459 .as_ref()
460 .ok()
461 .and_then(|req| req.try_clone())
462 .map(|req| RequestBuilder {
463 client: self.client.clone(),
464 request: Ok(req),
465 })
466 }
467}
468
469pub(crate) fn extract_authority(url: &mut Url) -> Option<(String, Option<String>)> {
472 use percent_encoding::percent_decode;
473
474 if url.has_authority() {
475 let username: String = percent_decode(url.username().as_bytes())
476 .decode_utf8()
477 .ok()?
478 .into();
479 let password = url.password().and_then(|pass| {
480 percent_decode(pass.as_bytes())
481 .decode_utf8()
482 .ok()
483 .map(String::from)
484 });
485 if !username.is_empty() || password.is_some() {
486 url.set_username("")
487 .expect("has_authority means set_username shouldn't fail");
488 url.set_password(None)
489 .expect("has_authority means set_password shouldn't fail");
490 return Some((username, password));
491 }
492 }
493
494 None
495}