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 config::{DEFAULT_H2_CONN_WINDOW_SIZE, DEFAULT_H2_STREAM_WINDOW_SIZE},
9 h1::{self, ExpectHandler, H1Service, UpgradeHandler},
10 service::HttpService,
11 ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfigBuilder,
12};
13
14pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler> {
18 keep_alive: KeepAlive,
19 client_request_timeout: Duration,
20 client_disconnect_timeout: Duration,
21 tcp_nodelay: Option<bool>,
22 secure: bool,
23 local_addr: Option<net::SocketAddr>,
24 h1_allow_half_closed: bool,
25 h2_conn_window_size: u32,
26 h2_stream_window_size: u32,
27 expect: X,
28 upgrade: Option<U>,
29 on_connect_ext: Option<Rc<ConnectCallback<T>>>,
30 _phantom: PhantomData<S>,
31}
32
33impl<T, S> Default for HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler>
34where
35 S: ServiceFactory<Request, Config = ()>,
36 S::Error: Into<Response<BoxBody>> + 'static,
37 S::InitError: fmt::Debug,
38 <S::Service as Service<Request>>::Future: 'static,
39{
40 fn default() -> Self {
41 HttpServiceBuilder {
42 keep_alive: KeepAlive::default(),
44 client_request_timeout: Duration::from_secs(5),
45 client_disconnect_timeout: Duration::ZERO,
46 tcp_nodelay: None,
47 secure: false,
48 local_addr: None,
49 h1_allow_half_closed: true,
50 h2_conn_window_size: DEFAULT_H2_CONN_WINDOW_SIZE,
51 h2_stream_window_size: DEFAULT_H2_STREAM_WINDOW_SIZE,
52
53 expect: ExpectHandler,
55 upgrade: None,
56 on_connect_ext: None,
57 _phantom: PhantomData,
58 }
59 }
60}
61
62impl<T, S, X, U> HttpServiceBuilder<T, S, X, U>
63where
64 S: ServiceFactory<Request, Config = ()>,
65 S::Error: Into<Response<BoxBody>> + 'static,
66 S::InitError: fmt::Debug,
67 <S::Service as Service<Request>>::Future: 'static,
68 X: ServiceFactory<Request, Config = (), Response = Request>,
69 X::Error: Into<Response<BoxBody>>,
70 X::InitError: fmt::Debug,
71 U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
72 U::Error: fmt::Display,
73 U::InitError: fmt::Debug,
74{
75 pub fn keep_alive<W: Into<KeepAlive>>(mut self, val: W) -> Self {
81 self.keep_alive = val.into();
82 self
83 }
84
85 pub fn secure(mut self) -> Self {
87 self.secure = true;
88 self
89 }
90
91 pub fn local_addr(mut self, addr: net::SocketAddr) -> Self {
93 self.local_addr = Some(addr);
94 self
95 }
96
97 pub fn client_request_timeout(mut self, dur: Duration) -> Self {
107 self.client_request_timeout = dur;
108 self
109 }
110
111 #[doc(hidden)]
112 #[deprecated(since = "3.0.0", note = "Renamed to `client_request_timeout`.")]
113 pub fn client_timeout(self, dur: Duration) -> Self {
114 self.client_request_timeout(dur)
115 }
116
117 pub fn client_disconnect_timeout(mut self, dur: Duration) -> Self {
126 self.client_disconnect_timeout = dur;
127 self
128 }
129
130 pub fn tcp_nodelay(mut self, nodelay: bool) -> Self {
132 self.tcp_nodelay = Some(nodelay);
133 self
134 }
135
136 #[doc(hidden)]
137 #[deprecated(since = "3.0.0", note = "Renamed to `client_disconnect_timeout`.")]
138 pub fn client_disconnect(self, dur: Duration) -> Self {
139 self.client_disconnect_timeout(dur)
140 }
141
142 pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
150 self.h1_allow_half_closed = allow;
151 self
152 }
153
154 pub fn h2_initial_window_size(mut self, size: u32) -> Self {
158 self.h2_stream_window_size = size;
159 self
160 }
161
162 pub fn h2_initial_connection_window_size(mut self, size: u32) -> Self {
166 self.h2_conn_window_size = size;
167 self
168 }
169
170 pub fn expect<F, X1>(self, expect: F) -> HttpServiceBuilder<T, S, X1, U>
176 where
177 F: IntoServiceFactory<X1, Request>,
178 X1: ServiceFactory<Request, Config = (), Response = Request>,
179 X1::Error: Into<Response<BoxBody>>,
180 X1::InitError: fmt::Debug,
181 {
182 HttpServiceBuilder {
183 keep_alive: self.keep_alive,
184 client_request_timeout: self.client_request_timeout,
185 client_disconnect_timeout: self.client_disconnect_timeout,
186 tcp_nodelay: self.tcp_nodelay,
187 secure: self.secure,
188 local_addr: self.local_addr,
189 h1_allow_half_closed: self.h1_allow_half_closed,
190 h2_conn_window_size: self.h2_conn_window_size,
191 h2_stream_window_size: self.h2_stream_window_size,
192 expect: expect.into_factory(),
193 upgrade: self.upgrade,
194 on_connect_ext: self.on_connect_ext,
195 _phantom: PhantomData,
196 }
197 }
198
199 pub fn upgrade<F, U1>(self, upgrade: F) -> HttpServiceBuilder<T, S, X, U1>
204 where
205 F: IntoServiceFactory<U1, (Request, Framed<T, h1::Codec>)>,
206 U1: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
207 U1::Error: fmt::Display,
208 U1::InitError: fmt::Debug,
209 {
210 HttpServiceBuilder {
211 keep_alive: self.keep_alive,
212 client_request_timeout: self.client_request_timeout,
213 client_disconnect_timeout: self.client_disconnect_timeout,
214 tcp_nodelay: self.tcp_nodelay,
215 secure: self.secure,
216 local_addr: self.local_addr,
217 h1_allow_half_closed: self.h1_allow_half_closed,
218 h2_conn_window_size: self.h2_conn_window_size,
219 h2_stream_window_size: self.h2_stream_window_size,
220 expect: self.expect,
221 upgrade: Some(upgrade.into_factory()),
222 on_connect_ext: self.on_connect_ext,
223 _phantom: PhantomData,
224 }
225 }
226
227 pub fn on_connect_ext<F>(mut self, f: F) -> Self
233 where
234 F: Fn(&T, &mut Extensions) + 'static,
235 {
236 self.on_connect_ext = Some(Rc::new(f));
237 self
238 }
239
240 pub fn h1<F, B>(self, service: F) -> H1Service<T, S, B, X, U>
242 where
243 B: MessageBody,
244 F: IntoServiceFactory<S, Request>,
245 S::Error: Into<Response<BoxBody>>,
246 S::InitError: fmt::Debug,
247 S::Response: Into<Response<B>>,
248 {
249 let cfg = ServiceConfigBuilder::new()
250 .keep_alive(self.keep_alive)
251 .client_request_timeout(self.client_request_timeout)
252 .client_disconnect_timeout(self.client_disconnect_timeout)
253 .tcp_nodelay(self.tcp_nodelay)
254 .secure(self.secure)
255 .local_addr(self.local_addr)
256 .h1_allow_half_closed(self.h1_allow_half_closed)
257 .h2_initial_window_size(self.h2_stream_window_size)
258 .h2_initial_connection_window_size(self.h2_conn_window_size)
259 .build();
260
261 H1Service::with_config(cfg, service.into_factory())
262 .expect(self.expect)
263 .upgrade(self.upgrade)
264 .on_connect_ext(self.on_connect_ext)
265 }
266
267 #[cfg(feature = "http2")]
269 pub fn h2<F, B>(self, service: F) -> crate::h2::H2Service<T, S, B>
270 where
271 F: IntoServiceFactory<S, Request>,
272 S::Error: Into<Response<BoxBody>> + 'static,
273 S::InitError: fmt::Debug,
274 S::Response: Into<Response<B>> + 'static,
275
276 B: MessageBody + 'static,
277 {
278 let cfg = ServiceConfigBuilder::new()
279 .keep_alive(self.keep_alive)
280 .client_request_timeout(self.client_request_timeout)
281 .client_disconnect_timeout(self.client_disconnect_timeout)
282 .tcp_nodelay(self.tcp_nodelay)
283 .secure(self.secure)
284 .local_addr(self.local_addr)
285 .h1_allow_half_closed(self.h1_allow_half_closed)
286 .h2_initial_window_size(self.h2_stream_window_size)
287 .h2_initial_connection_window_size(self.h2_conn_window_size)
288 .build();
289
290 crate::h2::H2Service::with_config(cfg, service.into_factory())
291 .on_connect_ext(self.on_connect_ext)
292 }
293
294 pub fn finish<F, B>(self, service: F) -> HttpService<T, S, B, X, U>
296 where
297 F: IntoServiceFactory<S, Request>,
298 S::Error: Into<Response<BoxBody>> + 'static,
299 S::InitError: fmt::Debug,
300 S::Response: Into<Response<B>> + 'static,
301
302 B: MessageBody + 'static,
303 {
304 let cfg = ServiceConfigBuilder::new()
305 .keep_alive(self.keep_alive)
306 .client_request_timeout(self.client_request_timeout)
307 .client_disconnect_timeout(self.client_disconnect_timeout)
308 .tcp_nodelay(self.tcp_nodelay)
309 .secure(self.secure)
310 .local_addr(self.local_addr)
311 .h1_allow_half_closed(self.h1_allow_half_closed)
312 .h2_initial_window_size(self.h2_stream_window_size)
313 .h2_initial_connection_window_size(self.h2_conn_window_size)
314 .build();
315
316 HttpService::with_config(cfg, service.into_factory())
317 .expect(self.expect)
318 .upgrade(self.upgrade)
319 .on_connect_ext(self.on_connect_ext)
320 }
321}