1use std::{fmt, marker::PhantomData, net, rc::Rc, time::Duration};
2
3use actix_codec::Framed;
4use actix_service::{IntoServiceFactory, Service, ServiceFactory};
5
6use crate::{
7 body::{BoxBody, MessageBody},
8 h1::{self, ExpectHandler, H1Service, UpgradeHandler},
9 service::HttpService,
10 ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfigBuilder,
11};
12
13pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler> {
17 keep_alive: KeepAlive,
18 client_request_timeout: Duration,
19 client_disconnect_timeout: Duration,
20 secure: bool,
21 local_addr: Option<net::SocketAddr>,
22 h1_allow_half_closed: bool,
23 expect: X,
24 upgrade: Option<U>,
25 on_connect_ext: Option<Rc<ConnectCallback<T>>>,
26 _phantom: PhantomData<S>,
27}
28
29impl<T, S> Default for HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler>
30where
31 S: ServiceFactory<Request, Config = ()>,
32 S::Error: Into<Response<BoxBody>> + 'static,
33 S::InitError: fmt::Debug,
34 <S::Service as Service<Request>>::Future: 'static,
35{
36 fn default() -> Self {
37 HttpServiceBuilder {
38 keep_alive: KeepAlive::default(),
40 client_request_timeout: Duration::from_secs(5),
41 client_disconnect_timeout: Duration::ZERO,
42 secure: false,
43 local_addr: None,
44 h1_allow_half_closed: true,
45
46 expect: ExpectHandler,
48 upgrade: None,
49 on_connect_ext: None,
50 _phantom: PhantomData,
51 }
52 }
53}
54
55impl<T, S, X, U> HttpServiceBuilder<T, S, X, U>
56where
57 S: ServiceFactory<Request, Config = ()>,
58 S::Error: Into<Response<BoxBody>> + 'static,
59 S::InitError: fmt::Debug,
60 <S::Service as Service<Request>>::Future: 'static,
61 X: ServiceFactory<Request, Config = (), Response = Request>,
62 X::Error: Into<Response<BoxBody>>,
63 X::InitError: fmt::Debug,
64 U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
65 U::Error: fmt::Display,
66 U::InitError: fmt::Debug,
67{
68 pub fn keep_alive<W: Into<KeepAlive>>(mut self, val: W) -> Self {
74 self.keep_alive = val.into();
75 self
76 }
77
78 pub fn secure(mut self) -> Self {
80 self.secure = true;
81 self
82 }
83
84 pub fn local_addr(mut self, addr: net::SocketAddr) -> Self {
86 self.local_addr = Some(addr);
87 self
88 }
89
90 pub fn client_request_timeout(mut self, dur: Duration) -> Self {
100 self.client_request_timeout = dur;
101 self
102 }
103
104 #[doc(hidden)]
105 #[deprecated(since = "3.0.0", note = "Renamed to `client_request_timeout`.")]
106 pub fn client_timeout(self, dur: Duration) -> Self {
107 self.client_request_timeout(dur)
108 }
109
110 pub fn client_disconnect_timeout(mut self, dur: Duration) -> Self {
119 self.client_disconnect_timeout = dur;
120 self
121 }
122
123 #[doc(hidden)]
124 #[deprecated(since = "3.0.0", note = "Renamed to `client_disconnect_timeout`.")]
125 pub fn client_disconnect(self, dur: Duration) -> Self {
126 self.client_disconnect_timeout(dur)
127 }
128
129 pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
137 self.h1_allow_half_closed = allow;
138 self
139 }
140
141 pub fn expect<F, X1>(self, expect: F) -> HttpServiceBuilder<T, S, X1, U>
147 where
148 F: IntoServiceFactory<X1, Request>,
149 X1: ServiceFactory<Request, Config = (), Response = Request>,
150 X1::Error: Into<Response<BoxBody>>,
151 X1::InitError: fmt::Debug,
152 {
153 HttpServiceBuilder {
154 keep_alive: self.keep_alive,
155 client_request_timeout: self.client_request_timeout,
156 client_disconnect_timeout: self.client_disconnect_timeout,
157 secure: self.secure,
158 local_addr: self.local_addr,
159 h1_allow_half_closed: self.h1_allow_half_closed,
160 expect: expect.into_factory(),
161 upgrade: self.upgrade,
162 on_connect_ext: self.on_connect_ext,
163 _phantom: PhantomData,
164 }
165 }
166
167 pub fn upgrade<F, U1>(self, upgrade: F) -> HttpServiceBuilder<T, S, X, U1>
172 where
173 F: IntoServiceFactory<U1, (Request, Framed<T, h1::Codec>)>,
174 U1: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
175 U1::Error: fmt::Display,
176 U1::InitError: fmt::Debug,
177 {
178 HttpServiceBuilder {
179 keep_alive: self.keep_alive,
180 client_request_timeout: self.client_request_timeout,
181 client_disconnect_timeout: self.client_disconnect_timeout,
182 secure: self.secure,
183 local_addr: self.local_addr,
184 h1_allow_half_closed: self.h1_allow_half_closed,
185 expect: self.expect,
186 upgrade: Some(upgrade.into_factory()),
187 on_connect_ext: self.on_connect_ext,
188 _phantom: PhantomData,
189 }
190 }
191
192 pub fn on_connect_ext<F>(mut self, f: F) -> Self
198 where
199 F: Fn(&T, &mut Extensions) + 'static,
200 {
201 self.on_connect_ext = Some(Rc::new(f));
202 self
203 }
204
205 pub fn h1<F, B>(self, service: F) -> H1Service<T, S, B, X, U>
207 where
208 B: MessageBody,
209 F: IntoServiceFactory<S, Request>,
210 S::Error: Into<Response<BoxBody>>,
211 S::InitError: fmt::Debug,
212 S::Response: Into<Response<B>>,
213 {
214 let cfg = ServiceConfigBuilder::new()
215 .keep_alive(self.keep_alive)
216 .client_request_timeout(self.client_request_timeout)
217 .client_disconnect_timeout(self.client_disconnect_timeout)
218 .secure(self.secure)
219 .local_addr(self.local_addr)
220 .h1_allow_half_closed(self.h1_allow_half_closed)
221 .build();
222
223 H1Service::with_config(cfg, service.into_factory())
224 .expect(self.expect)
225 .upgrade(self.upgrade)
226 .on_connect_ext(self.on_connect_ext)
227 }
228
229 #[cfg(feature = "http2")]
231 pub fn h2<F, B>(self, service: F) -> crate::h2::H2Service<T, S, B>
232 where
233 F: IntoServiceFactory<S, Request>,
234 S::Error: Into<Response<BoxBody>> + 'static,
235 S::InitError: fmt::Debug,
236 S::Response: Into<Response<B>> + 'static,
237
238 B: MessageBody + 'static,
239 {
240 let cfg = ServiceConfigBuilder::new()
241 .keep_alive(self.keep_alive)
242 .client_request_timeout(self.client_request_timeout)
243 .client_disconnect_timeout(self.client_disconnect_timeout)
244 .secure(self.secure)
245 .local_addr(self.local_addr)
246 .h1_allow_half_closed(self.h1_allow_half_closed)
247 .build();
248
249 crate::h2::H2Service::with_config(cfg, service.into_factory())
250 .on_connect_ext(self.on_connect_ext)
251 }
252
253 pub fn finish<F, B>(self, service: F) -> HttpService<T, S, B, X, U>
255 where
256 F: IntoServiceFactory<S, Request>,
257 S::Error: Into<Response<BoxBody>> + 'static,
258 S::InitError: fmt::Debug,
259 S::Response: Into<Response<B>> + 'static,
260
261 B: MessageBody + 'static,
262 {
263 let cfg = ServiceConfigBuilder::new()
264 .keep_alive(self.keep_alive)
265 .client_request_timeout(self.client_request_timeout)
266 .client_disconnect_timeout(self.client_disconnect_timeout)
267 .secure(self.secure)
268 .local_addr(self.local_addr)
269 .h1_allow_half_closed(self.h1_allow_half_closed)
270 .build();
271
272 HttpService::with_config(cfg, service.into_factory())
273 .expect(self.expect)
274 .upgrade(self.upgrade)
275 .on_connect_ext(self.on_connect_ext)
276 }
277}