1use std::convert::TryFrom;
2use std::fmt;
3use std::time::Duration;
4
5use bytes::Bytes;
6use http::{request::Parts, Method, Request as HttpRequest};
7#[cfg(any(feature = "query", feature = "form", feature = "json"))]
8use serde::Serialize;
9#[cfg(feature = "json")]
10use serde_json;
11use url::Url;
12use web_sys::{RequestCache, RequestCredentials};
13
14use super::{Body, Client, Response};
15#[cfg(any(feature = "form", feature = "json"))]
16use crate::header::CONTENT_TYPE;
17use crate::header::{HeaderMap, HeaderName, HeaderValue};
18
19pub struct Request {
21 method: Method,
22 url: Url,
23 headers: HeaderMap,
24 body: Option<Body>,
25 timeout: Option<Duration>,
26 pub(super) cors: bool,
27 pub(super) credentials: Option<RequestCredentials>,
28 pub(super) cache: Option<RequestCache>,
29}
30
31pub struct RequestBuilder {
33 client: Client,
34 request: crate::Result<Request>,
35}
36
37impl Request {
38 #[inline]
40 pub fn new(method: Method, url: Url) -> Self {
41 Request {
42 method,
43 url,
44 headers: HeaderMap::new(),
45 body: None,
46 timeout: None,
47 cors: true,
48 credentials: None,
49 cache: None,
50 }
51 }
52
53 #[inline]
55 pub fn method(&self) -> &Method {
56 &self.method
57 }
58
59 #[inline]
61 pub fn method_mut(&mut self) -> &mut Method {
62 &mut self.method
63 }
64
65 #[inline]
67 pub fn url(&self) -> &Url {
68 &self.url
69 }
70
71 #[inline]
73 pub fn url_mut(&mut self) -> &mut Url {
74 &mut self.url
75 }
76
77 #[inline]
79 pub fn headers(&self) -> &HeaderMap {
80 &self.headers
81 }
82
83 #[inline]
85 pub fn headers_mut(&mut self) -> &mut HeaderMap {
86 &mut self.headers
87 }
88
89 #[inline]
91 pub fn body(&self) -> Option<&Body> {
92 self.body.as_ref()
93 }
94
95 #[inline]
97 pub fn body_mut(&mut self) -> &mut Option<Body> {
98 &mut self.body
99 }
100
101 #[inline]
103 pub fn timeout(&self) -> Option<&Duration> {
104 self.timeout.as_ref()
105 }
106
107 #[inline]
109 pub fn timeout_mut(&mut self) -> &mut Option<Duration> {
110 &mut self.timeout
111 }
112
113 pub fn try_clone(&self) -> Option<Request> {
117 let body = match self.body.as_ref() {
118 Some(body) => Some(body.try_clone()?),
119 None => None,
120 };
121
122 Some(Self {
123 method: self.method.clone(),
124 url: self.url.clone(),
125 headers: self.headers.clone(),
126 body,
127 timeout: self.timeout,
128 cors: self.cors,
129 credentials: self.credentials,
130 cache: self.cache,
131 })
132 }
133}
134
135impl RequestBuilder {
136 pub(super) fn new(client: Client, request: crate::Result<Request>) -> RequestBuilder {
137 RequestBuilder { client, request }
138 }
139
140 pub fn from_parts(client: crate::Client, request: crate::Request) -> crate::RequestBuilder {
142 crate::RequestBuilder {
143 client,
144 request: crate::Result::Ok(request),
145 }
146 }
147
148 #[cfg(feature = "query")]
171 #[cfg_attr(docsrs, doc(cfg(feature = "query")))]
172 pub fn query<T: Serialize + ?Sized>(mut self, query: &T) -> RequestBuilder {
173 let mut error = None;
174 if let Ok(ref mut req) = self.request {
175 let url = req.url_mut();
176 let mut pairs = url.query_pairs_mut();
177 let serializer = serde_urlencoded::Serializer::new(&mut pairs);
178
179 if let Err(err) = query.serialize(serializer) {
180 error = Some(crate::error::builder(err));
181 }
182 }
183 if let Ok(ref mut req) = self.request {
184 if let Some("") = req.url().query() {
185 req.url_mut().set_query(None);
186 }
187 }
188 if let Some(err) = error {
189 self.request = Err(err);
190 }
191 self
192 }
193
194 #[cfg(feature = "form")]
209 #[cfg_attr(docsrs, doc(cfg(feature = "form")))]
210 pub fn form<T: Serialize + ?Sized>(mut self, form: &T) -> RequestBuilder {
211 let mut error = None;
212 if let Ok(ref mut req) = self.request {
213 match serde_urlencoded::to_string(form) {
214 Ok(body) => {
215 req.headers_mut().insert(
216 CONTENT_TYPE,
217 HeaderValue::from_static("application/x-www-form-urlencoded"),
218 );
219 *req.body_mut() = Some(body.into());
220 }
221 Err(err) => error = Some(crate::error::builder(err)),
222 }
223 }
224 if let Some(err) = error {
225 self.request = Err(err);
226 }
227 self
228 }
229
230 #[cfg(feature = "json")]
231 #[cfg_attr(docsrs, doc(cfg(feature = "json")))]
232 pub fn json<T: Serialize + ?Sized>(mut self, json: &T) -> RequestBuilder {
234 let mut error = None;
235 if let Ok(ref mut req) = self.request {
236 match serde_json::to_vec(json) {
237 Ok(body) => {
238 req.headers_mut()
239 .entry(CONTENT_TYPE)
240 .or_insert_with(|| HeaderValue::from_static("application/json"));
241 *req.body_mut() = Some(body.into());
242 }
243 Err(err) => error = Some(crate::error::builder(err)),
244 }
245 }
246 if let Some(err) = error {
247 self.request = Err(err);
248 }
249 self
250 }
251
252 pub fn basic_auth<U, P>(self, username: U, password: Option<P>) -> RequestBuilder
254 where
255 U: fmt::Display,
256 P: fmt::Display,
257 {
258 let header_value = crate::util::basic_auth(username, password);
259 self.header(crate::header::AUTHORIZATION, header_value)
260 }
261
262 pub fn bearer_auth<T>(self, token: T) -> RequestBuilder
264 where
265 T: fmt::Display,
266 {
267 let header_value = format!("Bearer {token}");
268 self.header(crate::header::AUTHORIZATION, header_value)
269 }
270
271 pub fn body<T: Into<Body>>(mut self, body: T) -> RequestBuilder {
273 if let Ok(ref mut req) = self.request {
274 req.body = Some(body.into());
275 }
276 self
277 }
278
279 pub fn timeout(mut self, timeout: Duration) -> RequestBuilder {
281 if let Ok(ref mut req) = self.request {
282 *req.timeout_mut() = Some(timeout);
283 }
284 self
285 }
286
287 #[cfg(feature = "multipart")]
289 #[cfg_attr(docsrs, doc(cfg(feature = "multipart")))]
290 pub fn multipart(mut self, multipart: super::multipart::Form) -> RequestBuilder {
291 if let Ok(ref mut req) = self.request {
292 *req.body_mut() = Some(Body::from_form(multipart))
293 }
294 self
295 }
296
297 pub fn header<K, V>(mut self, key: K, value: V) -> RequestBuilder
299 where
300 HeaderName: TryFrom<K>,
301 <HeaderName as TryFrom<K>>::Error: Into<http::Error>,
302 HeaderValue: TryFrom<V>,
303 <HeaderValue as TryFrom<V>>::Error: Into<http::Error>,
304 {
305 let mut error = None;
306 if let Ok(ref mut req) = self.request {
307 match <HeaderName as TryFrom<K>>::try_from(key) {
308 Ok(key) => match <HeaderValue as TryFrom<V>>::try_from(value) {
309 Ok(value) => {
310 req.headers_mut().append(key, value);
311 }
312 Err(e) => error = Some(crate::error::builder(e.into())),
313 },
314 Err(e) => error = Some(crate::error::builder(e.into())),
315 };
316 }
317 if let Some(err) = error {
318 self.request = Err(err);
319 }
320 self
321 }
322
323 pub fn headers(mut self, headers: crate::header::HeaderMap) -> RequestBuilder {
327 if let Ok(ref mut req) = self.request {
328 crate::util::replace_headers(req.headers_mut(), headers);
329 }
330 self
331 }
332
333 pub fn fetch_mode_no_cors(mut self) -> RequestBuilder {
343 if let Ok(ref mut req) = self.request {
344 req.cors = false;
345 }
346 self
347 }
348
349 pub fn fetch_credentials_same_origin(mut self) -> RequestBuilder {
359 if let Ok(ref mut req) = self.request {
360 req.credentials = Some(RequestCredentials::SameOrigin);
361 }
362 self
363 }
364
365 pub fn fetch_credentials_include(mut self) -> RequestBuilder {
375 if let Ok(ref mut req) = self.request {
376 req.credentials = Some(RequestCredentials::Include);
377 }
378 self
379 }
380
381 pub fn fetch_credentials_omit(mut self) -> RequestBuilder {
391 if let Ok(ref mut req) = self.request {
392 req.credentials = Some(RequestCredentials::Omit);
393 }
394 self
395 }
396
397 pub fn fetch_cache_default(mut self) -> RequestBuilder {
407 if let Ok(ref mut req) = self.request {
408 req.cache = Some(RequestCache::Default);
409 }
410 self
411 }
412
413 pub fn fetch_cache_no_store(mut self) -> RequestBuilder {
423 if let Ok(ref mut req) = self.request {
424 req.cache = Some(RequestCache::NoStore);
425 }
426 self
427 }
428
429 pub fn fetch_cache_reload(mut self) -> RequestBuilder {
439 if let Ok(ref mut req) = self.request {
440 req.cache = Some(RequestCache::Reload);
441 }
442 self
443 }
444
445 pub fn fetch_cache_no_cache(mut self) -> RequestBuilder {
455 if let Ok(ref mut req) = self.request {
456 req.cache = Some(RequestCache::NoCache);
457 }
458 self
459 }
460
461 pub fn fetch_cache_force_cache(mut self) -> RequestBuilder {
471 if let Ok(ref mut req) = self.request {
472 req.cache = Some(RequestCache::ForceCache);
473 }
474 self
475 }
476
477 pub fn fetch_cache_only_if_cached(mut self) -> RequestBuilder {
487 if let Ok(ref mut req) = self.request {
488 req.cache = Some(RequestCache::OnlyIfCached);
489 }
490 self
491 }
492
493 pub fn build(self) -> crate::Result<Request> {
496 self.request
497 }
498
499 pub fn build_split(self) -> (Client, crate::Result<Request>) {
505 (self.client, self.request)
506 }
507
508 pub async fn send(self) -> crate::Result<Response> {
529 let req = self.request?;
530 self.client.execute_request(req).await
531 }
532
533 pub fn try_clone(&self) -> Option<RequestBuilder> {
552 self.request
553 .as_ref()
554 .ok()
555 .and_then(|req| req.try_clone())
556 .map(|req| RequestBuilder {
557 client: self.client.clone(),
558 request: Ok(req),
559 })
560 }
561}
562
563impl fmt::Debug for Request {
564 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
565 fmt_request_fields(&mut f.debug_struct("Request"), self).finish()
566 }
567}
568
569impl fmt::Debug for RequestBuilder {
570 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
571 let mut builder = f.debug_struct("RequestBuilder");
572 match self.request {
573 Ok(ref req) => fmt_request_fields(&mut builder, req).finish(),
574 Err(ref err) => builder.field("error", err).finish(),
575 }
576 }
577}
578
579fn fmt_request_fields<'a, 'b>(
580 f: &'a mut fmt::DebugStruct<'a, 'b>,
581 req: &Request,
582) -> &'a mut fmt::DebugStruct<'a, 'b> {
583 f.field("method", &req.method)
584 .field("url", &req.url)
585 .field("headers", &req.headers)
586}
587
588impl<T> TryFrom<HttpRequest<T>> for Request
589where
590 T: Into<Body>,
591{
592 type Error = crate::Error;
593
594 fn try_from(req: HttpRequest<T>) -> crate::Result<Self> {
595 let (parts, body) = req.into_parts();
596 let Parts {
597 method,
598 uri,
599 headers,
600 ..
601 } = parts;
602 let url = Url::parse(&uri.to_string()).map_err(crate::error::builder)?;
603 Ok(Request {
604 method,
605 url,
606 headers,
607 body: Some(body.into()),
608 timeout: None,
609 cors: true,
610 credentials: None,
611 cache: None,
612 })
613 }
614}
615
616impl TryFrom<Request> for HttpRequest<Body> {
617 type Error = crate::Error;
618
619 fn try_from(req: Request) -> crate::Result<Self> {
620 let Request {
621 method,
622 url,
623 headers,
624 body,
625 ..
626 } = req;
627
628 let mut req = HttpRequest::builder()
629 .method(method)
630 .uri(url.as_str())
631 .body(body.unwrap_or_else(|| Body::from(Bytes::default())))
632 .map_err(crate::error::builder)?;
633
634 *req.headers_mut() = headers;
635 Ok(req)
636 }
637}