awc/
frozen.rs

1use std::{net, rc::Rc, time::Duration};
2
3use bytes::Bytes;
4use futures_core::Stream;
5use serde::Serialize;
6
7use actix_http::{
8    body::MessageBody,
9    error::HttpError,
10    header::{HeaderMap, TryIntoHeaderPair},
11    Method, RequestHead, Uri,
12};
13
14use crate::{
15    client::ClientConfig,
16    sender::{RequestSender, SendClientRequest},
17    BoxError,
18};
19
20/// `FrozenClientRequest` struct represents cloneable client request.
21///
22/// It could be used to send same request multiple times.
23#[derive(Clone)]
24pub struct FrozenClientRequest {
25    pub(crate) head: Rc<RequestHead>,
26    pub(crate) addr: Option<net::SocketAddr>,
27    pub(crate) response_decompress: bool,
28    pub(crate) timeout: Option<Duration>,
29    pub(crate) config: ClientConfig,
30}
31
32impl FrozenClientRequest {
33    /// Get HTTP URI of request
34    pub fn get_uri(&self) -> &Uri {
35        &self.head.uri
36    }
37
38    /// Get HTTP method of this request
39    pub fn get_method(&self) -> &Method {
40        &self.head.method
41    }
42
43    /// Returns request's headers.
44    pub fn headers(&self) -> &HeaderMap {
45        &self.head.headers
46    }
47
48    /// Send a body.
49    pub fn send_body<B>(&self, body: B) -> SendClientRequest
50    where
51        B: MessageBody + 'static,
52    {
53        RequestSender::Rc(self.head.clone(), None).send_body(
54            self.addr,
55            self.response_decompress,
56            self.timeout,
57            &self.config,
58            body,
59        )
60    }
61
62    /// Send a json body.
63    pub fn send_json<T: Serialize>(&self, value: &T) -> SendClientRequest {
64        RequestSender::Rc(self.head.clone(), None).send_json(
65            self.addr,
66            self.response_decompress,
67            self.timeout,
68            &self.config,
69            value,
70        )
71    }
72
73    /// Send an urlencoded body.
74    pub fn send_form<T: Serialize>(&self, value: &T) -> SendClientRequest {
75        RequestSender::Rc(self.head.clone(), None).send_form(
76            self.addr,
77            self.response_decompress,
78            self.timeout,
79            &self.config,
80            value,
81        )
82    }
83
84    /// Send a streaming body.
85    pub fn send_stream<S, E>(&self, stream: S) -> SendClientRequest
86    where
87        S: Stream<Item = Result<Bytes, E>> + 'static,
88        E: Into<BoxError> + 'static,
89    {
90        RequestSender::Rc(self.head.clone(), None).send_stream(
91            self.addr,
92            self.response_decompress,
93            self.timeout,
94            &self.config,
95            stream,
96        )
97    }
98
99    /// Send an empty body.
100    pub fn send(&self) -> SendClientRequest {
101        RequestSender::Rc(self.head.clone(), None).send(
102            self.addr,
103            self.response_decompress,
104            self.timeout,
105            &self.config,
106        )
107    }
108
109    /// Clones this `FrozenClientRequest`, returning a new one with extra headers added.
110    pub fn extra_headers(&self, extra_headers: HeaderMap) -> FrozenSendBuilder {
111        FrozenSendBuilder::new(self.clone(), extra_headers)
112    }
113
114    /// Clones this `FrozenClientRequest`, returning a new one with the extra header added.
115    pub fn extra_header(&self, header: impl TryIntoHeaderPair) -> FrozenSendBuilder {
116        self.extra_headers(HeaderMap::new()).extra_header(header)
117    }
118}
119
120/// Builder that allows to modify extra headers.
121pub struct FrozenSendBuilder {
122    req: FrozenClientRequest,
123    extra_headers: HeaderMap,
124    err: Option<HttpError>,
125}
126
127impl FrozenSendBuilder {
128    pub(crate) fn new(req: FrozenClientRequest, extra_headers: HeaderMap) -> Self {
129        Self {
130            req,
131            extra_headers,
132            err: None,
133        }
134    }
135
136    /// Insert a header, it overrides existing header in `FrozenClientRequest`.
137    pub fn extra_header(mut self, header: impl TryIntoHeaderPair) -> Self {
138        match header.try_into_pair() {
139            Ok((key, value)) => {
140                self.extra_headers.insert(key, value);
141            }
142
143            Err(err) => self.err = Some(err.into()),
144        }
145
146        self
147    }
148
149    /// Complete request construction and send a body.
150    pub fn send_body(self, body: impl MessageBody + 'static) -> SendClientRequest {
151        if let Some(e) = self.err {
152            return e.into();
153        }
154
155        RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_body(
156            self.req.addr,
157            self.req.response_decompress,
158            self.req.timeout,
159            &self.req.config,
160            body,
161        )
162    }
163
164    /// Complete request construction and send a json body.
165    pub fn send_json(self, value: impl Serialize) -> SendClientRequest {
166        if let Some(err) = self.err {
167            return err.into();
168        }
169
170        RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_json(
171            self.req.addr,
172            self.req.response_decompress,
173            self.req.timeout,
174            &self.req.config,
175            value,
176        )
177    }
178
179    /// Complete request construction and send an urlencoded body.
180    pub fn send_form(self, value: impl Serialize) -> SendClientRequest {
181        if let Some(e) = self.err {
182            return e.into();
183        }
184
185        RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_form(
186            self.req.addr,
187            self.req.response_decompress,
188            self.req.timeout,
189            &self.req.config,
190            value,
191        )
192    }
193
194    /// Complete request construction and send a streaming body.
195    pub fn send_stream<S, E>(self, stream: S) -> SendClientRequest
196    where
197        S: Stream<Item = Result<Bytes, E>> + 'static,
198        E: Into<BoxError> + 'static,
199    {
200        if let Some(e) = self.err {
201            return e.into();
202        }
203
204        RequestSender::Rc(self.req.head, Some(self.extra_headers)).send_stream(
205            self.req.addr,
206            self.req.response_decompress,
207            self.req.timeout,
208            &self.req.config,
209            stream,
210        )
211    }
212
213    /// Complete request construction and send an empty body.
214    pub fn send(self) -> SendClientRequest {
215        if let Some(e) = self.err {
216            return e.into();
217        }
218
219        RequestSender::Rc(self.req.head, Some(self.extra_headers)).send(
220            self.req.addr,
221            self.req.response_decompress,
222            self.req.timeout,
223            &self.req.config,
224        )
225    }
226}