axol_http/
request.rs

1use std::{any::Any, convert::Infallible};
2
3use http::Error as HttpError;
4use thiserror::Error;
5
6use crate::{header::HeaderMap, method::MethodParseError, Body, Extensions, Method, Uri, Version};
7
8/// Represents an HTTP request.
9///
10/// An HTTP request consists of a head and a optional body.
11///
12/// # Examples
13///
14/// Creating a `Request` to send
15///
16/// ```no_run
17/// use axol_http::{Request, Response};
18///
19/// let mut request = Request::builder()
20///     .uri("https://www.rust-lang.org/")
21///     .header("User-Agent", "my-awesome-agent/1.0");
22///
23/// if needs_awesome_header() {
24///     request = request.header("Awesome", "yes");
25/// }
26///
27/// let response = send(request.body(()).unwrap());
28///
29/// # fn needs_awesome_header() -> bool {
30/// #     true
31/// # }
32/// #
33/// fn send(req: Request<()>) -> Response<()> {
34///     // ...
35/// # panic!()
36/// }
37/// ```
38///
39/// Inspecting a request to see what was sent.
40///
41/// ```
42/// use axol_http::{Request, Response, StatusCode};
43///
44/// fn respond_to(req: Request<()>) -> axol_http::Result<Response<()>> {
45///     if req.uri() != "/awesome-url" {
46///         return Response::builder()
47///             .status(StatusCode::NOT_FOUND)
48///             .body(())
49///     }
50///
51///     let has_awesome_header = req.headers().contains_key("Awesome");
52///     let body = req.body();
53///
54///     // ...
55/// # panic!()
56/// }
57/// ```
58///
59/// Deserialize a request of bytes via json:
60///
61/// ```
62/// # extern crate serde;
63/// # extern crate serde_json;
64/// # extern crate http;
65/// use axol_http::Request;
66/// use serde::de;
67///
68/// fn deserialize<T>(req: Request<Vec<u8>>) -> serde_json::Result<Request<T>>
69///     where for<'de> T: de::Deserialize<'de>,
70/// {
71///     let (parts, body) = req.into_parts();
72///     let body = serde_json::from_slice(&body)?;
73///     Ok(Request::from_parts(parts, body))
74/// }
75/// #
76/// # fn main() {}
77/// ```
78///
79/// Or alternatively, serialize the body of a request to json
80///
81/// ```
82/// # extern crate serde;
83/// # extern crate serde_json;
84/// # extern crate http;
85/// use axol_http::Request;
86/// use serde::ser;
87///
88/// fn serialize<T>(req: Request<T>) -> serde_json::Result<Request<Vec<u8>>>
89///     where T: ser::Serialize,
90/// {
91///     let (parts, body) = req.into_parts();
92///     let body = serde_json::to_vec(&body)?;
93///     Ok(Request::from_parts(parts, body))
94/// }
95/// #
96/// # fn main() {}
97/// ```
98#[derive(Debug, Default)]
99pub struct Request {
100    /// The request's method
101    pub method: Method,
102
103    /// The request's URI
104    pub uri: Uri,
105
106    /// The request's version
107    pub version: Version,
108
109    /// The request's headers. All headers are always lowercased.
110    pub headers: HeaderMap,
111
112    /// The request's extensions
113    pub extensions: Extensions,
114
115    /// The request's body
116    pub body: Body,
117}
118
119/// Component parts of an HTTP `Request`
120///
121/// The HTTP request head consists of a method, uri, version, and a set of
122/// header fields.
123#[derive(Debug, Default)]
124pub struct RequestParts {
125    /// The request's method
126    pub method: Method,
127
128    /// The request's URI
129    pub uri: Uri,
130
131    /// The request's version
132    pub version: Version,
133
134    /// The request's headers. All headers are always lowercased.
135    pub headers: HeaderMap,
136
137    /// The request's extensions
138    pub extensions: Extensions,
139}
140
141impl RequestParts {
142    pub fn as_ref(&self) -> RequestPartsRef<'_> {
143        RequestPartsRef {
144            method: self.method,
145            uri: &self.uri,
146            version: self.version,
147            headers: &self.headers,
148            extensions: &self.extensions,
149        }
150    }
151}
152
153#[derive(Debug, Clone, Copy)]
154pub struct RequestPartsRef<'a> {
155    /// The request's method
156    pub method: Method,
157
158    /// The request's URI
159    pub uri: &'a Uri,
160
161    /// The request's version
162    pub version: Version,
163
164    /// The request's headers. All headers are always lowercased.
165    pub headers: &'a HeaderMap,
166
167    /// The request's extensions.
168    pub extensions: &'a Extensions,
169}
170
171impl<'a> RequestPartsRef<'a> {
172    pub fn into_owned(&self) -> RequestParts {
173        RequestParts {
174            method: self.method,
175            uri: self.uri.clone(),
176            version: self.version,
177            headers: self.headers.clone(),
178            extensions: self.extensions.clone(),
179        }
180    }
181}
182
183impl Request {
184    pub fn parts(&self) -> RequestPartsRef<'_> {
185        RequestPartsRef {
186            method: self.method,
187            uri: &self.uri,
188            version: self.version,
189            headers: &self.headers,
190            extensions: &self.extensions,
191        }
192    }
193
194    /// Creates a new builder-style object to manufacture a `Request`
195    ///
196    /// This method returns an instance of `Builder` which can be used to
197    /// create a `Request`.
198    ///
199    /// # Examples
200    ///
201    /// ```
202    /// # use axol_http::*;
203    /// let request = Request::builder()
204    ///     .method("GET")
205    ///     .uri("https://www.rust-lang.org/")
206    ///     .header("X-Custom-Foo", "Bar")
207    ///     .body(())
208    ///     .unwrap();
209    /// ```
210    pub fn builder() -> Builder {
211        Builder::new()
212    }
213
214    /// Creates a new `Builder` initialized with a GET method and the given URI.
215    ///
216    /// This method returns an instance of `Builder` which can be used to
217    /// create a `Request`.
218    ///
219    /// # Example
220    ///
221    /// ```
222    /// # use axol_http::*;
223    ///
224    /// let request = Request::get("https://www.rust-lang.org/")
225    ///     .body(())
226    ///     .unwrap();
227    /// ```
228    pub fn get<T>(uri: T) -> Builder
229    where
230        Uri: TryFrom<T>,
231        <Uri as TryFrom<T>>::Error: Into<HttpError>,
232    {
233        Builder::new().method(Method::Get).uri(uri)
234    }
235
236    /// Creates a new `Builder` initialized with a PUT method and the given URI.
237    ///
238    /// This method returns an instance of `Builder` which can be used to
239    /// create a `Request`.
240    ///
241    /// # Example
242    ///
243    /// ```
244    /// # use axol_http::*;
245    ///
246    /// let request = Request::put("https://www.rust-lang.org/")
247    ///     .body(())
248    ///     .unwrap();
249    /// ```
250    pub fn put<T>(uri: T) -> Builder
251    where
252        Uri: TryFrom<T>,
253        <Uri as TryFrom<T>>::Error: Into<HttpError>,
254    {
255        Builder::new().method(Method::Put).uri(uri)
256    }
257
258    /// Creates a new `Builder` initialized with a POST method and the given URI.
259    ///
260    /// This method returns an instance of `Builder` which can be used to
261    /// create a `Request`.
262    ///
263    /// # Example
264    ///
265    /// ```
266    /// # use axol_http::*;
267    ///
268    /// let request = Request::post("https://www.rust-lang.org/")
269    ///     .body(())
270    ///     .unwrap();
271    /// ```
272    pub fn post<T>(uri: T) -> Builder
273    where
274        Uri: TryFrom<T>,
275        <Uri as TryFrom<T>>::Error: Into<HttpError>,
276    {
277        Builder::new().method(Method::Post).uri(uri)
278    }
279
280    /// Creates a new `Builder` initialized with a DELETE method and the given URI.
281    ///
282    /// This method returns an instance of `Builder` which can be used to
283    /// create a `Request`.
284    ///
285    /// # Example
286    ///
287    /// ```
288    /// # use axol_http::*;
289    ///
290    /// let request = Request::delete("https://www.rust-lang.org/")
291    ///     .body(())
292    ///     .unwrap();
293    /// ```
294    pub fn delete<T>(uri: T) -> Builder
295    where
296        Uri: TryFrom<T>,
297        <Uri as TryFrom<T>>::Error: Into<HttpError>,
298    {
299        Builder::new().method(Method::Delete).uri(uri)
300    }
301
302    /// Creates a new `Builder` initialized with an OPTIONS method and the given URI.
303    ///
304    /// This method returns an instance of `Builder` which can be used to
305    /// create a `Request`.
306    ///
307    /// # Example
308    ///
309    /// ```
310    /// # use axol_http::*;
311    ///
312    /// let request = Request::options("https://www.rust-lang.org/")
313    ///     .body(())
314    ///     .unwrap();
315    /// # assert_eq!(*request.method(), Method::OPTIONS);
316    /// ```
317    pub fn options<T>(uri: T) -> Builder
318    where
319        Uri: TryFrom<T>,
320        <Uri as TryFrom<T>>::Error: Into<HttpError>,
321    {
322        Builder::new().method(Method::Options).uri(uri)
323    }
324
325    /// Creates a new `Builder` initialized with a HEAD method and the given URI.
326    ///
327    /// This method returns an instance of `Builder` which can be used to
328    /// create a `Request`.
329    ///
330    /// # Example
331    ///
332    /// ```
333    /// # use axol_http::*;
334    ///
335    /// let request = Request::head("https://www.rust-lang.org/")
336    ///     .body(())
337    ///     .unwrap();
338    /// ```
339    pub fn head<T>(uri: T) -> Builder
340    where
341        Uri: TryFrom<T>,
342        <Uri as TryFrom<T>>::Error: Into<HttpError>,
343    {
344        Builder::new().method(Method::Head).uri(uri)
345    }
346
347    /// Creates a new `Builder` initialized with a CONNECT method and the given URI.
348    ///
349    /// This method returns an instance of `Builder` which can be used to
350    /// create a `Request`.
351    ///
352    /// # Example
353    ///
354    /// ```
355    /// # use axol_http::*;
356    ///
357    /// let request = Request::connect("https://www.rust-lang.org/")
358    ///     .body(())
359    ///     .unwrap();
360    /// ```
361    pub fn connect<T>(uri: T) -> Builder
362    where
363        Uri: TryFrom<T>,
364        <Uri as TryFrom<T>>::Error: Into<HttpError>,
365    {
366        Builder::new().method(Method::Connect).uri(uri)
367    }
368
369    /// Creates a new `Builder` initialized with a PATCH method and the given URI.
370    ///
371    /// This method returns an instance of `Builder` which can be used to
372    /// create a `Request`.
373    ///
374    /// # Example
375    ///
376    /// ```
377    /// # use axol_http::*;
378    ///
379    /// let request = Request::patch("https://www.rust-lang.org/")
380    ///     .body(())
381    ///     .unwrap();
382    /// ```
383    pub fn patch<T>(uri: T) -> Builder
384    where
385        Uri: TryFrom<T>,
386        <Uri as TryFrom<T>>::Error: Into<HttpError>,
387    {
388        Builder::new().method(Method::Patch).uri(uri)
389    }
390
391    /// Creates a new `Builder` initialized with a TRACE method and the given URI.
392    ///
393    /// This method returns an instance of `Builder` which can be used to
394    /// create a `Request`.
395    ///
396    /// # Example
397    ///
398    /// ```
399    /// # use axol_http::*;
400    ///
401    /// let request = Request::trace("https://www.rust-lang.org/")
402    ///     .body(())
403    ///     .unwrap();
404    /// ```
405    pub fn trace<T>(uri: T) -> Builder
406    where
407        Uri: TryFrom<T>,
408        <Uri as TryFrom<T>>::Error: Into<HttpError>,
409    {
410        Builder::new().method(Method::Trace).uri(uri)
411    }
412
413    /// Creates a new blank `Request` with the body
414    ///
415    /// The component parts of this request will be set to their default, e.g.
416    /// the GET method, no headers, etc.
417    ///
418    /// # Examples
419    ///
420    /// ```
421    /// # use axol_http::*;
422    /// let request = Request::new("hello world");
423    ///
424    /// assert_eq!(*request.method(), Method::GET);
425    /// assert_eq!(*request.body(), "hello world");
426    /// ```
427    pub fn new(body: impl Into<Body>) -> Request {
428        Self::from_parts(Default::default(), body)
429    }
430
431    /// Creates a new `Request` with the given components parts and body.
432    ///
433    /// # Examples
434    ///
435    /// ```
436    /// # use axol_http::*;
437    /// let request = Request::new("hello world");
438    /// let (mut parts, body) = request.into_parts();
439    /// parts.method = Method::POST;
440    ///
441    /// let request = Request::from_parts(parts, body);
442    /// ```
443    pub fn from_parts(parts: RequestParts, body: impl Into<Body>) -> Request {
444        Request {
445            method: parts.method,
446            uri: parts.uri,
447            version: parts.version,
448            headers: parts.headers,
449            extensions: parts.extensions,
450            body: body.into(),
451        }
452    }
453
454    /// Consumes the request returning the head and body parts.
455    ///
456    /// # Examples
457    ///
458    /// ```
459    /// # use axol_http::*;
460    /// let request = Request::new(());
461    /// let (parts, body) = request.into_parts();
462    /// assert_eq!(parts.method, Method::GET);
463    /// ```
464    pub fn into_parts(self) -> (RequestParts, Body) {
465        (
466            RequestParts {
467                method: self.method,
468                uri: self.uri,
469                version: self.version,
470                headers: self.headers,
471                extensions: self.extensions,
472            },
473            self.body,
474        )
475    }
476}
477
478#[derive(Error, Debug)]
479pub enum RequestBuilderError {
480    #[error("")]
481    Infallible(#[from] Infallible),
482    #[error("method parse error: {0}")]
483    MethodParse(#[from] MethodParseError),
484    #[error("http error: {0}")]
485    Http(#[from] HttpError),
486}
487
488/// An HTTP request builder
489///
490/// This type can be used to construct an instance or `Request`
491/// through a builder-like pattern.
492#[derive(Debug)]
493pub struct Builder {
494    inner: Result<Request, RequestBuilderError>,
495}
496
497impl Builder {
498    /// Creates a new default instance of `Builder` to construct a `Request`.
499    ///
500    /// # Examples
501    ///
502    /// ```
503    /// # use axol_http::*;
504    ///
505    /// let req = request::Builder::new()
506    ///     .method("POST")
507    ///     .body(())
508    ///     .unwrap();
509    /// ```
510    pub fn new() -> Builder {
511        Builder::default()
512    }
513
514    /// Set the HTTP method for this request.
515    ///
516    /// This function will configure the HTTP method of the `Request` that will
517    /// be returned from `Builder::build`.
518    ///
519    /// By default this is `GET`.
520    ///
521    /// # Examples
522    ///
523    /// ```
524    /// # use axol_http::*;
525    ///
526    /// let req = Request::builder()
527    ///     .method("POST")
528    ///     .body(())
529    ///     .unwrap();
530    /// ```
531    pub fn method(self, method: Method) -> Builder {
532        self.and_then(move |mut head| {
533            head.method = method;
534            Ok(head)
535        })
536    }
537
538    /// Get the HTTP Method for this request.
539    ///
540    /// By default this is `GET`. If builder has error, returns None.
541    ///
542    /// # Examples
543    ///
544    /// ```
545    /// # use axol_http::*;
546    ///
547    /// let mut req = Request::builder();
548    /// assert_eq!(req.method_ref(),Some(&Method::GET));
549    ///
550    /// req = req.method("POST");
551    /// assert_eq!(req.method_ref(),Some(&Method::POST));
552    /// ```
553    pub fn method_ref(&self) -> Option<Method> {
554        self.inner.as_ref().ok().map(|h| h.method)
555    }
556
557    /// Set the URI for this request.
558    ///
559    /// This function will configure the URI of the `Request` that will
560    /// be returned from `Builder::build`.
561    ///
562    /// By default this is `/`.
563    ///
564    /// # Examples
565    ///
566    /// ```
567    /// # use axol_http::*;
568    ///
569    /// let req = Request::builder()
570    ///     .uri("https://www.rust-lang.org/")
571    ///     .body(())
572    ///     .unwrap();
573    /// ```
574    pub fn uri<T>(self, uri: T) -> Builder
575    where
576        Uri: TryFrom<T>,
577        <Uri as TryFrom<T>>::Error: Into<HttpError>,
578    {
579        self.and_then(move |mut head| {
580            head.uri = TryFrom::try_from(uri).map_err(Into::into)?;
581            Ok(head)
582        })
583    }
584
585    /// Get the URI for this request
586    ///
587    /// By default this is `/`.
588    ///
589    /// # Examples
590    ///
591    /// ```
592    /// # use axol_http::*;
593    ///
594    /// let mut req = Request::builder();
595    /// assert_eq!(req.uri_ref().unwrap(), "/" );
596    ///
597    /// req = req.uri("https://www.rust-lang.org/");
598    /// assert_eq!(req.uri_ref().unwrap(), "https://www.rust-lang.org/" );
599    /// ```
600    pub fn uri_ref(&self) -> Option<&Uri> {
601        self.inner.as_ref().ok().map(|h| &h.uri)
602    }
603
604    /// Set the HTTP version for this request.
605    ///
606    /// This function will configure the HTTP version of the `Request` that
607    /// will be returned from `Builder::build`.
608    ///
609    /// By default this is HTTP/1.1
610    ///
611    /// # Examples
612    ///
613    /// ```
614    /// # use axol_http::*;
615    ///
616    /// let req = Request::builder()
617    ///     .version(Version::HTTP_2)
618    ///     .body(())
619    ///     .unwrap();
620    /// ```
621    pub fn version(self, version: Version) -> Builder {
622        self.and_then(move |mut head| {
623            head.version = version;
624            Ok(head)
625        })
626    }
627
628    /// Get the HTTP version for this request
629    ///
630    /// By default this is HTTP/1.1.
631    ///
632    /// # Examples
633    ///
634    /// ```
635    /// # use axol_http::*;
636    ///
637    /// let mut req = Request::builder();
638    /// assert_eq!(req.version_ref().unwrap(), &Version::HTTP_11 );
639    ///
640    /// req = req.version(Version::HTTP_2);
641    /// assert_eq!(req.version_ref().unwrap(), &Version::HTTP_2 );
642    /// ```
643    pub fn version_ref(&self) -> Option<&Version> {
644        self.inner.as_ref().ok().map(|h| &h.version)
645    }
646
647    /// Appends a header to this request builder.
648    ///
649    /// This function will append the provided key/value as a header to the
650    /// internal `HeaderMap` being constructed. Essentially this is equivalent
651    /// to calling `HeaderMap::append`.
652    ///
653    /// # Examples
654    ///
655    /// ```
656    /// # use axol_http::*;
657    /// # use axol_http::header::HeaderValue;
658    ///
659    /// let req = Request::builder()
660    ///     .header("Accept", "text/html")
661    ///     .header("X-Custom-Foo", "bar")
662    ///     .body(())
663    ///     .unwrap();
664    /// ```
665    pub fn header(self, name: impl AsRef<str>, value: impl Into<String>) -> Builder {
666        self.and_then(move |mut head| {
667            head.headers.insert(name, value);
668            Ok(head)
669        })
670    }
671
672    /// Get header on this request builder.
673    /// when builder has error returns None
674    ///
675    /// # Example
676    ///
677    /// ```
678    /// # use axol_http::Request;
679    /// let req = Request::builder()
680    ///     .header("Accept", "text/html")
681    ///     .header("X-Custom-Foo", "bar");
682    /// let headers = req.headers_ref().unwrap();
683    /// assert_eq!( headers["Accept"], "text/html" );
684    /// assert_eq!( headers["X-Custom-Foo"], "bar" );
685    /// ```
686    pub fn headers_ref(&self) -> Option<&HeaderMap> {
687        self.inner.as_ref().ok().map(|h| &h.headers)
688    }
689
690    /// Get headers on this request builder.
691    ///
692    /// When builder has error returns None.
693    ///
694    /// # Example
695    ///
696    /// ```
697    /// # use axol_http::{header::HeaderValue, Request};
698    /// let mut req = Request::builder();
699    /// {
700    ///   let headers = req.headers_mut().unwrap();
701    ///   headers.insert("Accept", HeaderValue::from_static("text/html"));
702    ///   headers.insert("X-Custom-Foo", HeaderValue::from_static("bar"));
703    /// }
704    /// let headers = req.headers_ref().unwrap();
705    /// assert_eq!( headers["Accept"], "text/html" );
706    /// assert_eq!( headers["X-Custom-Foo"], "bar" );
707    /// ```
708    pub fn headers_mut(&mut self) -> Option<&mut HeaderMap> {
709        self.inner.as_mut().ok().map(|h| &mut h.headers)
710    }
711
712    /// Adds an extension to this builder
713    ///
714    /// # Examples
715    ///
716    /// ```
717    /// # use axol_http::*;
718    ///
719    /// let req = Request::builder()
720    ///     .extension("My Extension")
721    ///     .body(())
722    ///     .unwrap();
723    ///
724    /// assert_eq!(req.extensions().get::<&'static str>(),
725    ///            Some(&"My Extension"));
726    /// ```
727    pub fn extension<T>(self, extension: T) -> Builder
728    where
729        T: Any + Send + Sync + 'static,
730    {
731        self.and_then(move |head| {
732            head.extensions.insert(extension);
733            Ok(head)
734        })
735    }
736
737    /// Get a reference to the extensions for this request builder.
738    ///
739    /// If the builder has an error, this returns `None`.
740    ///
741    /// # Example
742    ///
743    /// ```
744    /// # use axol_http::Request;
745    /// let req = Request::builder().extension("My Extension").extension(5u32);
746    /// let extensions = req.extensions_ref().unwrap();
747    /// assert_eq!(extensions.get::<&'static str>(), Some(&"My Extension"));
748    /// assert_eq!(extensions.get::<u32>(), Some(&5u32));
749    /// ```
750    pub fn extensions(&self) -> Option<&Extensions> {
751        self.inner.as_ref().ok().map(|h| &h.extensions)
752    }
753
754    pub fn extensions_mut(&mut self) -> Option<&mut Extensions> {
755        self.inner.as_mut().ok().map(|h| &mut h.extensions)
756    }
757
758    /// "Consumes" this builder, using the provided `body` to return a
759    /// constructed `Request`.
760    ///
761    /// # Errors
762    ///
763    /// This function may return an error if any previously configured argument
764    /// failed to parse or get converted to the internal representation. For
765    /// example if an invalid `head` was specified via `header("Foo",
766    /// "Bar\r\n")` the error will be returned when this function is called
767    /// rather than when `header` was called.
768    ///
769    /// # Examples
770    ///
771    /// ```
772    /// # use axol_http::*;
773    ///
774    /// let request = Request::builder()
775    ///     .body(())
776    ///     .unwrap();
777    /// ```
778    pub fn body(self, body: impl Into<Body>) -> Result<Request, RequestBuilderError> {
779        self.inner.map(move |mut head| {
780            head.body = body.into();
781            head
782        })
783    }
784
785    fn and_then<F>(self, func: F) -> Self
786    where
787        F: FnOnce(Request) -> Result<Request, RequestBuilderError>,
788    {
789        Builder {
790            inner: self.inner.and_then(func),
791        }
792    }
793}
794
795impl Default for Builder {
796    fn default() -> Builder {
797        Builder {
798            inner: Ok(Request::default()),
799        }
800    }
801}