ttpkit_http/client/
request.rs

1//! Request types.
2
3use std::ops::Deref;
4
5use crate::{
6    Body, Method, Request, RequestHeader, Version,
7    header::HeaderField,
8    request::RequestBuilder,
9    url::{IntoUrl, Url, UrlParseError},
10};
11
12/// Builder for outgoing HTTP requests.
13pub struct OutgoingRequestBuilder {
14    inner: RequestBuilder,
15    url: Url,
16}
17
18impl OutgoingRequestBuilder {
19    /// Create a new builder.
20    #[inline(never)]
21    fn new(version: Version, method: Method, url: Url) -> Self {
22        let path = String::from(url.path_with_query());
23
24        Self {
25            inner: Request::builder(version, method, path.into()),
26            url,
27        }
28    }
29
30    /// Set protocol version.
31    #[inline]
32    pub fn set_version(mut self, version: Version) -> Self {
33        self.inner = self.inner.set_version(version);
34        self
35    }
36
37    /// Set request method.
38    #[inline]
39    pub fn set_method(mut self, method: Method) -> Self {
40        self.inner = self.inner.set_method(method);
41        self
42    }
43
44    /// Set request URL.
45    pub fn set_url(mut self, url: Url) -> Self {
46        let path = String::from(url.path_with_query());
47
48        self.inner = self.inner.set_path(path.into());
49        self.url = url;
50        self
51    }
52
53    /// Replace the current header fields having the same name (if any).
54    pub fn set_header_field<T>(mut self, field: T) -> Self
55    where
56        T: Into<HeaderField>,
57    {
58        self.inner = self.inner.set_header_field(field);
59        self
60    }
61
62    /// Add a given header field.
63    pub fn add_header_field<T>(mut self, field: T) -> Self
64    where
65        T: Into<HeaderField>,
66    {
67        self.inner = self.inner.add_header_field(field);
68        self
69    }
70
71    /// Remove all header fields with a given name.
72    pub fn remove_header_field<N>(mut self, name: &N) -> Self
73    where
74        N: AsRef<[u8]> + ?Sized,
75    {
76        self.inner = self.inner.remove_header_fields(name);
77        self
78    }
79
80    /// Build the request.
81    pub fn body<B>(self, body: B) -> OutgoingRequest<B> {
82        let request = self.inner.body(body);
83
84        OutgoingRequest {
85            inner: request,
86            url: self.url,
87        }
88    }
89}
90
91/// Client request that can be sent to an HTTP server.
92pub struct OutgoingRequest<B = Body> {
93    inner: Request<B>,
94    url: Url,
95}
96
97impl OutgoingRequest<()> {
98    /// Get a request builder.
99    pub fn builder<U>(method: Method, url: U) -> Result<OutgoingRequestBuilder, UrlParseError>
100    where
101        U: IntoUrl,
102    {
103        let url = url.into_url()?;
104
105        Ok(OutgoingRequestBuilder::new(Version::Version11, method, url))
106    }
107
108    /// Get a request builder for a GET request.
109    pub fn get<U>(url: U) -> Result<OutgoingRequestBuilder, UrlParseError>
110    where
111        U: IntoUrl,
112    {
113        Self::builder(Method::Get, url)
114    }
115
116    /// Get a request builder for a PUT request.
117    pub fn put<U>(url: U) -> Result<OutgoingRequestBuilder, UrlParseError>
118    where
119        U: IntoUrl,
120    {
121        Self::builder(Method::Put, url)
122    }
123
124    /// Get a request builder for a POST request.
125    pub fn post<U>(url: U) -> Result<OutgoingRequestBuilder, UrlParseError>
126    where
127        U: IntoUrl,
128    {
129        Self::builder(Method::Post, url)
130    }
131
132    /// Get a request builder for a DELETE request.
133    pub fn delete<U>(url: U) -> Result<OutgoingRequestBuilder, UrlParseError>
134    where
135        U: IntoUrl,
136    {
137        Self::builder(Method::Delete, url)
138    }
139}
140
141impl<B> OutgoingRequest<B> {
142    /// Get the request URL.
143    #[inline]
144    pub fn url(&self) -> &Url {
145        &self.url
146    }
147
148    /// Split the request into the header and body.
149    #[inline]
150    pub fn deconstruct(self) -> (Url, RequestHeader, B) {
151        let (header, body) = self.inner.deconstruct();
152
153        (self.url, header, body)
154    }
155
156    /// Deconstruct the request back into a request builder and the body.
157    pub fn into_builder(self) -> (OutgoingRequestBuilder, B) {
158        let (header, body) = self.inner.deconstruct();
159
160        let builder = OutgoingRequestBuilder {
161            inner: header.into(),
162            url: self.url,
163        };
164
165        (builder, body)
166    }
167}
168
169impl<B> Deref for OutgoingRequest<B> {
170    type Target = Request<B>;
171
172    #[inline]
173    fn deref(&self) -> &Self::Target {
174        &self.inner
175    }
176}