1use std::{
2 cell::RefCell,
3 collections::{BTreeMap, HashMap, hash_map::Entry},
4 io::ErrorKind,
5 net::{Shutdown, SocketAddr},
6 os::unix::io::AsRawFd,
7 rc::{Rc, Weak},
8 str::from_utf8_unchecked,
9 time::{Duration, Instant},
10};
11
12use mio::{
13 Interest, Registry, Token,
14 net::{TcpListener as MioTcpListener, TcpStream},
15 unix::SourceFd,
16};
17use rusty_ulid::Ulid;
18use sozu_command::{
19 logging::CachedTags,
20 proto::command::{
21 Cluster, HttpListenerConfig, ListenerType, RemoveListener, RequestHttpFrontend,
22 UpdateHttpListenerConfig, WorkerRequest, WorkerResponse, request::RequestType,
23 },
24 ready::Ready,
25 response::HttpFrontend,
26 state::{ClusterId, validate_h2_flood_knobs_http, validate_sozu_id_header},
27};
28
29use crate::metrics::names;
30use crate::{
31 AcceptError, FrontendFromRequestError, L7ListenerHandler, L7Proxy, ListenerError,
32 ListenerHandler, Protocol, ProxyConfiguration, ProxyError, ProxySession, SessionIsToBeClosed,
33 SessionMetrics, SessionResult, StateMachineBuilder, StateResult,
34 backends::BackendMap,
35 pool::Pool,
36 protocol::{
37 Pipe, SessionState,
38 http::{
39 answers::HttpAnswers,
40 parser::{Method, hostname_and_port},
41 },
42 mux::{self, Mux, MuxClear},
43 proxy_protocol::expect::ExpectProxyProtocol,
44 },
45 router::{RouteResult, Router},
46 server::{ListenToken, SessionManager},
47 socket::server_bind,
48 timer::TimeoutContainer,
49};
50
51#[derive(PartialEq, Eq)]
52pub enum SessionStatus {
53 Normal,
54 DefaultAnswer,
55}
56
57StateMachineBuilder! {
58 enum HttpStateMachine impl SessionState {
64 Expect(ExpectProxyProtocol<TcpStream>),
65 Mux(MuxClear),
66 WebSocket(Pipe<crate::socket::SessionTcpStream, HttpListener>),
67 }
68}
69
70macro_rules! log_module_context {
76 () => {{
77 let (open, reset, _, _, _) = sozu_command::logging::ansi_palette();
78 format!("{open}HTTP{reset}\t >>>", open = open, reset = reset)
79 }};
80}
81
82macro_rules! log_context {
88 ($self:expr) => {{
89 let (open, reset, grey, gray, white) = sozu_command::logging::ansi_palette();
90 format!(
91 "{open}HTTP{reset}\t{grey}Session{reset}({gray}frontend{reset}={white}{frontend}{reset})\t >>>",
92 open = open,
93 reset = reset,
94 grey = grey,
95 gray = gray,
96 white = white,
97 frontend = $self.frontend_token.0,
98 )
99 }};
100}
101
102pub struct HttpSession {
106 configured_backend_timeout: Duration,
107 configured_connect_timeout: Duration,
108 configured_frontend_timeout: Duration,
109 frontend_token: Token,
110 last_event: Instant,
111 listener: Rc<RefCell<HttpListener>>,
112 metrics: SessionMetrics,
113 pool: Weak<RefCell<Pool>>,
114 proxy: Rc<RefCell<HttpProxy>>,
115 state: HttpStateMachine,
116 has_been_closed: bool,
117}
118
119impl HttpSession {
120 #[allow(clippy::too_many_arguments)]
121 pub fn new(
122 configured_backend_timeout: Duration,
123 configured_connect_timeout: Duration,
124 configured_frontend_timeout: Duration,
125 configured_request_timeout: Duration,
126 expect_proxy: bool,
127 listener: Rc<RefCell<HttpListener>>,
128 pool: Weak<RefCell<Pool>>,
129 proxy: Rc<RefCell<HttpProxy>>,
130 public_address: SocketAddr,
131 sock: TcpStream,
132 token: Token,
133 wait_time: Duration,
134 ) -> Result<Self, AcceptError> {
135 let request_id = Ulid::generate();
136 let container_frontend_timeout = TimeoutContainer::new(configured_request_timeout, token);
137
138 let state = if expect_proxy {
139 trace!("{} starting in expect proxy state", log_module_context!());
140 gauge_add!(names::protocol::PROXY_EXPECT, 1);
141
142 HttpStateMachine::Expect(ExpectProxyProtocol::new(
143 container_frontend_timeout,
144 sock,
145 token,
146 request_id,
147 ))
148 } else {
149 gauge_add!(names::protocol::HTTP, 1);
150 let session_address = sock.peer_addr().ok();
151 let session_ulid = rusty_ulid::Ulid::generate();
152 let sock = crate::socket::SessionTcpStream::new(sock, session_ulid, session_address);
153
154 let frontend =
155 mux::Connection::new_h1_server(session_ulid, sock, container_frontend_timeout);
156 let router = mux::Router::new(configured_backend_timeout, configured_connect_timeout);
157 let mut context = mux::Context::new(
158 session_ulid,
159 pool.clone(),
160 listener.clone(),
161 session_address,
162 public_address,
163 );
164 context
165 .create_stream(request_id, 1 << 16)
166 .ok_or(AcceptError::BufferCapacityReached)?;
167 HttpStateMachine::Mux(Mux {
168 configured_frontend_timeout,
169 frontend_token: token,
170 frontend,
171 router,
172 context,
173 session_ulid,
174 })
175 };
176
177 debug_assert_eq!(
184 state.marker() as u8,
185 if expect_proxy {
186 StateMarker::Expect as u8
187 } else {
188 StateMarker::Mux as u8
189 },
190 "constructed state must match the expect_proxy branch"
191 );
192 debug_assert!(
196 !state.failed(),
197 "a newly created session must not start in FailedUpgrade"
198 );
199
200 let metrics = SessionMetrics::new(Some(wait_time));
201 let session = HttpSession {
202 configured_backend_timeout,
203 configured_connect_timeout,
204 configured_frontend_timeout,
205 frontend_token: token,
206 has_been_closed: false,
207 last_event: Instant::now(),
208 listener,
209 metrics,
210 pool,
211 proxy,
212 state,
213 };
214 debug_assert_eq!(
215 session.frontend_token, token,
216 "frontend token must be the slab token used for registration"
217 );
218 #[cfg(debug_assertions)]
219 session.check_invariants();
220 Ok(session)
221 }
222
223 #[cfg(debug_assertions)]
236 fn check_invariants(&self) {
237 let marker = self.state.marker();
238 debug_assert!(
239 matches!(
240 marker,
241 StateMarker::Expect | StateMarker::Mux | StateMarker::WebSocket
242 ),
243 "session marker must be a legal H1 stage (Expect/Mux/WebSocket), got {marker:?}"
244 );
245 debug_assert!(
249 !self.state.failed() || self.has_been_closed,
250 "FailedUpgrade state must be reaped by close(), never left live"
251 );
252 }
253
254 pub fn upgrade(&mut self) -> SessionIsToBeClosed {
255 debug!("{} upgrade", log_context!(self));
256 let from_marker = self.state.marker();
262 let new_state = match self.state.take() {
263 HttpStateMachine::Mux(mux) => self.upgrade_mux(mux),
264 HttpStateMachine::Expect(expect) => self.upgrade_expect(expect),
265 HttpStateMachine::WebSocket(ws) => self.upgrade_websocket(ws),
266 HttpStateMachine::FailedUpgrade(_) => {
267 error!(
271 "{} upgrade called on FailedUpgrade state; closing session",
272 log_context!(self)
273 );
274 None
275 }
276 };
277
278 match new_state {
279 Some(state) => {
280 debug_assert!(
284 matches!(
285 (from_marker, state.marker()),
286 (StateMarker::Expect, StateMarker::Mux)
287 | (StateMarker::Mux, StateMarker::WebSocket)
288 | (StateMarker::WebSocket, StateMarker::WebSocket)
289 ),
290 "illegal protocol-upgrade transition {from_marker:?} -> {:?}",
291 state.marker()
292 );
293 debug_assert!(
294 !state.failed(),
295 "a successful upgrade must not install a FailedUpgrade state"
296 );
297 self.state = state;
298 #[cfg(debug_assertions)]
299 self.check_invariants();
300 false
301 }
302 None => {
304 debug_assert!(
308 self.state.failed(),
309 "a failed upgrade must leave the session in FailedUpgrade"
310 );
311 true
312 }
313 }
314 }
315
316 fn upgrade_expect(
317 &mut self,
318 expect: ExpectProxyProtocol<TcpStream>,
319 ) -> Option<HttpStateMachine> {
320 debug!("{} switching to HTTP", log_context!(self));
321 match expect
322 .addresses
323 .as_ref()
324 .map(|add| (add.destination(), add.source()))
325 {
326 Some((Some(public_address), Some(session_address))) => {
327 let session_ulid = rusty_ulid::Ulid::generate();
328 let frontend = mux::Connection::new_h1_server(
329 session_ulid,
330 crate::socket::SessionTcpStream::new(
331 expect.frontend,
332 session_ulid,
333 Some(session_address),
334 ),
335 expect.container_frontend_timeout,
336 );
337 let router = mux::Router::new(
338 self.configured_backend_timeout,
339 self.configured_connect_timeout,
340 );
341 let mut context = mux::Context::new(
342 session_ulid,
343 self.pool.clone(),
344 self.listener.clone(),
345 Some(session_address),
346 public_address,
347 );
348 if context.create_stream(expect.request_id, 1 << 16).is_none() {
349 error!(
350 "{} expect upgrade failed: could not create stream",
351 log_context!(self)
352 );
353 return None;
354 }
355 let mut mux = Mux {
356 configured_frontend_timeout: self.configured_frontend_timeout,
357 frontend_token: self.frontend_token,
358 frontend,
359 router,
360 context,
361 session_ulid,
362 };
363 mux.frontend.readiness_mut().event = expect.frontend_readiness.event;
364
365 debug_assert_eq!(
369 mux.frontend_token, self.frontend_token,
370 "expect upgrade must preserve the frontend token"
371 );
372 debug_assert_eq!(
375 mux.context.streams.len(),
376 1,
377 "a freshly upgraded Mux owns exactly the request stream"
378 );
379
380 gauge_add!(names::protocol::PROXY_EXPECT, -1);
384 gauge_add!(names::protocol::HTTP, 1);
385 Some(HttpStateMachine::Mux(mux))
386 }
387 _ => {
388 debug!(
389 "{} expect upgrade failed: bad header {:?}",
390 log_context!(self),
391 expect.addresses
392 );
393 None
394 }
395 }
396 }
397
398 fn upgrade_mux(&mut self, mut mux: MuxClear) -> Option<HttpStateMachine> {
399 debug!("{} mux switching to ws", log_context!(self));
400 let Some(stream) = mux.context.streams.pop() else {
401 error!(
402 "{} upgrade_mux: no stream attached to the mux session, closing",
403 log_context!(self)
404 );
405 return None;
406 };
407 let (frontend_readiness, frontend_socket, mut container_frontend_timeout) =
411 match mux.frontend {
412 mux::Connection::H1(mux::ConnectionH1 {
413 readiness,
414 socket,
415 timeout_container,
416 ..
417 }) => (readiness, socket, timeout_container),
418 mux::Connection::H2(_) => {
419 error!(
420 "{} only h1<->h1 connections can upgrade to websocket",
421 log_context!(self)
422 );
423 return None;
424 }
425 };
426
427 let mux::StreamState::Linked(back_token) = stream.state else {
428 error!(
429 "{} upgrading stream should be linked to a backend",
430 log_context!(self)
431 );
432 return None;
433 };
434 debug_assert!(
440 mux.router.backends.contains_key(&back_token),
441 "a Linked stream's back token must index a connected backend"
442 );
443 let backends_before = mux.router.backends.len();
444 let Some(backend) = mux.router.backends.remove(&back_token) else {
445 error!(
446 "{} upgrade_mux: backend for token {:?} is missing (already disconnected?), closing",
447 log_context!(self),
448 back_token
449 );
450 return None;
451 };
452 let (cluster_id, backend, backend_readiness, backend_socket, mut container_backend_timeout) =
453 match backend {
454 mux::Connection::H1(mux::ConnectionH1 {
455 position:
456 mux::Position::Client(cluster_id, backend, mux::BackendStatus::Connected),
457 readiness,
458 socket,
459 timeout_container,
460 ..
461 }) => (cluster_id, backend, readiness, socket, timeout_container),
462 mux::Connection::H1(_) => {
463 error!(
464 "{} the backend disconnected just after upgrade, abort",
465 log_context!(self)
466 );
467 return None;
468 }
469 mux::Connection::H2(_) => {
470 error!(
471 "{} only h1<->h1 connections can upgrade to websocket",
472 log_context!(self)
473 );
474 return None;
475 }
476 };
477
478 debug_assert!(
481 !mux.router.backends.contains_key(&back_token),
482 "the upgraded backend must be evicted from the router map"
483 );
484 debug_assert_eq!(
485 mux.router.backends.len(),
486 backends_before - 1,
487 "removing the backend must drop the backend count by exactly one"
488 );
489
490 let ws_context = stream.context.websocket_context();
491
492 container_frontend_timeout.reset();
493 container_backend_timeout.reset();
494
495 let backend_id = backend.borrow().backend_id.clone();
496 let backend_socket = backend_socket.stream;
501 let mut pipe = Pipe::new(
502 stream.back.storage.buffer,
503 Some(backend_id),
504 Some(backend_socket),
505 Some(backend),
506 Some(container_backend_timeout),
507 Some(container_frontend_timeout),
508 Some(cluster_id),
509 stream.front.storage.buffer,
510 self.frontend_token,
511 frontend_socket,
512 self.listener.clone(),
513 Protocol::HTTP,
514 stream.context.session_id,
515 stream.context.id,
516 stream.context.session_address,
517 ws_context,
518 );
519
520 pipe.restore_readiness_events(frontend_readiness.event, backend_readiness.event);
521 pipe.set_back_token(back_token);
524 debug_assert_eq!(
525 pipe.back_token(),
526 vec![back_token],
527 "websocket pipe must carry exactly the upgraded backend token"
528 );
529
530 gauge_add!(names::protocol::HTTP, -1);
537 gauge_add!(names::protocol::WS, 1);
538 gauge_add!(names::websocket::ACTIVE_REQUESTS, 1);
539 Some(HttpStateMachine::WebSocket(pipe))
540 }
541
542 fn upgrade_websocket(
543 &self,
544 ws: Pipe<crate::socket::SessionTcpStream, HttpListener>,
545 ) -> Option<HttpStateMachine> {
546 error!(
548 "{} upgrade called on WS, this should not happen",
549 log_context!(self)
550 );
551 Some(HttpStateMachine::WebSocket(ws))
552 }
553}
554
555impl ProxySession for HttpSession {
556 fn close(&mut self) {
557 if self.has_been_closed {
558 return;
559 }
560 debug_assert!(
562 !self.has_been_closed,
563 "close past the guard must run on a not-yet-closed session"
564 );
565
566 trace!("{} closing HTTP session", log_context!(self));
567 self.metrics.service_stop();
568
569 match self.state.marker() {
571 StateMarker::Expect => gauge_add!(names::protocol::PROXY_EXPECT, -1),
572 StateMarker::Mux => gauge_add!(names::protocol::HTTP, -1),
573 StateMarker::WebSocket => {
574 gauge_add!(names::protocol::WS, -1);
575 gauge_add!(names::websocket::ACTIVE_REQUESTS, -1);
576 }
577 }
578
579 if self.state.failed() {
580 match self.state.marker() {
581 StateMarker::Expect => incr!(names::http::UPGRADE_EXPECT_FAILED),
582 StateMarker::Mux => incr!(names::http::UPGRADE_MUX_FAILED),
583 StateMarker::WebSocket => incr!(names::http::UPGRADE_WS_FAILED),
584 }
585 self.state.close(self.proxy.clone(), &mut self.metrics);
589 self.proxy.borrow().remove_session(self.frontend_token);
590 self.has_been_closed = true;
591 debug_assert!(
592 self.has_been_closed,
593 "failed-upgrade close path must mark the session closed"
594 );
595 return;
596 }
597
598 self.state.cancel_timeouts();
599 self.state.close(self.proxy.clone(), &mut self.metrics);
601
602 let front_socket = self.state.front_socket();
603 if let Err(e) = front_socket.shutdown(Shutdown::Write) {
608 if e.kind() != ErrorKind::NotConnected {
610 error!(
611 "{} error shutting down front socket({:?}): {:?}",
612 log_context!(self),
613 front_socket,
614 e
615 )
616 }
617 }
618
619 let proxy = self.proxy.borrow();
621 let fd = front_socket.as_raw_fd();
622 if let Err(e) = proxy.registry.deregister(&mut SourceFd(&fd)) {
623 error!(
624 "{} error deregistering front socket({:?}) while closing HTTP session: {:?}",
625 log_context!(self),
626 fd,
627 e
628 );
629 }
630 proxy.remove_session(self.frontend_token);
631
632 self.has_been_closed = true;
633 debug_assert!(
634 self.has_been_closed,
635 "close must leave the session marked closed (idempotency latch)"
636 );
637 }
638
639 fn timeout(&mut self, token: Token) -> SessionIsToBeClosed {
640 let state_result = self.state.timeout(token, &mut self.metrics);
641 state_result == StateResult::CloseSession
642 }
643
644 fn protocol(&self) -> Protocol {
645 Protocol::HTTP
646 }
647
648 fn update_readiness(&mut self, token: Token, events: Ready) {
649 trace!(
650 "{} token {:?} got event {}",
651 log_context!(self),
652 token,
653 super::ready_to_string(events)
654 );
655 self.last_event = Instant::now();
656 self.metrics.wait_start();
657 self.state.update_readiness(token, events);
658 }
659
660 fn ready(&mut self, session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
661 self.metrics.service_start();
662
663 let session_result =
664 self.state
665 .ready(session.clone(), self.proxy.clone(), &mut self.metrics);
666
667 let to_be_closed = match session_result {
668 SessionResult::Close => true,
669 SessionResult::Continue => false,
670 SessionResult::Upgrade => match self.upgrade() {
671 false => self.ready(session),
672 true => true,
673 },
674 };
675
676 self.metrics.service_stop();
677 #[cfg(debug_assertions)]
682 if !to_be_closed {
683 self.check_invariants();
684 }
685 to_be_closed
686 }
687
688 fn shutting_down(&mut self) -> SessionIsToBeClosed {
689 self.state.shutting_down()
690 }
691
692 fn last_event(&self) -> Instant {
693 self.last_event
694 }
695
696 fn print_session(&self) {
697 self.state.print_state("HTTP");
698 error!("{} Metrics: {:?}", log_context!(self), self.metrics);
699 }
700
701 fn frontend_token(&self) -> Token {
702 self.frontend_token
703 }
704}
705
706pub type Hostname = String;
707
708pub struct HttpListener {
730 active: bool,
731 address: SocketAddr,
732 answers: Rc<RefCell<HttpAnswers>>,
733 config: HttpListenerConfig,
734 fronts: Router,
735 listener: Option<MioTcpListener>,
736 tags: BTreeMap<String, CachedTags>,
737 token: Token,
738}
739
740impl ListenerHandler for HttpListener {
741 fn get_addr(&self) -> &SocketAddr {
742 &self.address
743 }
744
745 fn get_tags(&self, key: &str) -> Option<&CachedTags> {
746 self.tags.get(key)
747 }
748
749 fn set_tags(&mut self, key: String, tags: Option<BTreeMap<String, String>>) {
750 match tags {
751 Some(tags) => self.tags.insert(key, CachedTags::new(tags)),
752 None => self.tags.remove(&key),
753 };
754 }
755
756 fn protocol(&self) -> Protocol {
757 Protocol::HTTP
758 }
759
760 fn public_address(&self) -> SocketAddr {
761 self.config
762 .public_address
763 .map(|addr| addr.into())
764 .unwrap_or(self.address)
765 }
766}
767
768impl L7ListenerHandler for HttpListener {
769 fn get_sticky_name(&self) -> &str {
770 &self.config.sticky_name
771 }
772
773 fn get_sozu_id_header(&self) -> &str {
774 self.config
775 .sozu_id_header
776 .as_deref()
777 .filter(|s| !s.is_empty())
778 .unwrap_or("Sozu-Id")
779 }
780
781 fn get_connect_timeout(&self) -> u32 {
782 self.config.connect_timeout
783 }
784
785 fn frontend_from_request(
787 &self,
788 host: &str,
789 uri: &str,
790 method: &Method,
791 ) -> Result<RouteResult, FrontendFromRequestError> {
792 let start = Instant::now();
793 let (remaining_input, (hostname, _)) = match hostname_and_port(host.as_bytes()) {
794 Ok(tuple) => tuple,
795 Err(parse_error) => {
796 return Err(FrontendFromRequestError::HostParse {
798 host: host.to_owned(),
799 error: parse_error.to_string(),
800 });
801 }
802 };
803 if remaining_input != &b""[..] {
804 return Err(FrontendFromRequestError::InvalidCharsAfterHost(
805 host.to_owned(),
806 ));
807 }
808
809 let host = unsafe { from_utf8_unchecked(hostname) };
824
825 let route = self.fronts.lookup(host, uri, method).map_err(|e| {
826 incr!(names::http::FAILED_BACKEND_MATCHING);
827 FrontendFromRequestError::NoClusterFound(e)
828 })?;
829
830 let now = Instant::now();
831
832 if let Some(cluster) = route.cluster_id.as_deref() {
833 time!(
834 names::event_loop::FRONTEND_MATCHING_TIME,
835 cluster,
836 (now - start).as_millis()
837 );
838 }
839
840 Ok(route)
841 }
842
843 fn get_answers(&self) -> &Rc<RefCell<HttpAnswers>> {
844 &self.answers
845 }
846
847 fn get_h2_flood_config(&self) -> crate::protocol::mux::H2FloodConfig {
848 let defaults = crate::protocol::mux::H2FloodConfig::default();
849 crate::protocol::mux::H2FloodConfig {
850 max_rst_stream_per_window: self
851 .config
852 .h2_max_rst_stream_per_window
853 .unwrap_or(defaults.max_rst_stream_per_window),
854 max_ping_per_window: self
855 .config
856 .h2_max_ping_per_window
857 .unwrap_or(defaults.max_ping_per_window),
858 max_settings_per_window: self
859 .config
860 .h2_max_settings_per_window
861 .unwrap_or(defaults.max_settings_per_window),
862 max_empty_data_per_window: self
863 .config
864 .h2_max_empty_data_per_window
865 .unwrap_or(defaults.max_empty_data_per_window),
866 max_window_update_stream0_per_window: self
867 .config
868 .h2_max_window_update_stream0_per_window
869 .unwrap_or(defaults.max_window_update_stream0_per_window),
870 max_continuation_frames: self
871 .config
872 .h2_max_continuation_frames
873 .unwrap_or(defaults.max_continuation_frames),
874 max_glitch_count: self
875 .config
876 .h2_max_glitch_count
877 .unwrap_or(defaults.max_glitch_count),
878 max_rst_stream_lifetime: self
879 .config
880 .h2_max_rst_stream_lifetime
881 .unwrap_or(defaults.max_rst_stream_lifetime),
882 max_rst_stream_abusive_lifetime: self
883 .config
884 .h2_max_rst_stream_abusive_lifetime
885 .unwrap_or(defaults.max_rst_stream_abusive_lifetime),
886 max_rst_stream_emitted_lifetime: self
887 .config
888 .h2_max_rst_stream_emitted_lifetime
889 .unwrap_or(defaults.max_rst_stream_emitted_lifetime),
890 max_header_list_size: self
891 .config
892 .h2_max_header_list_size
893 .unwrap_or(defaults.max_header_list_size),
894 max_header_table_size: self
895 .config
896 .h2_max_header_table_size
897 .unwrap_or(defaults.max_header_table_size),
898 max_header_fields: self
899 .config
900 .h2_max_header_fields
901 .unwrap_or(defaults.max_header_fields),
902 }
903 }
904
905 fn get_h2_connection_config(&self) -> crate::protocol::mux::H2ConnectionConfig {
906 crate::protocol::mux::H2ConnectionConfig::from_optional(
907 self.config.h2_initial_connection_window,
908 self.config.h2_max_concurrent_streams,
909 self.config.h2_stream_shrink_ratio,
910 )
911 }
912
913 fn get_h2_stream_idle_timeout(&self) -> std::time::Duration {
914 let seconds = self
921 .config
922 .h2_stream_idle_timeout_seconds
923 .map(|s| u64::from(s.max(1)))
924 .unwrap_or_else(|| u64::from(self.config.back_timeout).max(30));
925 std::time::Duration::from_secs(seconds)
926 }
927
928 fn get_h2_graceful_shutdown_deadline(&self) -> Option<std::time::Duration> {
929 match self.config.h2_graceful_shutdown_deadline_seconds {
930 None => Some(std::time::Duration::from_secs(5)),
931 Some(0) => None,
932 Some(s) => Some(std::time::Duration::from_secs(u64::from(s))),
933 }
934 }
935
936 fn get_elide_x_real_ip(&self) -> bool {
937 self.config.elide_x_real_ip.unwrap_or(false)
938 }
939
940 fn get_send_x_real_ip(&self) -> bool {
941 self.config.send_x_real_ip.unwrap_or(false)
942 }
943}
944
945pub struct HttpProxy {
946 backends: Rc<RefCell<BackendMap>>,
947 clusters: HashMap<ClusterId, Cluster>,
948 listeners: HashMap<Token, Rc<RefCell<HttpListener>>>,
949 pool: Rc<RefCell<Pool>>,
950 registry: Registry,
951 sessions: Rc<RefCell<SessionManager>>,
952}
953
954impl HttpProxy {
955 pub fn new(
956 registry: Registry,
957 sessions: Rc<RefCell<SessionManager>>,
958 pool: Rc<RefCell<Pool>>,
959 backends: Rc<RefCell<BackendMap>>,
960 ) -> HttpProxy {
961 HttpProxy {
962 backends,
963 clusters: HashMap::new(),
964 listeners: HashMap::new(),
965 pool,
966 registry,
967 sessions,
968 }
969 }
970
971 pub fn add_listener(
972 &mut self,
973 config: HttpListenerConfig,
974 token: Token,
975 ) -> Result<Token, ProxyError> {
976 match self.listeners.entry(token) {
977 Entry::Vacant(entry) => {
978 let http_listener =
979 HttpListener::new(config, token).map_err(ProxyError::AddListener)?;
980 entry.insert(Rc::new(RefCell::new(http_listener)));
981 Ok(token)
982 }
983 _ => Err(ProxyError::ListenerAlreadyPresent),
984 }
985 }
986
987 pub fn get_listener(&self, token: &Token) -> Option<Rc<RefCell<HttpListener>>> {
988 self.listeners.get(token).cloned()
989 }
990
991 pub fn remove_listener(&mut self, remove: RemoveListener) -> Result<(), ProxyError> {
992 let len = self.listeners.len();
993 let remove_address = remove.address.into();
994 self.listeners
995 .retain(|_, l| l.borrow().address != remove_address);
996
997 if !self.listeners.len() < len {
998 info!(
999 "{} no HTTP listener to remove at address {:?}",
1000 log_module_context!(),
1001 remove_address
1002 );
1003 }
1004 Ok(())
1005 }
1006
1007 pub fn activate_listener(
1008 &self,
1009 addr: &SocketAddr,
1010 tcp_listener: Option<MioTcpListener>,
1011 ) -> Result<Token, ProxyError> {
1012 let listener = self
1013 .listeners
1014 .values()
1015 .find(|listener| listener.borrow().address == *addr)
1016 .ok_or(ProxyError::NoListenerFound(addr.to_owned()))?;
1017
1018 listener
1019 .borrow_mut()
1020 .activate(&self.registry, tcp_listener)
1021 .map_err(|listener_error| ProxyError::ListenerActivation {
1022 address: *addr,
1023 listener_error,
1024 })
1025 }
1026
1027 pub fn give_back_listeners(&mut self) -> Vec<(SocketAddr, MioTcpListener)> {
1028 self.listeners
1029 .iter()
1030 .filter_map(|(_, listener)| {
1031 let mut owned = listener.borrow_mut();
1032 if let Some(listener) = owned.listener.take() {
1033 owned.active = false;
1036 return Some((owned.address, listener));
1037 }
1038
1039 None
1040 })
1041 .collect()
1042 }
1043
1044 pub fn give_back_listener(
1045 &mut self,
1046 address: SocketAddr,
1047 ) -> Result<(Token, MioTcpListener), ProxyError> {
1048 let listener = self
1049 .listeners
1050 .values()
1051 .find(|listener| listener.borrow().address == address)
1052 .ok_or(ProxyError::NoListenerFound(address))?;
1053
1054 let mut owned = listener.borrow_mut();
1055
1056 let taken_listener = owned
1057 .listener
1058 .take()
1059 .ok_or(ProxyError::UnactivatedListener)?;
1060
1061 owned.active = false;
1064
1065 Ok((owned.token, taken_listener))
1066 }
1067
1068 pub fn update_listener(&mut self, patch: UpdateHttpListenerConfig) -> Result<(), ProxyError> {
1070 let address: std::net::SocketAddr = patch.address.into();
1071 let listener = self
1072 .listeners
1073 .values()
1074 .find(|l| l.borrow().address == address)
1075 .ok_or(ProxyError::NoListenerFound(address))?;
1076 listener
1077 .borrow_mut()
1078 .update_config(&patch)
1079 .map_err(|listener_error| ProxyError::ListenerActivation {
1080 address,
1081 listener_error,
1082 })
1083 }
1084
1085 pub fn add_cluster(&mut self, mut cluster: Cluster) -> Result<(), ProxyError> {
1086 let mut overrides = cluster.answers.clone();
1089 if let Some(answer_503) = cluster.answer_503.take() {
1090 overrides.entry("503".to_owned()).or_insert(answer_503);
1091 }
1092 if !overrides.is_empty() {
1093 for listener in self.listeners.values() {
1094 listener
1095 .borrow()
1096 .answers
1097 .borrow_mut()
1098 .add_cluster_answers(&cluster.cluster_id, &overrides)
1099 .map_err(|(name, error)| {
1100 ProxyError::AddCluster(ListenerError::TemplateParse(name, error))
1101 })?;
1102 }
1103 }
1104 self.clusters.insert(cluster.cluster_id.clone(), cluster);
1105 Ok(())
1106 }
1107
1108 pub fn remove_cluster(&mut self, cluster_id: &str) -> Result<(), ProxyError> {
1109 self.clusters.remove(cluster_id);
1110
1111 for listener in self.listeners.values() {
1112 listener
1113 .borrow()
1114 .answers
1115 .borrow_mut()
1116 .remove_cluster_answers(cluster_id);
1117 }
1118 Ok(())
1119 }
1120
1121 pub fn add_http_frontend(&mut self, front: RequestHttpFrontend) -> Result<(), ProxyError> {
1122 if front.hsts.is_some() {
1137 incr!(names::http::HSTS_SUPPRESSED_PLAINTEXT);
1138 return Err(ProxyError::HstsOnPlainHttp(front.address.into()));
1139 }
1140
1141 let front = front.clone().to_frontend().map_err(|request_error| {
1142 ProxyError::WrongInputFrontend {
1143 front: Box::new(front),
1144 error: request_error.to_string(),
1145 }
1146 })?;
1147
1148 let mut listener = self
1149 .listeners
1150 .values()
1151 .find(|l| l.borrow().address == front.address)
1152 .ok_or(ProxyError::NoListenerFound(front.address))?
1153 .borrow_mut();
1154
1155 let hostname = front.hostname.to_owned();
1156 let tags = front.tags.to_owned();
1157
1158 listener
1159 .add_http_front(front)
1160 .map_err(ProxyError::AddFrontend)?;
1161 listener.set_tags(hostname, tags);
1162 Ok(())
1163 }
1164
1165 pub fn remove_http_frontend(&mut self, front: RequestHttpFrontend) -> Result<(), ProxyError> {
1166 let front = front.clone().to_frontend().map_err(|request_error| {
1167 ProxyError::WrongInputFrontend {
1168 front: Box::new(front),
1169 error: request_error.to_string(),
1170 }
1171 })?;
1172
1173 let mut listener = self
1174 .listeners
1175 .values()
1176 .find(|l| l.borrow().address == front.address)
1177 .ok_or(ProxyError::NoListenerFound(front.address))?
1178 .borrow_mut();
1179
1180 let hostname = front.hostname.to_owned();
1181
1182 listener
1183 .remove_http_front(front)
1184 .map_err(ProxyError::RemoveFrontend)?;
1185
1186 if !listener.fronts.has_hostname(&hostname) {
1187 listener.set_tags(hostname, None);
1188 }
1189 Ok(())
1190 }
1191
1192 pub fn soft_stop(&mut self) -> Result<(), ProxyError> {
1193 let listeners: HashMap<_, _> = self.listeners.drain().collect();
1194 let mut socket_errors = vec![];
1195 for (_, l) in listeners.iter() {
1196 if let Some(mut sock) = l.borrow_mut().listener.take() {
1197 debug!("{} deregistering socket {:?}", log_module_context!(), sock);
1198 if let Err(e) = self.registry.deregister(&mut sock) {
1199 let error = format!("socket {sock:?}: {e:?}");
1200 socket_errors.push(error);
1201 }
1202 }
1203 }
1204
1205 if !socket_errors.is_empty() {
1206 return Err(ProxyError::SoftStop {
1207 proxy_protocol: "HTTP".to_string(),
1208 error: format!("Error deregistering listen sockets: {socket_errors:?}"),
1209 });
1210 }
1211
1212 Ok(())
1213 }
1214
1215 pub fn hard_stop(&mut self) -> Result<(), ProxyError> {
1216 let mut listeners: HashMap<_, _> = self.listeners.drain().collect();
1217 let mut socket_errors = vec![];
1218 for (_, l) in listeners.drain() {
1219 if let Some(mut sock) = l.borrow_mut().listener.take() {
1220 debug!("{} deregistering socket {:?}", log_module_context!(), sock);
1221 if let Err(e) = self.registry.deregister(&mut sock) {
1222 let error = format!("socket {sock:?}: {e:?}");
1223 socket_errors.push(error);
1224 }
1225 }
1226 }
1227
1228 if !socket_errors.is_empty() {
1229 return Err(ProxyError::HardStop {
1230 proxy_protocol: "HTTP".to_string(),
1231 error: format!("Error deregistering listen sockets: {socket_errors:?}"),
1232 });
1233 }
1234
1235 Ok(())
1236 }
1237}
1238
1239impl HttpListener {
1240 pub fn new(config: HttpListenerConfig, token: Token) -> Result<HttpListener, ListenerError> {
1241 Ok(HttpListener {
1242 active: false,
1243 address: config.address.into(),
1244 answers: Rc::new(RefCell::new({
1245 let mut answers_map = config.answers.clone();
1250 if let Some(ref legacy) = config.http_answers {
1251 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1252 }
1253 HttpAnswers::new(&answers_map)
1254 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?
1255 })),
1256 config,
1257 fronts: Router::new(),
1258 listener: None,
1259 tags: BTreeMap::new(),
1260 token,
1261 })
1262 }
1263
1264 pub fn activate(
1265 &mut self,
1266 registry: &Registry,
1267 tcp_listener: Option<MioTcpListener>,
1268 ) -> Result<Token, ListenerError> {
1269 if self.active {
1270 return Ok(self.token);
1271 }
1272 let address: SocketAddr = self.config.address.into();
1273
1274 let mut listener = match tcp_listener {
1275 Some(tcp_listener) => tcp_listener,
1276 None => {
1277 server_bind(address).map_err(|server_bind_error| ListenerError::Activation {
1278 address,
1279 error: server_bind_error.to_string(),
1280 })?
1281 }
1282 };
1283
1284 registry
1285 .register(&mut listener, self.token, Interest::READABLE)
1286 .map_err(ListenerError::SocketRegistration)?;
1287
1288 self.listener = Some(listener);
1289 self.active = true;
1290 Ok(self.token)
1291 }
1292
1293 pub fn update_config(&mut self, patch: &UpdateHttpListenerConfig) -> Result<(), ListenerError> {
1299 validate_h2_flood_knobs_http(patch)?;
1304 if let Some(ref hdr) = patch.sozu_id_header {
1305 validate_sozu_id_header(hdr)?;
1306 }
1307
1308 if let Some(v) = patch.public_address {
1309 self.config.public_address = Some(v);
1310 }
1311 if let Some(v) = patch.expect_proxy {
1312 self.config.expect_proxy = v;
1313 }
1314 if let Some(ref v) = patch.sticky_name {
1315 self.config.sticky_name = v.to_owned();
1316 }
1317 if let Some(v) = patch.front_timeout {
1318 self.config.front_timeout = v;
1319 }
1320 if let Some(v) = patch.back_timeout {
1321 self.config.back_timeout = v;
1322 }
1323 if let Some(v) = patch.connect_timeout {
1324 self.config.connect_timeout = v;
1325 }
1326 if let Some(v) = patch.request_timeout {
1327 self.config.request_timeout = v;
1328 }
1329 if let Some(ref v) = patch.sozu_id_header {
1330 self.config.sozu_id_header = Some(v.to_owned());
1331 }
1332 if let Some(v) = patch.elide_x_real_ip {
1333 self.config.elide_x_real_ip = Some(v);
1334 }
1335 if let Some(v) = patch.send_x_real_ip {
1336 self.config.send_x_real_ip = Some(v);
1337 }
1338
1339 if let Some(v) = patch.h2_max_rst_stream_per_window {
1341 self.config.h2_max_rst_stream_per_window = Some(v);
1342 }
1343 if let Some(v) = patch.h2_max_ping_per_window {
1344 self.config.h2_max_ping_per_window = Some(v);
1345 }
1346 if let Some(v) = patch.h2_max_settings_per_window {
1347 self.config.h2_max_settings_per_window = Some(v);
1348 }
1349 if let Some(v) = patch.h2_max_empty_data_per_window {
1350 self.config.h2_max_empty_data_per_window = Some(v);
1351 }
1352 if let Some(v) = patch.h2_max_continuation_frames {
1353 self.config.h2_max_continuation_frames = Some(v);
1354 }
1355 if let Some(v) = patch.h2_max_glitch_count {
1356 self.config.h2_max_glitch_count = Some(v);
1357 }
1358 if let Some(v) = patch.h2_initial_connection_window {
1359 self.config.h2_initial_connection_window = Some(v);
1360 }
1361 if let Some(v) = patch.h2_max_concurrent_streams {
1362 self.config.h2_max_concurrent_streams = Some(v);
1363 }
1364 if let Some(v) = patch.h2_stream_shrink_ratio {
1365 self.config.h2_stream_shrink_ratio = Some(v);
1366 }
1367 if let Some(v) = patch.h2_max_rst_stream_lifetime {
1368 self.config.h2_max_rst_stream_lifetime = Some(v);
1369 }
1370 if let Some(v) = patch.h2_max_rst_stream_abusive_lifetime {
1371 self.config.h2_max_rst_stream_abusive_lifetime = Some(v);
1372 }
1373 if let Some(v) = patch.h2_max_rst_stream_emitted_lifetime {
1374 self.config.h2_max_rst_stream_emitted_lifetime = Some(v);
1375 }
1376 if let Some(v) = patch.h2_max_header_list_size {
1377 self.config.h2_max_header_list_size = Some(v);
1378 }
1379 if let Some(v) = patch.h2_max_header_table_size {
1380 self.config.h2_max_header_table_size = Some(v);
1381 }
1382 if let Some(v) = patch.h2_max_header_fields {
1383 self.config.h2_max_header_fields = Some(v);
1384 }
1385 if let Some(v) = patch.h2_stream_idle_timeout_seconds {
1386 self.config.h2_stream_idle_timeout_seconds = Some(v);
1387 }
1388 if let Some(v) = patch.h2_graceful_shutdown_deadline_seconds {
1389 self.config.h2_graceful_shutdown_deadline_seconds = Some(v);
1390 }
1391 if let Some(v) = patch.h2_max_window_update_stream0_per_window {
1392 self.config.h2_max_window_update_stream0_per_window = Some(v);
1393 }
1394
1395 let answers_changed = patch.http_answers.is_some() || !patch.answers.is_empty();
1400 if answers_changed {
1401 if let Some(ref new_answers) = patch.http_answers {
1402 crate::sozu_command::state::merge_custom_http_answers(
1403 &mut self.config.http_answers,
1404 new_answers,
1405 );
1406 }
1407 for (code, body) in &patch.answers {
1408 if !body.is_empty() {
1409 self.config.answers.insert(code.clone(), body.clone());
1410 }
1411 }
1412
1413 let mut answers_map = self.config.answers.clone();
1414 if let Some(ref legacy) = self.config.http_answers {
1415 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1416 }
1417 let mut new_answers = HttpAnswers::new(&answers_map)
1420 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?;
1421 let preserved = std::mem::take(&mut self.answers.borrow_mut().cluster_answers);
1422 new_answers.cluster_answers = preserved;
1423 *self.answers.borrow_mut() = new_answers;
1424 }
1425
1426 Ok(())
1427 }
1428
1429 pub fn add_http_front(&mut self, http_front: HttpFrontend) -> Result<(), ListenerError> {
1430 self.fronts
1431 .add_http_front(&http_front)
1432 .map_err(ListenerError::AddFrontend)
1433 }
1434
1435 pub fn remove_http_front(&mut self, http_front: HttpFrontend) -> Result<(), ListenerError> {
1436 debug!(
1437 "{} removing http_front {:?}",
1438 log_module_context!(),
1439 http_front
1440 );
1441 self.fronts
1442 .remove_http_front(&http_front)
1443 .map_err(ListenerError::RemoveFrontend)
1444 }
1445
1446 fn accept(&mut self) -> Result<TcpStream, AcceptError> {
1447 if let Some(ref sock) = self.listener {
1448 sock.accept()
1449 .map_err(|e| match e.kind() {
1450 ErrorKind::WouldBlock => AcceptError::WouldBlock,
1451 _ => {
1452 error!("{} accept() IO error: {:?}", log_module_context!(), e);
1453 AcceptError::IoError
1454 }
1455 })
1456 .map(|(sock, _)| sock)
1457 } else {
1458 error!(
1459 "{} cannot accept connections, no listening socket available",
1460 log_module_context!()
1461 );
1462 Err(AcceptError::IoError)
1463 }
1464 }
1465}
1466
1467impl ProxyConfiguration for HttpProxy {
1468 fn notify(&mut self, request: WorkerRequest) -> WorkerResponse {
1469 let request_id = request.id.clone();
1470
1471 let result = match request.content.request_type {
1472 Some(RequestType::AddCluster(cluster)) => {
1473 debug!(
1474 "{} {} add cluster {:?}",
1475 log_module_context!(),
1476 request.id,
1477 cluster
1478 );
1479 self.add_cluster(cluster)
1480 }
1481 Some(RequestType::RemoveCluster(cluster_id)) => {
1482 debug!(
1483 "{} {} remove cluster {:?}",
1484 log_module_context!(),
1485 request_id,
1486 cluster_id
1487 );
1488 self.remove_cluster(&cluster_id)
1489 }
1490 Some(RequestType::AddHttpFrontend(front)) => {
1491 debug!(
1492 "{} {} add front {:?}",
1493 log_module_context!(),
1494 request_id,
1495 front
1496 );
1497 self.add_http_frontend(front)
1498 }
1499 Some(RequestType::RemoveHttpFrontend(front)) => {
1500 debug!(
1501 "{} {} remove front {:?}",
1502 log_module_context!(),
1503 request_id,
1504 front
1505 );
1506 self.remove_http_frontend(front)
1507 }
1508 Some(RequestType::RemoveListener(remove)) => {
1509 debug!(
1510 "{} removing HTTP listener at address {:?}",
1511 log_module_context!(),
1512 remove.address
1513 );
1514 self.remove_listener(remove)
1515 }
1516 Some(RequestType::SoftStop(_)) => {
1517 debug!(
1518 "{} {} processing soft shutdown",
1519 log_module_context!(),
1520 request_id
1521 );
1522 match self.soft_stop() {
1523 Ok(()) => {
1524 info!(
1525 "{} {} soft stop successful",
1526 log_module_context!(),
1527 request_id
1528 );
1529 return WorkerResponse::processing(request.id);
1530 }
1531 Err(e) => Err(e),
1532 }
1533 }
1534 Some(RequestType::HardStop(_)) => {
1535 debug!(
1536 "{} {} processing hard shutdown",
1537 log_module_context!(),
1538 request_id
1539 );
1540 match self.hard_stop() {
1541 Ok(()) => {
1542 info!(
1543 "{} {} hard stop successful",
1544 log_module_context!(),
1545 request_id
1546 );
1547 return WorkerResponse::processing(request.id);
1548 }
1549 Err(e) => Err(e),
1550 }
1551 }
1552 Some(RequestType::Status(_)) => {
1553 debug!("{} {} status", log_module_context!(), request_id);
1554 Ok(())
1555 }
1556 other_command => {
1557 debug!(
1558 "{} {} unsupported message for HTTP proxy, ignoring: {:?}",
1559 log_module_context!(),
1560 request.id,
1561 other_command
1562 );
1563 Err(ProxyError::UnsupportedMessage)
1564 }
1565 };
1566
1567 match result {
1568 Ok(()) => {
1569 debug!("{} {} successful", log_module_context!(), request_id);
1570 WorkerResponse::ok(request_id)
1571 }
1572 Err(proxy_error) => {
1573 debug!(
1574 "{} {} unsuccessful: {}",
1575 log_module_context!(),
1576 request_id,
1577 proxy_error
1578 );
1579 WorkerResponse::error(request_id, proxy_error)
1580 }
1581 }
1582 }
1583
1584 fn accept(&mut self, token: ListenToken) -> Result<TcpStream, AcceptError> {
1585 if let Some(listener) = self.listeners.get(&Token(token.0)) {
1586 listener.borrow_mut().accept()
1587 } else {
1588 Err(AcceptError::IoError)
1589 }
1590 }
1591
1592 fn create_session(
1593 &mut self,
1594 mut frontend_sock: TcpStream,
1595 listener_token: ListenToken,
1596 wait_time: Duration,
1597 proxy: Rc<RefCell<Self>>,
1598 ) -> Result<(), AcceptError> {
1599 let listener = self
1600 .listeners
1601 .get(&Token(listener_token.0))
1602 .cloned()
1603 .ok_or(AcceptError::IoError)?;
1604
1605 if let Err(e) = frontend_sock.set_nodelay(true) {
1606 error!(
1607 "{} error setting nodelay on front socket({:?}): {:?}",
1608 log_module_context!(),
1609 frontend_sock,
1610 e
1611 );
1612 }
1613 let mut session_manager = self.sessions.borrow_mut();
1614 let slab_len_before = session_manager.slab.len();
1615 let session_entry = session_manager.slab.vacant_entry();
1616 let session_token = Token(session_entry.key());
1617 debug_assert_eq!(
1622 session_token.0,
1623 session_entry.key(),
1624 "session token must equal the slab vacant-entry key"
1625 );
1626 let owned = listener.borrow();
1627
1628 if let Err(register_error) = self.registry.register(
1629 &mut frontend_sock,
1630 session_token,
1631 Interest::READABLE | Interest::WRITABLE,
1632 ) {
1633 error!(
1634 "{} error registering listen socket({:?}): {:?}",
1635 log_module_context!(),
1636 frontend_sock,
1637 register_error
1638 );
1639 return Err(AcceptError::RegisterError);
1640 }
1641
1642 let public_address: SocketAddr = match owned.config.public_address {
1643 Some(pub_addr) => pub_addr.into(),
1644 None => owned.config.address.into(),
1645 };
1646
1647 let session = HttpSession::new(
1648 Duration::from_secs(owned.config.back_timeout as u64),
1649 Duration::from_secs(owned.config.connect_timeout as u64),
1650 Duration::from_secs(owned.config.front_timeout as u64),
1651 Duration::from_secs(owned.config.request_timeout as u64),
1652 owned.config.expect_proxy,
1653 listener.clone(),
1654 Rc::downgrade(&self.pool),
1655 proxy,
1656 public_address,
1657 frontend_sock,
1658 session_token,
1659 wait_time,
1660 )?;
1661
1662 debug_assert_eq!(
1666 session.frontend_token, session_token,
1667 "session must own the frontend token it was created with"
1668 );
1669
1670 let session = Rc::new(RefCell::new(session));
1671 session_entry.insert(session);
1672 debug_assert_eq!(
1676 session_manager.slab.len(),
1677 slab_len_before + 1,
1678 "creating a session must occupy exactly one new slab slot"
1679 );
1680
1681 Ok(())
1682 }
1683}
1684
1685impl L7Proxy for HttpProxy {
1686 fn kind(&self) -> ListenerType {
1687 ListenerType::Http
1688 }
1689
1690 fn register_socket(
1691 &self,
1692 source: &mut TcpStream,
1693 token: Token,
1694 interest: Interest,
1695 ) -> Result<(), std::io::Error> {
1696 self.registry.register(source, token, interest)
1697 }
1698
1699 fn deregister_socket(&self, tcp_stream: &mut TcpStream) -> Result<(), std::io::Error> {
1700 self.registry.deregister(tcp_stream)
1701 }
1702
1703 fn add_session(&self, session: Rc<RefCell<dyn ProxySession>>) -> Token {
1704 let mut session_manager = self.sessions.borrow_mut();
1705 let len_before = session_manager.slab.len();
1706 let entry = session_manager.slab.vacant_entry();
1707 let token = Token(entry.key());
1708 let _entry = entry.insert(session);
1709 debug_assert_eq!(
1712 session_manager.slab.len(),
1713 len_before + 1,
1714 "add_session must occupy exactly one new slab slot"
1715 );
1716 debug_assert!(
1717 session_manager.slab.contains(token.0),
1718 "the returned token must index the freshly inserted session"
1719 );
1720 token
1721 }
1722
1723 fn remove_session(&self, token: Token) -> bool {
1724 let mut sessions = self.sessions.borrow_mut();
1725 let was_present = sessions.slab.contains(token.0);
1726 let len_before = sessions.slab.len();
1727 sessions.untrack_all_cluster_ip(token);
1733 let removed = sessions.slab.try_remove(token.0).is_some();
1734 debug_assert_eq!(
1738 removed, was_present,
1739 "try_remove reports presence iff the slot was occupied"
1740 );
1741 debug_assert_eq!(
1742 sessions.slab.len(),
1743 len_before - removed as usize,
1744 "slab len drops by exactly one iff a session was removed"
1745 );
1746 debug_assert!(
1747 !sessions.slab.contains(token.0),
1748 "the slot must be free after remove_session"
1749 );
1750 removed
1751 }
1752
1753 fn backends(&self) -> Rc<RefCell<BackendMap>> {
1754 self.backends.clone()
1755 }
1756
1757 fn clusters(&self) -> &HashMap<ClusterId, Cluster> {
1758 &self.clusters
1759 }
1760
1761 fn sessions(&self) -> Rc<RefCell<SessionManager>> {
1762 self.sessions.clone()
1763 }
1764}
1765
1766pub mod testing {
1767 use crate::testing::*;
1768
1769 pub fn start_http_worker(
1771 config: HttpListenerConfig,
1772 channel: ProxyChannel,
1773 max_buffers: usize,
1774 buffer_size: usize,
1775 ) -> anyhow::Result<()> {
1776 let address = config.address.into();
1777
1778 let ServerParts {
1779 event_loop,
1780 registry,
1781 sessions,
1782 pool,
1783 backends,
1784 client_scm_socket: _,
1785 server_scm_socket,
1786 server_config,
1787 } = prebuild_server(max_buffers, buffer_size, true)?;
1788
1789 let token = {
1790 let mut sessions = sessions.borrow_mut();
1791 let entry = sessions.slab.vacant_entry();
1792 let key = entry.key();
1793 let _ = entry.insert(Rc::new(RefCell::new(ListenSession {
1794 protocol: Protocol::HTTPListen,
1795 })));
1796 Token(key)
1797 };
1798
1799 let mut proxy = HttpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone());
1800 proxy
1801 .add_listener(config, token)
1802 .with_context(|| "Failed at creating adding the listener")?;
1803 proxy
1804 .activate_listener(&address, None)
1805 .with_context(|| "Failed at creating activating the listener")?;
1806
1807 let mut server = Server::new(
1808 event_loop,
1809 channel,
1810 server_scm_socket,
1811 sessions,
1812 pool,
1813 backends,
1814 Some(proxy),
1815 None,
1816 None,
1817 server_config,
1818 None,
1819 false,
1820 )
1821 .with_context(|| "Failed at creating server")?;
1822
1823 debug!("{} starting event loop", log_module_context!());
1824 server.run();
1825 debug!("{} ending event loop", log_module_context!());
1826 Ok(())
1827 }
1828}
1829
1830#[cfg(test)]
1831mod tests {
1832 extern crate tiny_http;
1833
1834 use std::{
1835 io::{Read, Write},
1836 net::TcpStream,
1837 str,
1838 sync::{Arc, Barrier},
1839 thread,
1840 time::Duration,
1841 };
1842
1843 use sozu_command::proto::command::SocketAddress;
1844
1845 use super::{testing::start_http_worker, *};
1846 use crate::sozu_command::{
1847 channel::Channel,
1848 config::ListenerBuilder,
1849 proto::command::{
1850 LoadBalancingParams, PathRule, RulePosition, SoftStop, WorkerRequest,
1851 request::RequestType,
1852 },
1853 response::{Backend, HttpFrontend},
1854 };
1855
1856 #[test]
1870 fn round_trip() {
1871 setup_test_logger!();
1872 let front_port = crate::testing::provide_port();
1873 let backend_server = Arc::new(
1874 tiny_http::Server::http("127.0.0.1:0").expect("could not create tiny_http server"),
1875 );
1876 let backend_port = backend_server
1877 .server_addr()
1878 .to_ip()
1879 .expect("tiny_http server should bind to IP address")
1880 .port();
1881
1882 let barrier = Arc::new(Barrier::new(2));
1883
1884 let config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, front_port))
1885 .to_http(None)
1886 .expect("could not create listener config");
1887
1888 let (mut command, channel) =
1889 Channel::generate(1000, 10000).expect("should create a channel");
1890
1891 thread::scope(|s| {
1892 let backend_handle = backend_server.clone();
1893 let barrier_clone = barrier.to_owned();
1894 s.spawn(move || {
1895 setup_test_logger!();
1896 start_server(&backend_handle, barrier_clone);
1897 });
1898 barrier.wait();
1899
1900 s.spawn(move || {
1901 setup_test_logger!();
1902 start_http_worker(config, channel, 10, 16384)
1903 .expect("could not start the http server");
1904 });
1905
1906 let front = RequestHttpFrontend {
1907 cluster_id: Some("cluster_1".to_owned()),
1908 address: SocketAddress::new_v4(127, 0, 0, 1, front_port),
1909 hostname: "localhost".to_owned(),
1910 path: PathRule::prefix("/".to_owned()),
1911 ..Default::default()
1912 };
1913 command
1914 .write_message(&WorkerRequest {
1915 id: "ID_ABCD".to_owned(),
1916 content: RequestType::AddHttpFrontend(front).into(),
1917 })
1918 .expect("could not send AddHttpFrontend");
1919 let backend = Backend {
1920 cluster_id: "cluster_1".to_owned(),
1921 backend_id: "cluster_1-0".to_owned(),
1922 address: SocketAddress::new_v4(127, 0, 0, 1, backend_port).into(),
1923 load_balancing_parameters: Some(LoadBalancingParams::default()),
1924 sticky_id: None,
1925 backup: None,
1926 };
1927 command
1928 .write_message(&WorkerRequest {
1929 id: "ID_EFGH".to_owned(),
1930 content: RequestType::AddBackend(backend.to_add_backend()).into(),
1931 })
1932 .expect("could not send AddBackend");
1933
1934 println!("test received: {:?}", command.read_message());
1935 println!("test received: {:?}", command.read_message());
1936
1937 let mut client =
1938 TcpStream::connect(("127.0.0.1", front_port)).expect("could not connect to sozu");
1939
1940 client
1941 .set_read_timeout(Some(Duration::new(1, 0)))
1942 .expect("could not set read timeout");
1943 let request = format!(
1944 "GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\nConnection: Close\r\n\r\n"
1945 );
1946 let w = client.write(request.as_bytes());
1947 println!("http client write: {w:?}");
1948
1949 barrier.wait();
1950 let mut buffer = [0; 4096];
1951 let mut index = 0;
1952
1953 let expected_len = 191;
1956
1957 loop {
1958 assert!(index <= expected_len);
1959 if index == expected_len {
1960 break;
1961 }
1962
1963 let r = client.read(&mut buffer[index..]);
1964 println!("http client read: {r:?}");
1965 match r {
1966 Err(e) => panic!("client request should not fail. Error: {e:?}"),
1967 Ok(sz) => {
1968 index += sz;
1969 }
1970 }
1971 }
1972 println!(
1973 "Response: {}",
1974 str::from_utf8(&buffer[..index]).expect("could not make string from buffer")
1975 );
1976
1977 command
1979 .write_message(&WorkerRequest {
1980 id: "ID_STOP".to_owned(),
1981 content: RequestType::SoftStop(SoftStop {}).into(),
1982 })
1983 .expect("could not send SoftStop");
1984 backend_server.unblock();
1986 });
1987 }
1988
1989 #[test]
1990 fn keep_alive() {
1991 setup_test_logger!();
1992 let front_port = crate::testing::provide_port();
1993 let backend_server = Arc::new(
1994 tiny_http::Server::http("127.0.0.1:0").expect("could not create tiny_http server"),
1995 );
1996 let backend_port = backend_server
1997 .server_addr()
1998 .to_ip()
1999 .expect("tiny_http server should bind to IP address")
2000 .port();
2001
2002 let barrier = Arc::new(Barrier::new(2));
2003
2004 let config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, front_port))
2005 .to_http(None)
2006 .expect("could not create listener config");
2007
2008 let (mut command, channel) =
2009 Channel::generate(1000, 10000).expect("should create a channel");
2010
2011 thread::scope(|s| {
2012 let backend_handle = backend_server.clone();
2013 let barrier_clone = barrier.to_owned();
2014 s.spawn(move || {
2015 setup_test_logger!();
2016 start_server(&backend_handle, barrier_clone);
2017 });
2018 barrier.wait();
2019
2020 s.spawn(move || {
2021 setup_test_logger!();
2022 start_http_worker(config, channel, 10, 16384)
2023 .expect("could not start the http server");
2024 });
2025
2026 let front = RequestHttpFrontend {
2027 address: SocketAddress::new_v4(127, 0, 0, 1, front_port),
2028 hostname: "localhost".to_owned(),
2029 path: PathRule::prefix("/".to_owned()),
2030 cluster_id: Some("cluster_1".to_owned()),
2031 ..Default::default()
2032 };
2033 command
2034 .write_message(&WorkerRequest {
2035 id: "ID_ABCD".to_owned(),
2036 content: RequestType::AddHttpFrontend(front).into(),
2037 })
2038 .expect("could not send AddHttpFrontend");
2039 let backend = Backend {
2040 address: SocketAddress::new_v4(127, 0, 0, 1, backend_port).into(),
2041 backend_id: "cluster_1-0".to_owned(),
2042 backup: None,
2043 cluster_id: "cluster_1".to_owned(),
2044 load_balancing_parameters: Some(LoadBalancingParams::default()),
2045 sticky_id: None,
2046 };
2047 command
2048 .write_message(&WorkerRequest {
2049 id: "ID_EFGH".to_owned(),
2050 content: RequestType::AddBackend(backend.to_add_backend()).into(),
2051 })
2052 .expect("could not send AddBackend");
2053
2054 println!("test received: {:?}", command.read_message());
2055 println!("test received: {:?}", command.read_message());
2056
2057 let mut client =
2058 TcpStream::connect(("127.0.0.1", front_port)).expect("could not connect to sozu");
2059 client
2060 .set_read_timeout(Some(Duration::new(5, 0)))
2061 .expect("could not set read timeout");
2062
2063 let expected_len = 191;
2066
2067 let request = format!("GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\n\r\n");
2068 let w = client
2069 .write(request.as_bytes())
2070 .expect("could not write first request");
2071 println!("http client write: {w:?}");
2072 barrier.wait();
2073
2074 let mut buffer = [0; 4096];
2075 let mut index = 0;
2076
2077 loop {
2078 assert!(index <= expected_len);
2079 if index == expected_len {
2080 break;
2081 }
2082
2083 let r = client.read(&mut buffer[index..]);
2084 println!("http client read: {r:?}");
2085 match r {
2086 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2087 Ok(sz) => {
2088 index += sz;
2089 }
2090 }
2091 }
2092
2093 println!(
2094 "Response: {}",
2095 str::from_utf8(&buffer[..index]).expect("could not make string from buffer")
2096 );
2097
2098 println!("first request ended, will send second one");
2099 let request2 = format!("GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\n\r\n");
2100 let w2 = client.write(request2.as_bytes());
2101 println!("http client write: {w2:?}");
2102 barrier.wait();
2103
2104 let mut buffer2 = [0; 4096];
2105 let mut index = 0;
2106
2107 loop {
2108 assert!(index <= expected_len);
2109 if index == expected_len {
2110 break;
2111 }
2112
2113 let r2 = client.read(&mut buffer2[index..]);
2114 println!("http client read: {r2:?}");
2115 match r2 {
2116 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2117 Ok(sz) => {
2118 index += sz;
2119 }
2120 }
2121 }
2122 println!(
2123 "Response: {}",
2124 str::from_utf8(&buffer2[..index]).expect("could not make string from buffer")
2125 );
2126
2127 command
2129 .write_message(&WorkerRequest {
2130 id: "ID_STOP".to_owned(),
2131 content: RequestType::SoftStop(SoftStop {}).into(),
2132 })
2133 .expect("could not send SoftStop");
2134 backend_server.unblock();
2136 });
2137 }
2138
2139 use self::tiny_http::Response;
2140
2141 fn start_server(server: &tiny_http::Server, barrier: Arc<Barrier>) {
2142 let addr = server.server_addr();
2143 info!("starting web server on {:?}", addr);
2144 barrier.wait();
2145
2146 for request in server.incoming_requests() {
2147 info!(
2148 "backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
2149 request.method(),
2150 request.url(),
2151 request.headers()
2152 );
2153
2154 let response = Response::from_string("hello world");
2155 request
2156 .respond(response)
2157 .expect("could not respond to request");
2158 info!("backend web server sent response");
2159 barrier.wait();
2160 info!("server session stopped");
2161 }
2162
2163 println!("server on {addr:?} closed");
2164 }
2165
2166 #[test]
2167 fn frontend_from_request_test() {
2168 let cluster_id1 = "cluster_1".to_owned();
2169 let cluster_id2 = "cluster_2".to_owned();
2170 let cluster_id3 = "cluster_3".to_owned();
2171 let uri1 = "/".to_owned();
2172 let uri2 = "/yolo".to_owned();
2173 let uri3 = "/yolo/swag".to_owned();
2174
2175 let mut fronts = Router::new();
2176 fronts
2177 .add_http_front(&HttpFrontend {
2178 address: "0.0.0.0:80".parse().unwrap(),
2179 hostname: "lolcatho.st".to_owned(),
2180 method: None,
2181 path: PathRule::prefix(uri1),
2182 position: RulePosition::Tree,
2183 cluster_id: Some(cluster_id1),
2184 tags: None,
2185 redirect: None,
2186 redirect_scheme: None,
2187 redirect_template: None,
2188 rewrite_host: None,
2189 rewrite_path: None,
2190 rewrite_port: None,
2191 required_auth: None,
2192 headers: Vec::new(),
2193 hsts: None,
2194 })
2195 .expect("Could not add http frontend");
2196 fronts
2197 .add_http_front(&HttpFrontend {
2198 address: "0.0.0.0:80".parse().unwrap(),
2199 hostname: "lolcatho.st".to_owned(),
2200 method: None,
2201 path: PathRule::prefix(uri2),
2202 position: RulePosition::Tree,
2203 cluster_id: Some(cluster_id2),
2204 tags: None,
2205 redirect: None,
2206 redirect_scheme: None,
2207 redirect_template: None,
2208 rewrite_host: None,
2209 rewrite_path: None,
2210 rewrite_port: None,
2211 required_auth: None,
2212 headers: Vec::new(),
2213 hsts: None,
2214 })
2215 .expect("Could not add http frontend");
2216 fronts
2217 .add_http_front(&HttpFrontend {
2218 address: "0.0.0.0:80".parse().unwrap(),
2219 hostname: "lolcatho.st".to_owned(),
2220 method: None,
2221 path: PathRule::prefix(uri3),
2222 position: RulePosition::Tree,
2223 cluster_id: Some(cluster_id3),
2224 tags: None,
2225 redirect: None,
2226 redirect_scheme: None,
2227 redirect_template: None,
2228 rewrite_host: None,
2229 rewrite_path: None,
2230 rewrite_port: None,
2231 required_auth: None,
2232 headers: Vec::new(),
2233 hsts: None,
2234 })
2235 .expect("Could not add http frontend");
2236 fronts
2237 .add_http_front(&HttpFrontend {
2238 address: "0.0.0.0:80".parse().unwrap(),
2239 hostname: "other.domain".to_owned(),
2240 method: None,
2241 path: PathRule::prefix("/test".to_owned()),
2242 position: RulePosition::Tree,
2243 cluster_id: Some("cluster_1".to_owned()),
2244 tags: None,
2245 redirect: None,
2246 redirect_scheme: None,
2247 redirect_template: None,
2248 rewrite_host: None,
2249 rewrite_path: None,
2250 rewrite_port: None,
2251 required_auth: None,
2252 headers: Vec::new(),
2253 hsts: None,
2254 })
2255 .expect("Could not add http frontend");
2256
2257 let address = SocketAddress::new_v4(127, 0, 0, 1, 1030);
2258
2259 let default_config = ListenerBuilder::new_http(address)
2260 .to_http(None)
2261 .expect("Could not create default HTTP listener config");
2262
2263 let listener = HttpListener {
2264 listener: None,
2265 address: address.into(),
2266 fronts,
2267 answers: Rc::new(RefCell::new(HttpAnswers::new(&BTreeMap::new()).unwrap())),
2268 config: default_config,
2269 token: Token(0),
2270 active: true,
2271 tags: BTreeMap::new(),
2272 };
2273
2274 let frontend1 = listener.frontend_from_request("lolcatho.st", "/", &Method::Get);
2275 let frontend2 = listener.frontend_from_request("lolcatho.st", "/test", &Method::Get);
2276 let frontend3 = listener.frontend_from_request("lolcatho.st", "/yolo/test", &Method::Get);
2277 let frontend4 = listener.frontend_from_request("lolcatho.st", "/yolo/swag", &Method::Get);
2278 let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);
2279 assert_eq!(
2280 frontend1
2281 .expect("should find frontend")
2282 .cluster_id
2283 .as_deref(),
2284 Some("cluster_1")
2285 );
2286 assert_eq!(
2287 frontend2
2288 .expect("should find frontend")
2289 .cluster_id
2290 .as_deref(),
2291 Some("cluster_1")
2292 );
2293 assert_eq!(
2294 frontend3
2295 .expect("should find frontend")
2296 .cluster_id
2297 .as_deref(),
2298 Some("cluster_2")
2299 );
2300 assert_eq!(
2301 frontend4
2302 .expect("should find frontend")
2303 .cluster_id
2304 .as_deref(),
2305 Some("cluster_3")
2306 );
2307 assert!(frontend5.is_err());
2308 }
2309
2310 #[test]
2311 fn h2_stream_idle_timeout_inherits_back_timeout() {
2312 let address = SocketAddress::new_v4(127, 0, 0, 1, 1040);
2313 let build = |back_timeout: u32, explicit: Option<u32>| -> HttpListener {
2314 let mut cfg = ListenerBuilder::new_http(address)
2315 .to_http(None)
2316 .expect("default HTTP listener config");
2317 cfg.back_timeout = back_timeout;
2318 cfg.h2_stream_idle_timeout_seconds = explicit;
2319 HttpListener::new(cfg, Token(0)).expect("build listener")
2320 };
2321
2322 assert_eq!(
2324 build(180, None).get_h2_stream_idle_timeout(),
2325 Duration::from_secs(180)
2326 );
2327
2328 assert_eq!(
2331 build(5, None).get_h2_stream_idle_timeout(),
2332 Duration::from_secs(30)
2333 );
2334
2335 assert_eq!(
2338 build(180, Some(10)).get_h2_stream_idle_timeout(),
2339 Duration::from_secs(10)
2340 );
2341 assert_eq!(
2342 build(5, Some(600)).get_h2_stream_idle_timeout(),
2343 Duration::from_secs(600)
2344 );
2345
2346 assert_eq!(
2348 build(180, Some(0)).get_h2_stream_idle_timeout(),
2349 Duration::from_secs(1)
2350 );
2351 }
2352}