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 .values()
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.values() {
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 let answers = Self::build_answers(&config)?;
1242 Ok(HttpListener {
1243 active: false,
1244 address: config.address.into(),
1245 answers: Rc::new(RefCell::new(answers)),
1246 config,
1247 fronts: Router::new(),
1248 listener: None,
1249 tags: BTreeMap::new(),
1250 token,
1251 })
1252 }
1253
1254 fn build_answers(config: &HttpListenerConfig) -> Result<HttpAnswers, ListenerError> {
1261 let mut answers_map = config.answers.clone();
1262 if let Some(ref legacy) = config.http_answers {
1263 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1264 }
1265 HttpAnswers::new(&answers_map)
1266 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))
1267 }
1268
1269 pub fn validate_config(config: &HttpListenerConfig) -> Result<(), ListenerError> {
1276 Self::build_answers(config)?;
1277 Ok(())
1278 }
1279
1280 pub fn activate(
1281 &mut self,
1282 registry: &Registry,
1283 tcp_listener: Option<MioTcpListener>,
1284 ) -> Result<Token, ListenerError> {
1285 if self.active {
1286 return Ok(self.token);
1287 }
1288 let address: SocketAddr = self.config.address.into();
1289
1290 let mut listener = match tcp_listener {
1291 Some(tcp_listener) => tcp_listener,
1292 None => {
1293 server_bind(address).map_err(|server_bind_error| ListenerError::Activation {
1294 address,
1295 error: server_bind_error.to_string(),
1296 })?
1297 }
1298 };
1299
1300 registry
1301 .register(&mut listener, self.token, Interest::READABLE)
1302 .map_err(ListenerError::SocketRegistration)?;
1303
1304 self.listener = Some(listener);
1305 self.active = true;
1306 Ok(self.token)
1307 }
1308
1309 pub fn update_config(&mut self, patch: &UpdateHttpListenerConfig) -> Result<(), ListenerError> {
1315 validate_h2_flood_knobs_http(patch)?;
1320 if let Some(ref hdr) = patch.sozu_id_header {
1321 validate_sozu_id_header(hdr)?;
1322 }
1323
1324 if let Some(v) = patch.public_address {
1325 self.config.public_address = Some(v);
1326 }
1327 if let Some(v) = patch.expect_proxy {
1328 self.config.expect_proxy = v;
1329 }
1330 if let Some(ref v) = patch.sticky_name {
1331 self.config.sticky_name = v.to_owned();
1332 }
1333 if let Some(v) = patch.front_timeout {
1334 self.config.front_timeout = v;
1335 }
1336 if let Some(v) = patch.back_timeout {
1337 self.config.back_timeout = v;
1338 }
1339 if let Some(v) = patch.connect_timeout {
1340 self.config.connect_timeout = v;
1341 }
1342 if let Some(v) = patch.request_timeout {
1343 self.config.request_timeout = v;
1344 }
1345 if let Some(ref v) = patch.sozu_id_header {
1346 self.config.sozu_id_header = Some(v.to_owned());
1347 }
1348 if let Some(v) = patch.elide_x_real_ip {
1349 self.config.elide_x_real_ip = Some(v);
1350 }
1351 if let Some(v) = patch.send_x_real_ip {
1352 self.config.send_x_real_ip = Some(v);
1353 }
1354
1355 if let Some(v) = patch.h2_max_rst_stream_per_window {
1357 self.config.h2_max_rst_stream_per_window = Some(v);
1358 }
1359 if let Some(v) = patch.h2_max_ping_per_window {
1360 self.config.h2_max_ping_per_window = Some(v);
1361 }
1362 if let Some(v) = patch.h2_max_settings_per_window {
1363 self.config.h2_max_settings_per_window = Some(v);
1364 }
1365 if let Some(v) = patch.h2_max_empty_data_per_window {
1366 self.config.h2_max_empty_data_per_window = Some(v);
1367 }
1368 if let Some(v) = patch.h2_max_continuation_frames {
1369 self.config.h2_max_continuation_frames = Some(v);
1370 }
1371 if let Some(v) = patch.h2_max_glitch_count {
1372 self.config.h2_max_glitch_count = Some(v);
1373 }
1374 if let Some(v) = patch.h2_initial_connection_window {
1375 self.config.h2_initial_connection_window = Some(v);
1376 }
1377 if let Some(v) = patch.h2_max_concurrent_streams {
1378 self.config.h2_max_concurrent_streams = Some(v);
1379 }
1380 if let Some(v) = patch.h2_stream_shrink_ratio {
1381 self.config.h2_stream_shrink_ratio = Some(v);
1382 }
1383 if let Some(v) = patch.h2_max_rst_stream_lifetime {
1384 self.config.h2_max_rst_stream_lifetime = Some(v);
1385 }
1386 if let Some(v) = patch.h2_max_rst_stream_abusive_lifetime {
1387 self.config.h2_max_rst_stream_abusive_lifetime = Some(v);
1388 }
1389 if let Some(v) = patch.h2_max_rst_stream_emitted_lifetime {
1390 self.config.h2_max_rst_stream_emitted_lifetime = Some(v);
1391 }
1392 if let Some(v) = patch.h2_max_header_list_size {
1393 self.config.h2_max_header_list_size = Some(v);
1394 }
1395 if let Some(v) = patch.h2_max_header_table_size {
1396 self.config.h2_max_header_table_size = Some(v);
1397 }
1398 if let Some(v) = patch.h2_max_header_fields {
1399 self.config.h2_max_header_fields = Some(v);
1400 }
1401 if let Some(v) = patch.h2_stream_idle_timeout_seconds {
1402 self.config.h2_stream_idle_timeout_seconds = Some(v);
1403 }
1404 if let Some(v) = patch.h2_graceful_shutdown_deadline_seconds {
1405 self.config.h2_graceful_shutdown_deadline_seconds = Some(v);
1406 }
1407 if let Some(v) = patch.h2_max_window_update_stream0_per_window {
1408 self.config.h2_max_window_update_stream0_per_window = Some(v);
1409 }
1410
1411 let answers_changed = patch.http_answers.is_some() || !patch.answers.is_empty();
1416 if answers_changed {
1417 if let Some(ref new_answers) = patch.http_answers {
1418 crate::sozu_command::state::merge_custom_http_answers(
1419 &mut self.config.http_answers,
1420 new_answers,
1421 );
1422 }
1423 for (code, body) in &patch.answers {
1424 if !body.is_empty() {
1425 self.config.answers.insert(code.clone(), body.clone());
1426 }
1427 }
1428
1429 let mut answers_map = self.config.answers.clone();
1430 if let Some(ref legacy) = self.config.http_answers {
1431 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1432 }
1433 let mut new_answers = HttpAnswers::new(&answers_map)
1436 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?;
1437 let preserved = std::mem::take(&mut self.answers.borrow_mut().cluster_answers);
1438 new_answers.cluster_answers = preserved;
1439 *self.answers.borrow_mut() = new_answers;
1440 }
1441
1442 Ok(())
1443 }
1444
1445 pub fn add_http_front(&mut self, http_front: HttpFrontend) -> Result<(), ListenerError> {
1446 self.fronts
1447 .add_http_front(&http_front)
1448 .map_err(ListenerError::AddFrontend)
1449 }
1450
1451 pub fn remove_http_front(&mut self, http_front: HttpFrontend) -> Result<(), ListenerError> {
1452 debug!(
1453 "{} removing http_front {:?}",
1454 log_module_context!(),
1455 http_front
1456 );
1457 self.fronts
1458 .remove_http_front(&http_front)
1459 .map_err(ListenerError::RemoveFrontend)
1460 }
1461
1462 fn accept(&mut self) -> Result<TcpStream, AcceptError> {
1463 if let Some(ref sock) = self.listener {
1464 sock.accept()
1465 .map_err(|e| match e.kind() {
1466 ErrorKind::WouldBlock => AcceptError::WouldBlock,
1467 _ => {
1468 error!("{} accept() IO error: {:?}", log_module_context!(), e);
1469 AcceptError::IoError
1470 }
1471 })
1472 .map(|(sock, _)| sock)
1473 } else {
1474 error!(
1475 "{} cannot accept connections, no listening socket available",
1476 log_module_context!()
1477 );
1478 Err(AcceptError::IoError)
1479 }
1480 }
1481}
1482
1483impl ProxyConfiguration for HttpProxy {
1484 fn notify(&mut self, request: WorkerRequest) -> WorkerResponse {
1485 let request_id = request.id.clone();
1486
1487 let result = match request.content.request_type {
1488 Some(RequestType::AddCluster(cluster)) => {
1489 debug!(
1490 "{} {} add cluster {:?}",
1491 log_module_context!(),
1492 request.id,
1493 cluster
1494 );
1495 self.add_cluster(cluster)
1496 }
1497 Some(RequestType::RemoveCluster(cluster_id)) => {
1498 debug!(
1499 "{} {} remove cluster {:?}",
1500 log_module_context!(),
1501 request_id,
1502 cluster_id
1503 );
1504 self.remove_cluster(&cluster_id)
1505 }
1506 Some(RequestType::AddHttpFrontend(front)) => {
1507 debug!(
1508 "{} {} add front {:?}",
1509 log_module_context!(),
1510 request_id,
1511 front
1512 );
1513 self.add_http_frontend(front)
1514 }
1515 Some(RequestType::RemoveHttpFrontend(front)) => {
1516 debug!(
1517 "{} {} remove front {:?}",
1518 log_module_context!(),
1519 request_id,
1520 front
1521 );
1522 self.remove_http_frontend(front)
1523 }
1524 Some(RequestType::RemoveListener(remove)) => {
1525 debug!(
1526 "{} removing HTTP listener at address {:?}",
1527 log_module_context!(),
1528 remove.address
1529 );
1530 self.remove_listener(remove)
1531 }
1532 Some(RequestType::SoftStop(_)) => {
1533 debug!(
1534 "{} {} processing soft shutdown",
1535 log_module_context!(),
1536 request_id
1537 );
1538 match self.soft_stop() {
1539 Ok(()) => {
1540 info!(
1541 "{} {} soft stop successful",
1542 log_module_context!(),
1543 request_id
1544 );
1545 return WorkerResponse::processing(request.id);
1546 }
1547 Err(e) => Err(e),
1548 }
1549 }
1550 Some(RequestType::HardStop(_)) => {
1551 debug!(
1552 "{} {} processing hard shutdown",
1553 log_module_context!(),
1554 request_id
1555 );
1556 match self.hard_stop() {
1557 Ok(()) => {
1558 info!(
1559 "{} {} hard stop successful",
1560 log_module_context!(),
1561 request_id
1562 );
1563 return WorkerResponse::processing(request.id);
1564 }
1565 Err(e) => Err(e),
1566 }
1567 }
1568 Some(RequestType::Status(_)) => {
1569 debug!("{} {} status", log_module_context!(), request_id);
1570 Ok(())
1571 }
1572 other_command => {
1573 debug!(
1574 "{} {} unsupported message for HTTP proxy, ignoring: {:?}",
1575 log_module_context!(),
1576 request.id,
1577 other_command
1578 );
1579 Err(ProxyError::UnsupportedMessage)
1580 }
1581 };
1582
1583 match result {
1584 Ok(()) => {
1585 debug!("{} {} successful", log_module_context!(), request_id);
1586 WorkerResponse::ok(request_id)
1587 }
1588 Err(proxy_error) => {
1589 debug!(
1590 "{} {} unsuccessful: {}",
1591 log_module_context!(),
1592 request_id,
1593 proxy_error
1594 );
1595 WorkerResponse::error(request_id, proxy_error)
1596 }
1597 }
1598 }
1599
1600 fn accept(&mut self, token: ListenToken) -> Result<TcpStream, AcceptError> {
1601 if let Some(listener) = self.listeners.get(&Token(token.0)) {
1602 listener.borrow_mut().accept()
1603 } else {
1604 Err(AcceptError::IoError)
1605 }
1606 }
1607
1608 fn create_session(
1609 &mut self,
1610 mut frontend_sock: TcpStream,
1611 listener_token: ListenToken,
1612 wait_time: Duration,
1613 proxy: Rc<RefCell<Self>>,
1614 ) -> Result<(), AcceptError> {
1615 let listener = self
1616 .listeners
1617 .get(&Token(listener_token.0))
1618 .cloned()
1619 .ok_or(AcceptError::IoError)?;
1620
1621 if let Err(e) = frontend_sock.set_nodelay(true) {
1622 error!(
1623 "{} error setting nodelay on front socket({:?}): {:?}",
1624 log_module_context!(),
1625 frontend_sock,
1626 e
1627 );
1628 }
1629 let mut session_manager = self.sessions.borrow_mut();
1630 let slab_len_before = session_manager.slab.len();
1631 let session_entry = session_manager.slab.vacant_entry();
1632 let session_token = Token(session_entry.key());
1633 debug_assert_eq!(
1638 session_token.0,
1639 session_entry.key(),
1640 "session token must equal the slab vacant-entry key"
1641 );
1642 let owned = listener.borrow();
1643
1644 if let Err(register_error) = self.registry.register(
1645 &mut frontend_sock,
1646 session_token,
1647 Interest::READABLE | Interest::WRITABLE,
1648 ) {
1649 error!(
1650 "{} error registering listen socket({:?}): {:?}",
1651 log_module_context!(),
1652 frontend_sock,
1653 register_error
1654 );
1655 return Err(AcceptError::RegisterError);
1656 }
1657
1658 let public_address: SocketAddr = match owned.config.public_address {
1659 Some(pub_addr) => pub_addr.into(),
1660 None => owned.config.address.into(),
1661 };
1662
1663 let session = HttpSession::new(
1664 Duration::from_secs(owned.config.back_timeout as u64),
1665 Duration::from_secs(owned.config.connect_timeout as u64),
1666 Duration::from_secs(owned.config.front_timeout as u64),
1667 Duration::from_secs(owned.config.request_timeout as u64),
1668 owned.config.expect_proxy,
1669 listener.clone(),
1670 Rc::downgrade(&self.pool),
1671 proxy,
1672 public_address,
1673 frontend_sock,
1674 session_token,
1675 wait_time,
1676 )?;
1677
1678 debug_assert_eq!(
1682 session.frontend_token, session_token,
1683 "session must own the frontend token it was created with"
1684 );
1685
1686 let session = Rc::new(RefCell::new(session));
1687 session_entry.insert(session);
1688 debug_assert_eq!(
1692 session_manager.slab.len(),
1693 slab_len_before + 1,
1694 "creating a session must occupy exactly one new slab slot"
1695 );
1696
1697 Ok(())
1698 }
1699}
1700
1701impl L7Proxy for HttpProxy {
1702 fn kind(&self) -> ListenerType {
1703 ListenerType::Http
1704 }
1705
1706 fn register_socket(
1707 &self,
1708 source: &mut TcpStream,
1709 token: Token,
1710 interest: Interest,
1711 ) -> Result<(), std::io::Error> {
1712 self.registry.register(source, token, interest)
1713 }
1714
1715 fn deregister_socket(&self, tcp_stream: &mut TcpStream) -> Result<(), std::io::Error> {
1716 self.registry.deregister(tcp_stream)
1717 }
1718
1719 fn add_session(&self, session: Rc<RefCell<dyn ProxySession>>) -> Token {
1720 let mut session_manager = self.sessions.borrow_mut();
1721 let len_before = session_manager.slab.len();
1722 let entry = session_manager.slab.vacant_entry();
1723 let token = Token(entry.key());
1724 let _entry = entry.insert(session);
1725 debug_assert_eq!(
1728 session_manager.slab.len(),
1729 len_before + 1,
1730 "add_session must occupy exactly one new slab slot"
1731 );
1732 debug_assert!(
1733 session_manager.slab.contains(token.0),
1734 "the returned token must index the freshly inserted session"
1735 );
1736 token
1737 }
1738
1739 fn remove_session(&self, token: Token) -> bool {
1740 let mut sessions = self.sessions.borrow_mut();
1741 let was_present = sessions.slab.contains(token.0);
1742 let len_before = sessions.slab.len();
1743 sessions.untrack_all_cluster_ip(token);
1749 let removed = sessions.slab.try_remove(token.0).is_some();
1750 debug_assert_eq!(
1754 removed, was_present,
1755 "try_remove reports presence iff the slot was occupied"
1756 );
1757 debug_assert_eq!(
1758 sessions.slab.len(),
1759 len_before - removed as usize,
1760 "slab len drops by exactly one iff a session was removed"
1761 );
1762 debug_assert!(
1763 !sessions.slab.contains(token.0),
1764 "the slot must be free after remove_session"
1765 );
1766 removed
1767 }
1768
1769 fn backends(&self) -> Rc<RefCell<BackendMap>> {
1770 self.backends.clone()
1771 }
1772
1773 fn clusters(&self) -> &HashMap<ClusterId, Cluster> {
1774 &self.clusters
1775 }
1776
1777 fn sessions(&self) -> Rc<RefCell<SessionManager>> {
1778 self.sessions.clone()
1779 }
1780}
1781
1782pub mod testing {
1783 use crate::testing::*;
1784
1785 pub fn start_http_worker(
1787 config: HttpListenerConfig,
1788 channel: ProxyChannel,
1789 max_buffers: usize,
1790 buffer_size: usize,
1791 ) -> anyhow::Result<()> {
1792 let address = config.address.into();
1793
1794 let ServerParts {
1795 event_loop,
1796 registry,
1797 sessions,
1798 pool,
1799 backends,
1800 client_scm_socket: _,
1801 server_scm_socket,
1802 server_config,
1803 } = prebuild_server(max_buffers, buffer_size, true)?;
1804
1805 let token = {
1806 let mut sessions = sessions.borrow_mut();
1807 let entry = sessions.slab.vacant_entry();
1808 let key = entry.key();
1809 let _ = entry.insert(Rc::new(RefCell::new(ListenSession {
1810 protocol: Protocol::HTTPListen,
1811 })));
1812 Token(key)
1813 };
1814
1815 let mut proxy = HttpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone());
1816 proxy
1817 .add_listener(config, token)
1818 .with_context(|| "Failed at creating adding the listener")?;
1819 proxy
1820 .activate_listener(&address, None)
1821 .with_context(|| "Failed at creating activating the listener")?;
1822
1823 let mut server = Server::new(
1824 event_loop,
1825 channel,
1826 server_scm_socket,
1827 sessions,
1828 pool,
1829 backends,
1830 Some(proxy),
1831 None,
1832 None,
1833 server_config,
1834 None,
1835 false,
1836 )
1837 .with_context(|| "Failed at creating server")?;
1838
1839 debug!("{} starting event loop", log_module_context!());
1840 server.run();
1841 debug!("{} ending event loop", log_module_context!());
1842 Ok(())
1843 }
1844}
1845
1846#[cfg(test)]
1847mod tests {
1848 extern crate tiny_http;
1849
1850 use std::{
1851 io::{Read, Write},
1852 net::TcpStream,
1853 str,
1854 sync::{Arc, Barrier},
1855 thread,
1856 time::Duration,
1857 };
1858
1859 use sozu_command::proto::command::SocketAddress;
1860
1861 use super::{testing::start_http_worker, *};
1862 use crate::sozu_command::{
1863 channel::Channel,
1864 config::ListenerBuilder,
1865 proto::command::{
1866 LoadBalancingParams, PathRule, RulePosition, SoftStop, WorkerRequest,
1867 request::RequestType,
1868 },
1869 response::{Backend, HttpFrontend},
1870 };
1871
1872 #[test]
1886 fn round_trip() {
1887 setup_test_logger!();
1888 let front_port = crate::testing::provide_port();
1889 let backend_server = Arc::new(
1890 tiny_http::Server::http("127.0.0.1:0").expect("could not create tiny_http server"),
1891 );
1892 let backend_port = backend_server
1893 .server_addr()
1894 .to_ip()
1895 .expect("tiny_http server should bind to IP address")
1896 .port();
1897
1898 let barrier = Arc::new(Barrier::new(2));
1899
1900 let config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, front_port))
1901 .to_http(None)
1902 .expect("could not create listener config");
1903
1904 let (mut command, channel) =
1905 Channel::generate(1000, 10000).expect("should create a channel");
1906
1907 thread::scope(|s| {
1908 let backend_handle = backend_server.clone();
1909 let barrier_clone = barrier.to_owned();
1910 s.spawn(move || {
1911 setup_test_logger!();
1912 start_server(&backend_handle, barrier_clone);
1913 });
1914 barrier.wait();
1915
1916 s.spawn(move || {
1917 setup_test_logger!();
1918 start_http_worker(config, channel, 10, 16384)
1919 .expect("could not start the http server");
1920 });
1921
1922 let front = RequestHttpFrontend {
1923 cluster_id: Some("cluster_1".to_owned()),
1924 address: SocketAddress::new_v4(127, 0, 0, 1, front_port),
1925 hostname: "localhost".to_owned(),
1926 path: PathRule::prefix("/".to_owned()),
1927 ..Default::default()
1928 };
1929 command
1930 .write_message(&WorkerRequest {
1931 id: "ID_ABCD".to_owned(),
1932 content: RequestType::AddHttpFrontend(front).into(),
1933 })
1934 .expect("could not send AddHttpFrontend");
1935 let backend = Backend {
1936 cluster_id: "cluster_1".to_owned(),
1937 backend_id: "cluster_1-0".to_owned(),
1938 address: SocketAddress::new_v4(127, 0, 0, 1, backend_port).into(),
1939 load_balancing_parameters: Some(LoadBalancingParams::default()),
1940 sticky_id: None,
1941 backup: None,
1942 };
1943 command
1944 .write_message(&WorkerRequest {
1945 id: "ID_EFGH".to_owned(),
1946 content: RequestType::AddBackend(backend.to_add_backend()).into(),
1947 })
1948 .expect("could not send AddBackend");
1949
1950 println!("test received: {:?}", command.read_message());
1951 println!("test received: {:?}", command.read_message());
1952
1953 let mut client =
1954 TcpStream::connect(("127.0.0.1", front_port)).expect("could not connect to sozu");
1955
1956 client
1957 .set_read_timeout(Some(Duration::new(1, 0)))
1958 .expect("could not set read timeout");
1959 let request = format!(
1960 "GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\nConnection: Close\r\n\r\n"
1961 );
1962 let w = client.write(request.as_bytes());
1963 println!("http client write: {w:?}");
1964
1965 barrier.wait();
1966 let mut buffer = [0; 4096];
1967 let mut index = 0;
1968
1969 let expected_len = 191;
1972
1973 loop {
1974 assert!(index <= expected_len);
1975 if index == expected_len {
1976 break;
1977 }
1978
1979 let r = client.read(&mut buffer[index..]);
1980 println!("http client read: {r:?}");
1981 match r {
1982 Err(e) => panic!("client request should not fail. Error: {e:?}"),
1983 Ok(sz) => {
1984 index += sz;
1985 }
1986 }
1987 }
1988 println!(
1989 "Response: {}",
1990 str::from_utf8(&buffer[..index]).expect("could not make string from buffer")
1991 );
1992
1993 command
1995 .write_message(&WorkerRequest {
1996 id: "ID_STOP".to_owned(),
1997 content: RequestType::SoftStop(SoftStop {}).into(),
1998 })
1999 .expect("could not send SoftStop");
2000 backend_server.unblock();
2002 });
2003 }
2004
2005 #[test]
2006 fn keep_alive() {
2007 setup_test_logger!();
2008 let front_port = crate::testing::provide_port();
2009 let backend_server = Arc::new(
2010 tiny_http::Server::http("127.0.0.1:0").expect("could not create tiny_http server"),
2011 );
2012 let backend_port = backend_server
2013 .server_addr()
2014 .to_ip()
2015 .expect("tiny_http server should bind to IP address")
2016 .port();
2017
2018 let barrier = Arc::new(Barrier::new(2));
2019
2020 let config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, front_port))
2021 .to_http(None)
2022 .expect("could not create listener config");
2023
2024 let (mut command, channel) =
2025 Channel::generate(1000, 10000).expect("should create a channel");
2026
2027 thread::scope(|s| {
2028 let backend_handle = backend_server.clone();
2029 let barrier_clone = barrier.to_owned();
2030 s.spawn(move || {
2031 setup_test_logger!();
2032 start_server(&backend_handle, barrier_clone);
2033 });
2034 barrier.wait();
2035
2036 s.spawn(move || {
2037 setup_test_logger!();
2038 start_http_worker(config, channel, 10, 16384)
2039 .expect("could not start the http server");
2040 });
2041
2042 let front = RequestHttpFrontend {
2043 address: SocketAddress::new_v4(127, 0, 0, 1, front_port),
2044 hostname: "localhost".to_owned(),
2045 path: PathRule::prefix("/".to_owned()),
2046 cluster_id: Some("cluster_1".to_owned()),
2047 ..Default::default()
2048 };
2049 command
2050 .write_message(&WorkerRequest {
2051 id: "ID_ABCD".to_owned(),
2052 content: RequestType::AddHttpFrontend(front).into(),
2053 })
2054 .expect("could not send AddHttpFrontend");
2055 let backend = Backend {
2056 address: SocketAddress::new_v4(127, 0, 0, 1, backend_port).into(),
2057 backend_id: "cluster_1-0".to_owned(),
2058 backup: None,
2059 cluster_id: "cluster_1".to_owned(),
2060 load_balancing_parameters: Some(LoadBalancingParams::default()),
2061 sticky_id: None,
2062 };
2063 command
2064 .write_message(&WorkerRequest {
2065 id: "ID_EFGH".to_owned(),
2066 content: RequestType::AddBackend(backend.to_add_backend()).into(),
2067 })
2068 .expect("could not send AddBackend");
2069
2070 println!("test received: {:?}", command.read_message());
2071 println!("test received: {:?}", command.read_message());
2072
2073 let mut client =
2074 TcpStream::connect(("127.0.0.1", front_port)).expect("could not connect to sozu");
2075 client
2076 .set_read_timeout(Some(Duration::new(5, 0)))
2077 .expect("could not set read timeout");
2078
2079 let expected_len = 191;
2082
2083 let request = format!("GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\n\r\n");
2084 let w = client
2085 .write(request.as_bytes())
2086 .expect("could not write first request");
2087 println!("http client write: {w:?}");
2088 barrier.wait();
2089
2090 let mut buffer = [0; 4096];
2091 let mut index = 0;
2092
2093 loop {
2094 assert!(index <= expected_len);
2095 if index == expected_len {
2096 break;
2097 }
2098
2099 let r = client.read(&mut buffer[index..]);
2100 println!("http client read: {r:?}");
2101 match r {
2102 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2103 Ok(sz) => {
2104 index += sz;
2105 }
2106 }
2107 }
2108
2109 println!(
2110 "Response: {}",
2111 str::from_utf8(&buffer[..index]).expect("could not make string from buffer")
2112 );
2113
2114 println!("first request ended, will send second one");
2115 let request2 = format!("GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\n\r\n");
2116 let w2 = client.write(request2.as_bytes());
2117 println!("http client write: {w2:?}");
2118 barrier.wait();
2119
2120 let mut buffer2 = [0; 4096];
2121 let mut index = 0;
2122
2123 loop {
2124 assert!(index <= expected_len);
2125 if index == expected_len {
2126 break;
2127 }
2128
2129 let r2 = client.read(&mut buffer2[index..]);
2130 println!("http client read: {r2:?}");
2131 match r2 {
2132 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2133 Ok(sz) => {
2134 index += sz;
2135 }
2136 }
2137 }
2138 println!(
2139 "Response: {}",
2140 str::from_utf8(&buffer2[..index]).expect("could not make string from buffer")
2141 );
2142
2143 command
2145 .write_message(&WorkerRequest {
2146 id: "ID_STOP".to_owned(),
2147 content: RequestType::SoftStop(SoftStop {}).into(),
2148 })
2149 .expect("could not send SoftStop");
2150 backend_server.unblock();
2152 });
2153 }
2154
2155 use self::tiny_http::Response;
2156
2157 fn start_server(server: &tiny_http::Server, barrier: Arc<Barrier>) {
2158 let addr = server.server_addr();
2159 info!("starting web server on {:?}", addr);
2160 barrier.wait();
2161
2162 for request in server.incoming_requests() {
2163 info!(
2164 "backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
2165 request.method(),
2166 request.url(),
2167 request.headers()
2168 );
2169
2170 let response = Response::from_string("hello world");
2171 request
2172 .respond(response)
2173 .expect("could not respond to request");
2174 info!("backend web server sent response");
2175 barrier.wait();
2176 info!("server session stopped");
2177 }
2178
2179 println!("server on {addr:?} closed");
2180 }
2181
2182 #[test]
2183 fn frontend_from_request_test() {
2184 let cluster_id1 = "cluster_1".to_owned();
2185 let cluster_id2 = "cluster_2".to_owned();
2186 let cluster_id3 = "cluster_3".to_owned();
2187 let uri1 = "/".to_owned();
2188 let uri2 = "/yolo".to_owned();
2189 let uri3 = "/yolo/swag".to_owned();
2190
2191 let mut fronts = Router::new();
2192 fronts
2193 .add_http_front(&HttpFrontend {
2194 address: "0.0.0.0:80".parse().unwrap(),
2195 hostname: "lolcatho.st".to_owned(),
2196 method: None,
2197 path: PathRule::prefix(uri1),
2198 position: RulePosition::Tree,
2199 cluster_id: Some(cluster_id1),
2200 tags: None,
2201 redirect: None,
2202 redirect_scheme: None,
2203 redirect_template: None,
2204 rewrite_host: None,
2205 rewrite_path: None,
2206 rewrite_port: None,
2207 required_auth: None,
2208 headers: Vec::new(),
2209 hsts: None,
2210 })
2211 .expect("Could not add http frontend");
2212 fronts
2213 .add_http_front(&HttpFrontend {
2214 address: "0.0.0.0:80".parse().unwrap(),
2215 hostname: "lolcatho.st".to_owned(),
2216 method: None,
2217 path: PathRule::prefix(uri2),
2218 position: RulePosition::Tree,
2219 cluster_id: Some(cluster_id2),
2220 tags: None,
2221 redirect: None,
2222 redirect_scheme: None,
2223 redirect_template: None,
2224 rewrite_host: None,
2225 rewrite_path: None,
2226 rewrite_port: None,
2227 required_auth: None,
2228 headers: Vec::new(),
2229 hsts: None,
2230 })
2231 .expect("Could not add http frontend");
2232 fronts
2233 .add_http_front(&HttpFrontend {
2234 address: "0.0.0.0:80".parse().unwrap(),
2235 hostname: "lolcatho.st".to_owned(),
2236 method: None,
2237 path: PathRule::prefix(uri3),
2238 position: RulePosition::Tree,
2239 cluster_id: Some(cluster_id3),
2240 tags: None,
2241 redirect: None,
2242 redirect_scheme: None,
2243 redirect_template: None,
2244 rewrite_host: None,
2245 rewrite_path: None,
2246 rewrite_port: None,
2247 required_auth: None,
2248 headers: Vec::new(),
2249 hsts: None,
2250 })
2251 .expect("Could not add http frontend");
2252 fronts
2253 .add_http_front(&HttpFrontend {
2254 address: "0.0.0.0:80".parse().unwrap(),
2255 hostname: "other.domain".to_owned(),
2256 method: None,
2257 path: PathRule::prefix("/test".to_owned()),
2258 position: RulePosition::Tree,
2259 cluster_id: Some("cluster_1".to_owned()),
2260 tags: None,
2261 redirect: None,
2262 redirect_scheme: None,
2263 redirect_template: None,
2264 rewrite_host: None,
2265 rewrite_path: None,
2266 rewrite_port: None,
2267 required_auth: None,
2268 headers: Vec::new(),
2269 hsts: None,
2270 })
2271 .expect("Could not add http frontend");
2272
2273 let address = SocketAddress::new_v4(127, 0, 0, 1, 1030);
2274
2275 let default_config = ListenerBuilder::new_http(address)
2276 .to_http(None)
2277 .expect("Could not create default HTTP listener config");
2278
2279 let listener = HttpListener {
2280 listener: None,
2281 address: address.into(),
2282 fronts,
2283 answers: Rc::new(RefCell::new(HttpAnswers::new(&BTreeMap::new()).unwrap())),
2284 config: default_config,
2285 token: Token(0),
2286 active: true,
2287 tags: BTreeMap::new(),
2288 };
2289
2290 let frontend1 = listener.frontend_from_request("lolcatho.st", "/", &Method::Get);
2291 let frontend2 = listener.frontend_from_request("lolcatho.st", "/test", &Method::Get);
2292 let frontend3 = listener.frontend_from_request("lolcatho.st", "/yolo/test", &Method::Get);
2293 let frontend4 = listener.frontend_from_request("lolcatho.st", "/yolo/swag", &Method::Get);
2294 let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);
2295 assert_eq!(
2296 frontend1
2297 .expect("should find frontend")
2298 .cluster_id
2299 .as_deref(),
2300 Some("cluster_1")
2301 );
2302 assert_eq!(
2303 frontend2
2304 .expect("should find frontend")
2305 .cluster_id
2306 .as_deref(),
2307 Some("cluster_1")
2308 );
2309 assert_eq!(
2310 frontend3
2311 .expect("should find frontend")
2312 .cluster_id
2313 .as_deref(),
2314 Some("cluster_2")
2315 );
2316 assert_eq!(
2317 frontend4
2318 .expect("should find frontend")
2319 .cluster_id
2320 .as_deref(),
2321 Some("cluster_3")
2322 );
2323 assert!(frontend5.is_err());
2324 }
2325
2326 #[test]
2327 fn h2_stream_idle_timeout_inherits_back_timeout() {
2328 let address = SocketAddress::new_v4(127, 0, 0, 1, 1040);
2329 let build = |back_timeout: u32, explicit: Option<u32>| -> HttpListener {
2330 let mut cfg = ListenerBuilder::new_http(address)
2331 .to_http(None)
2332 .expect("default HTTP listener config");
2333 cfg.back_timeout = back_timeout;
2334 cfg.h2_stream_idle_timeout_seconds = explicit;
2335 HttpListener::new(cfg, Token(0)).expect("build listener")
2336 };
2337
2338 assert_eq!(
2340 build(180, None).get_h2_stream_idle_timeout(),
2341 Duration::from_secs(180)
2342 );
2343
2344 assert_eq!(
2347 build(5, None).get_h2_stream_idle_timeout(),
2348 Duration::from_secs(30)
2349 );
2350
2351 assert_eq!(
2354 build(180, Some(10)).get_h2_stream_idle_timeout(),
2355 Duration::from_secs(10)
2356 );
2357 assert_eq!(
2358 build(5, Some(600)).get_h2_stream_idle_timeout(),
2359 Duration::from_secs(600)
2360 );
2361
2362 assert_eq!(
2364 build(180, Some(0)).get_h2_stream_idle_timeout(),
2365 Duration::from_secs(1)
2366 );
2367 }
2368}