Skip to main content

awc/
frozen.rs

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