1use std::{fmt, future::Future, 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::{
9 GracefulShutdownSignal, DEFAULT_H1_WRITE_BUFFER_SIZE, DEFAULT_H2_CONN_WINDOW_SIZE,
10 DEFAULT_H2_STREAM_WINDOW_SIZE,
11 },
12 h1::{self, ExpectHandler, H1Service, UpgradeHandler},
13 service::HttpService,
14 ConnectCallback, Extensions, KeepAlive, Request, Response, ServiceConfigBuilder,
15};
16
17pub struct HttpServiceBuilder<T, S, X = ExpectHandler, U = UpgradeHandler> {
21 keep_alive: KeepAlive,
22 client_request_timeout: Duration,
23 client_disconnect_timeout: Duration,
24 tcp_nodelay: Option<bool>,
25 secure: bool,
26 local_addr: Option<net::SocketAddr>,
27 h1_allow_half_closed: bool,
28 h1_write_buffer_size: usize,
29 h2_conn_window_size: u32,
30 h2_stream_window_size: u32,
31 graceful_shutdown_signal: Option<GracefulShutdownSignal>,
32 expect: X,
33 upgrade: Option<U>,
34 on_connect_ext: Option<Rc<ConnectCallback<T>>>,
35 _phantom: PhantomData<S>,
36}
37
38impl<T, S> Default for HttpServiceBuilder<T, S, ExpectHandler, UpgradeHandler>
39where
40 S: ServiceFactory<Request, Config = ()>,
41 S::Error: Into<Response<BoxBody>> + 'static,
42 S::InitError: fmt::Debug,
43 <S::Service as Service<Request>>::Future: 'static,
44{
45 fn default() -> Self {
46 HttpServiceBuilder {
47 keep_alive: KeepAlive::default(),
49 client_request_timeout: Duration::from_secs(5),
50 client_disconnect_timeout: Duration::ZERO,
51 tcp_nodelay: Some(true),
52 secure: false,
53 local_addr: None,
54 h1_allow_half_closed: true,
55 h1_write_buffer_size: DEFAULT_H1_WRITE_BUFFER_SIZE,
56 h2_conn_window_size: DEFAULT_H2_CONN_WINDOW_SIZE,
57 h2_stream_window_size: DEFAULT_H2_STREAM_WINDOW_SIZE,
58 graceful_shutdown_signal: None,
59
60 expect: ExpectHandler,
62 upgrade: None,
63 on_connect_ext: None,
64 _phantom: PhantomData,
65 }
66 }
67}
68
69impl<T, S, X, U> HttpServiceBuilder<T, S, X, U>
70where
71 S: ServiceFactory<Request, Config = ()>,
72 S::Error: Into<Response<BoxBody>> + 'static,
73 S::InitError: fmt::Debug,
74 <S::Service as Service<Request>>::Future: 'static,
75 X: ServiceFactory<Request, Config = (), Response = Request>,
76 X::Error: Into<Response<BoxBody>>,
77 X::InitError: fmt::Debug,
78 U: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
79 U::Error: fmt::Display,
80 U::InitError: fmt::Debug,
81{
82 pub fn keep_alive<W: Into<KeepAlive>>(mut self, val: W) -> Self {
88 self.keep_alive = val.into();
89 self
90 }
91
92 pub fn secure(mut self) -> Self {
94 self.secure = true;
95 self
96 }
97
98 pub fn local_addr(mut self, addr: net::SocketAddr) -> Self {
100 self.local_addr = Some(addr);
101 self
102 }
103
104 pub fn client_request_timeout(mut self, dur: Duration) -> Self {
114 self.client_request_timeout = dur;
115 self
116 }
117
118 #[doc(hidden)]
119 #[deprecated(since = "3.0.0", note = "Renamed to `client_request_timeout`.")]
120 pub fn client_timeout(self, dur: Duration) -> Self {
121 self.client_request_timeout(dur)
122 }
123
124 pub fn client_disconnect_timeout(mut self, dur: Duration) -> Self {
133 self.client_disconnect_timeout = dur;
134 self
135 }
136
137 pub fn tcp_nodelay(mut self, nodelay: bool) -> Self {
141 self.tcp_nodelay = Some(nodelay);
142 self
143 }
144
145 #[doc(hidden)]
146 #[deprecated(since = "3.0.0", note = "Renamed to `client_disconnect_timeout`.")]
147 pub fn client_disconnect(self, dur: Duration) -> Self {
148 self.client_disconnect_timeout(dur)
149 }
150
151 pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
159 self.h1_allow_half_closed = allow;
160 self
161 }
162
163 pub fn h1_write_buffer_size(mut self, size: usize) -> Self {
173 assert!(
174 size > 0,
175 "HTTP/1 write buffer size must be greater than zero"
176 );
177
178 self.h1_write_buffer_size = size;
179 self
180 }
181
182 #[doc(hidden)]
184 pub fn graceful_shutdown_signal<F, Fut>(mut self, signal: F) -> Self
185 where
186 F: Fn() -> Fut + 'static,
187 Fut: Future<Output = ()> + 'static,
188 {
189 self.graceful_shutdown_signal = Some(GracefulShutdownSignal::new(signal));
190 self
191 }
192
193 pub fn h2_initial_window_size(mut self, size: u32) -> Self {
197 self.h2_stream_window_size = size;
198 self
199 }
200
201 pub fn h2_initial_connection_window_size(mut self, size: u32) -> Self {
205 self.h2_conn_window_size = size;
206 self
207 }
208
209 pub fn expect<F, X1>(self, expect: F) -> HttpServiceBuilder<T, S, X1, U>
215 where
216 F: IntoServiceFactory<X1, Request>,
217 X1: ServiceFactory<Request, Config = (), Response = Request>,
218 X1::Error: Into<Response<BoxBody>>,
219 X1::InitError: fmt::Debug,
220 {
221 HttpServiceBuilder {
222 keep_alive: self.keep_alive,
223 client_request_timeout: self.client_request_timeout,
224 client_disconnect_timeout: self.client_disconnect_timeout,
225 tcp_nodelay: self.tcp_nodelay,
226 secure: self.secure,
227 local_addr: self.local_addr,
228 h1_allow_half_closed: self.h1_allow_half_closed,
229 h1_write_buffer_size: self.h1_write_buffer_size,
230 h2_conn_window_size: self.h2_conn_window_size,
231 h2_stream_window_size: self.h2_stream_window_size,
232 graceful_shutdown_signal: self.graceful_shutdown_signal,
233 expect: expect.into_factory(),
234 upgrade: self.upgrade,
235 on_connect_ext: self.on_connect_ext,
236 _phantom: PhantomData,
237 }
238 }
239
240 pub fn upgrade<F, U1>(self, upgrade: F) -> HttpServiceBuilder<T, S, X, U1>
245 where
246 F: IntoServiceFactory<U1, (Request, Framed<T, h1::Codec>)>,
247 U1: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
248 U1::Error: fmt::Display,
249 U1::InitError: fmt::Debug,
250 {
251 HttpServiceBuilder {
252 keep_alive: self.keep_alive,
253 client_request_timeout: self.client_request_timeout,
254 client_disconnect_timeout: self.client_disconnect_timeout,
255 tcp_nodelay: self.tcp_nodelay,
256 secure: self.secure,
257 local_addr: self.local_addr,
258 h1_allow_half_closed: self.h1_allow_half_closed,
259 h1_write_buffer_size: self.h1_write_buffer_size,
260 h2_conn_window_size: self.h2_conn_window_size,
261 h2_stream_window_size: self.h2_stream_window_size,
262 graceful_shutdown_signal: self.graceful_shutdown_signal,
263 expect: self.expect,
264 upgrade: Some(upgrade.into_factory()),
265 on_connect_ext: self.on_connect_ext,
266 _phantom: PhantomData,
267 }
268 }
269
270 pub fn on_connect_ext<F>(mut self, f: F) -> Self
276 where
277 F: Fn(&T, &mut Extensions) + 'static,
278 {
279 self.on_connect_ext = Some(Rc::new(f));
280 self
281 }
282
283 pub fn h1<F, B>(self, service: F) -> H1Service<T, S, B, X, U>
285 where
286 B: MessageBody,
287 F: IntoServiceFactory<S, Request>,
288 S::Error: Into<Response<BoxBody>>,
289 S::InitError: fmt::Debug,
290 S::Response: Into<Response<B>>,
291 {
292 let cfg = ServiceConfigBuilder::new()
293 .keep_alive(self.keep_alive)
294 .client_request_timeout(self.client_request_timeout)
295 .client_disconnect_timeout(self.client_disconnect_timeout)
296 .tcp_nodelay(self.tcp_nodelay)
297 .secure(self.secure)
298 .local_addr(self.local_addr)
299 .h1_allow_half_closed(self.h1_allow_half_closed)
300 .h1_write_buffer_size(self.h1_write_buffer_size)
301 .h2_initial_window_size(self.h2_stream_window_size)
302 .h2_initial_connection_window_size(self.h2_conn_window_size)
303 .graceful_shutdown_signal(self.graceful_shutdown_signal)
304 .build();
305
306 H1Service::with_config(cfg, service.into_factory())
307 .expect(self.expect)
308 .upgrade(self.upgrade)
309 .on_connect_ext(self.on_connect_ext)
310 }
311
312 #[cfg(feature = "http2")]
314 pub fn h2<F, B>(self, service: F) -> crate::h2::H2Service<T, S, B>
315 where
316 F: IntoServiceFactory<S, Request>,
317 S::Error: Into<Response<BoxBody>> + 'static,
318 S::InitError: fmt::Debug,
319 S::Response: Into<Response<B>> + 'static,
320
321 B: MessageBody + 'static,
322 {
323 let cfg = ServiceConfigBuilder::new()
324 .keep_alive(self.keep_alive)
325 .client_request_timeout(self.client_request_timeout)
326 .client_disconnect_timeout(self.client_disconnect_timeout)
327 .tcp_nodelay(self.tcp_nodelay)
328 .secure(self.secure)
329 .local_addr(self.local_addr)
330 .h1_allow_half_closed(self.h1_allow_half_closed)
331 .h1_write_buffer_size(self.h1_write_buffer_size)
332 .h2_initial_window_size(self.h2_stream_window_size)
333 .h2_initial_connection_window_size(self.h2_conn_window_size)
334 .graceful_shutdown_signal(self.graceful_shutdown_signal)
335 .build();
336
337 crate::h2::H2Service::with_config(cfg, service.into_factory())
338 .on_connect_ext(self.on_connect_ext)
339 }
340
341 pub fn finish<F, B>(self, service: F) -> HttpService<T, S, B, X, U>
343 where
344 F: IntoServiceFactory<S, Request>,
345 S::Error: Into<Response<BoxBody>> + 'static,
346 S::InitError: fmt::Debug,
347 S::Response: Into<Response<B>> + 'static,
348
349 B: MessageBody + 'static,
350 {
351 let cfg = ServiceConfigBuilder::new()
352 .keep_alive(self.keep_alive)
353 .client_request_timeout(self.client_request_timeout)
354 .client_disconnect_timeout(self.client_disconnect_timeout)
355 .tcp_nodelay(self.tcp_nodelay)
356 .secure(self.secure)
357 .local_addr(self.local_addr)
358 .h1_allow_half_closed(self.h1_allow_half_closed)
359 .h1_write_buffer_size(self.h1_write_buffer_size)
360 .h2_initial_window_size(self.h2_stream_window_size)
361 .h2_initial_connection_window_size(self.h2_conn_window_size)
362 .graceful_shutdown_signal(self.graceful_shutdown_signal)
363 .build();
364
365 HttpService::with_config(cfg, service.into_factory())
366 .expect(self.expect)
367 .upgrade(self.upgrade)
368 .on_connect_ext(self.on_connect_ext)
369 }
370}