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: None,
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 {
139 self.tcp_nodelay = Some(nodelay);
140 self
141 }
142
143 #[doc(hidden)]
144 #[deprecated(since = "3.0.0", note = "Renamed to `client_disconnect_timeout`.")]
145 pub fn client_disconnect(self, dur: Duration) -> Self {
146 self.client_disconnect_timeout(dur)
147 }
148
149 pub fn h1_allow_half_closed(mut self, allow: bool) -> Self {
157 self.h1_allow_half_closed = allow;
158 self
159 }
160
161 pub fn h1_write_buffer_size(mut self, size: usize) -> Self {
171 assert!(
172 size > 0,
173 "HTTP/1 write buffer size must be greater than zero"
174 );
175
176 self.h1_write_buffer_size = size;
177 self
178 }
179
180 #[doc(hidden)]
182 pub fn graceful_shutdown_signal<F, Fut>(mut self, signal: F) -> Self
183 where
184 F: Fn() -> Fut + 'static,
185 Fut: Future<Output = ()> + 'static,
186 {
187 self.graceful_shutdown_signal = Some(GracefulShutdownSignal::new(signal));
188 self
189 }
190
191 pub fn h2_initial_window_size(mut self, size: u32) -> Self {
195 self.h2_stream_window_size = size;
196 self
197 }
198
199 pub fn h2_initial_connection_window_size(mut self, size: u32) -> Self {
203 self.h2_conn_window_size = size;
204 self
205 }
206
207 pub fn expect<F, X1>(self, expect: F) -> HttpServiceBuilder<T, S, X1, U>
213 where
214 F: IntoServiceFactory<X1, Request>,
215 X1: ServiceFactory<Request, Config = (), Response = Request>,
216 X1::Error: Into<Response<BoxBody>>,
217 X1::InitError: fmt::Debug,
218 {
219 HttpServiceBuilder {
220 keep_alive: self.keep_alive,
221 client_request_timeout: self.client_request_timeout,
222 client_disconnect_timeout: self.client_disconnect_timeout,
223 tcp_nodelay: self.tcp_nodelay,
224 secure: self.secure,
225 local_addr: self.local_addr,
226 h1_allow_half_closed: self.h1_allow_half_closed,
227 h1_write_buffer_size: self.h1_write_buffer_size,
228 h2_conn_window_size: self.h2_conn_window_size,
229 h2_stream_window_size: self.h2_stream_window_size,
230 graceful_shutdown_signal: self.graceful_shutdown_signal,
231 expect: expect.into_factory(),
232 upgrade: self.upgrade,
233 on_connect_ext: self.on_connect_ext,
234 _phantom: PhantomData,
235 }
236 }
237
238 pub fn upgrade<F, U1>(self, upgrade: F) -> HttpServiceBuilder<T, S, X, U1>
243 where
244 F: IntoServiceFactory<U1, (Request, Framed<T, h1::Codec>)>,
245 U1: ServiceFactory<(Request, Framed<T, h1::Codec>), Config = (), Response = ()>,
246 U1::Error: fmt::Display,
247 U1::InitError: fmt::Debug,
248 {
249 HttpServiceBuilder {
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 h1_write_buffer_size: self.h1_write_buffer_size,
258 h2_conn_window_size: self.h2_conn_window_size,
259 h2_stream_window_size: self.h2_stream_window_size,
260 graceful_shutdown_signal: self.graceful_shutdown_signal,
261 expect: self.expect,
262 upgrade: Some(upgrade.into_factory()),
263 on_connect_ext: self.on_connect_ext,
264 _phantom: PhantomData,
265 }
266 }
267
268 pub fn on_connect_ext<F>(mut self, f: F) -> Self
274 where
275 F: Fn(&T, &mut Extensions) + 'static,
276 {
277 self.on_connect_ext = Some(Rc::new(f));
278 self
279 }
280
281 pub fn h1<F, B>(self, service: F) -> H1Service<T, S, B, X, U>
283 where
284 B: MessageBody,
285 F: IntoServiceFactory<S, Request>,
286 S::Error: Into<Response<BoxBody>>,
287 S::InitError: fmt::Debug,
288 S::Response: Into<Response<B>>,
289 {
290 let cfg = ServiceConfigBuilder::new()
291 .keep_alive(self.keep_alive)
292 .client_request_timeout(self.client_request_timeout)
293 .client_disconnect_timeout(self.client_disconnect_timeout)
294 .tcp_nodelay(self.tcp_nodelay)
295 .secure(self.secure)
296 .local_addr(self.local_addr)
297 .h1_allow_half_closed(self.h1_allow_half_closed)
298 .h1_write_buffer_size(self.h1_write_buffer_size)
299 .h2_initial_window_size(self.h2_stream_window_size)
300 .h2_initial_connection_window_size(self.h2_conn_window_size)
301 .graceful_shutdown_signal(self.graceful_shutdown_signal)
302 .build();
303
304 H1Service::with_config(cfg, service.into_factory())
305 .expect(self.expect)
306 .upgrade(self.upgrade)
307 .on_connect_ext(self.on_connect_ext)
308 }
309
310 #[cfg(feature = "http2")]
312 pub fn h2<F, B>(self, service: F) -> crate::h2::H2Service<T, S, B>
313 where
314 F: IntoServiceFactory<S, Request>,
315 S::Error: Into<Response<BoxBody>> + 'static,
316 S::InitError: fmt::Debug,
317 S::Response: Into<Response<B>> + 'static,
318
319 B: MessageBody + 'static,
320 {
321 let cfg = ServiceConfigBuilder::new()
322 .keep_alive(self.keep_alive)
323 .client_request_timeout(self.client_request_timeout)
324 .client_disconnect_timeout(self.client_disconnect_timeout)
325 .tcp_nodelay(self.tcp_nodelay)
326 .secure(self.secure)
327 .local_addr(self.local_addr)
328 .h1_allow_half_closed(self.h1_allow_half_closed)
329 .h1_write_buffer_size(self.h1_write_buffer_size)
330 .h2_initial_window_size(self.h2_stream_window_size)
331 .h2_initial_connection_window_size(self.h2_conn_window_size)
332 .graceful_shutdown_signal(self.graceful_shutdown_signal)
333 .build();
334
335 crate::h2::H2Service::with_config(cfg, service.into_factory())
336 .on_connect_ext(self.on_connect_ext)
337 }
338
339 pub fn finish<F, B>(self, service: F) -> HttpService<T, S, B, X, U>
341 where
342 F: IntoServiceFactory<S, Request>,
343 S::Error: Into<Response<BoxBody>> + 'static,
344 S::InitError: fmt::Debug,
345 S::Response: Into<Response<B>> + 'static,
346
347 B: MessageBody + 'static,
348 {
349 let cfg = ServiceConfigBuilder::new()
350 .keep_alive(self.keep_alive)
351 .client_request_timeout(self.client_request_timeout)
352 .client_disconnect_timeout(self.client_disconnect_timeout)
353 .tcp_nodelay(self.tcp_nodelay)
354 .secure(self.secure)
355 .local_addr(self.local_addr)
356 .h1_allow_half_closed(self.h1_allow_half_closed)
357 .h1_write_buffer_size(self.h1_write_buffer_size)
358 .h2_initial_window_size(self.h2_stream_window_size)
359 .h2_initial_connection_window_size(self.h2_conn_window_size)
360 .graceful_shutdown_signal(self.graceful_shutdown_signal)
361 .build();
362
363 HttpService::with_config(cfg, service.into_factory())
364 .expect(self.expect)
365 .upgrade(self.upgrade)
366 .on_connect_ext(self.on_connect_ext)
367 }
368}