1use std::{
2 cell::RefCell,
3 collections::{BTreeMap, HashMap, hash_map::Entry},
4 io::ErrorKind,
5 net::SocketAddr,
6 rc::{Rc, Weak},
7 str::from_utf8_unchecked,
8 time::{Duration, Instant},
9};
10
11use mio::{
12 Interest, Registry, Token,
13 net::{TcpListener as MioTcpListener, TcpStream},
14};
15use rusty_ulid::Ulid;
16use socket2::SockRef;
17use sozu_command::{
18 listener_key::ListenerKey,
19 logging::CachedTags,
20 proto::command::{
21 Cluster, ForwardedHeaders, HttpListenerConfig, ListenerType, RemoveListener,
22 RequestHttpFrontend, UpdateHttpListenerConfig, WorkerRequest, WorkerResponse,
23 request::RequestType,
24 },
25 ready::Ready,
26 response::HttpFrontend,
27 state::{
28 ClusterId, validate_forwarded_headers, validate_h2_flood_knobs_http,
29 validate_sozu_id_header,
30 },
31};
32
33use crate::metrics::names;
34use crate::{
35 AcceptError, FrontendFromRequestError, L7ListenerHandler, L7Proxy, ListenerError,
36 ListenerHandler, Protocol, ProxyConfiguration, ProxyError, ProxySession, SessionIsToBeClosed,
37 SessionMetrics, SessionResult, StateMachineBuilder, StateResult,
38 backends::BackendMap,
39 pool::Pool,
40 protocol::{
41 Pipe, SessionState,
42 http::{
43 answers::HttpAnswers,
44 parser::{Method, hostname_and_port},
45 },
46 mux::{self, Mux, MuxClear},
47 proxy_protocol::expect::ExpectProxyProtocol,
48 },
49 router::{RouteResult, Router},
50 server::{ListenToken, SessionManager},
51 socket::server_bind,
52 timer::TimeoutContainer,
53};
54
55#[derive(PartialEq, Eq)]
56pub enum SessionStatus {
57 Normal,
58 DefaultAnswer,
59}
60
61StateMachineBuilder! {
62 enum HttpStateMachine impl SessionState {
68 Expect(ExpectProxyProtocol<TcpStream>),
69 Mux(MuxClear),
70 WebSocket(Pipe<crate::socket::SessionTcpStream, HttpListener>),
71 }
72}
73
74macro_rules! log_module_context {
80 () => {{
81 let (open, reset, _, _, _) = sozu_command::logging::ansi_palette();
82 format!("{open}HTTP{reset}\t >>>", open = open, reset = reset)
83 }};
84}
85
86macro_rules! log_context {
92 ($self:expr) => {{
93 let (open, reset, grey, gray, white) = sozu_command::logging::ansi_palette();
94 format!(
95 "{open}HTTP{reset}\t{grey}Session{reset}({gray}frontend{reset}={white}{frontend}{reset})\t >>>",
96 open = open,
97 reset = reset,
98 grey = grey,
99 gray = gray,
100 white = white,
101 frontend = $self.frontend_token.0,
102 )
103 }};
104}
105
106pub struct HttpSession {
110 configured_backend_timeout: Duration,
111 configured_connect_timeout: Duration,
112 configured_frontend_timeout: Duration,
113 frontend_token: Token,
114 last_event: Instant,
115 listener: Rc<RefCell<HttpListener>>,
116 metrics: SessionMetrics,
117 pool: Weak<RefCell<Pool>>,
118 proxy: Rc<RefCell<HttpProxy>>,
119 state: HttpStateMachine,
120 has_been_closed: bool,
121}
122
123impl HttpSession {
124 #[allow(clippy::too_many_arguments)]
125 pub fn new(
126 configured_backend_timeout: Duration,
127 configured_connect_timeout: Duration,
128 configured_frontend_timeout: Duration,
129 configured_request_timeout: Duration,
130 expect_proxy: bool,
131 listener: Rc<RefCell<HttpListener>>,
132 pool: Weak<RefCell<Pool>>,
133 proxy: Rc<RefCell<HttpProxy>>,
134 backends: Rc<RefCell<BackendMap>>,
135 public_address: SocketAddr,
136 sock: TcpStream,
137 peer: SocketAddr,
138 token: Token,
139 wait_time: Duration,
140 ) -> Result<Self, AcceptError> {
141 let request_id = Ulid::generate();
142 let container_frontend_timeout = TimeoutContainer::new(configured_request_timeout, token);
143
144 let state = if expect_proxy {
145 trace!("{} starting in expect proxy state", log_module_context!());
146 gauge_add!(names::protocol::PROXY_EXPECT, 1);
147
148 HttpStateMachine::Expect(ExpectProxyProtocol::new(
149 container_frontend_timeout,
150 sock,
151 token,
152 request_id,
153 ))
154 } else {
155 gauge_add!(names::protocol::HTTP, 1);
156 let session_address = Some(peer);
160 let session_ulid = rusty_ulid::Ulid::generate();
161 let sock = crate::socket::SessionTcpStream::new(sock, session_ulid, session_address);
162
163 let frontend = mux::Connection::new_h1_server(
164 session_ulid,
165 sock,
166 container_frontend_timeout.duration(),
167 );
168 let router = mux::Router::new(configured_backend_timeout, configured_connect_timeout);
169 let mut context = mux::Context::new(
170 session_ulid,
171 pool.clone(),
172 listener.clone(),
173 session_address,
174 public_address,
175 );
176 context
177 .create_stream(request_id, 1 << 16)
178 .ok_or(AcceptError::BufferCapacityReached)?;
179 HttpStateMachine::Mux(Mux {
180 configured_frontend_timeout,
181 frontend_token: token,
182 frontend,
183 router,
184 context,
185 session_ulid,
186 timeouts: mux::MuxTimeouts::new(container_frontend_timeout),
190 backend_registry: mux::BackendRegistry::default(),
191 backends,
192 })
193 };
194
195 debug_assert_eq!(
202 state.marker() as u8,
203 if expect_proxy {
204 StateMarker::Expect as u8
205 } else {
206 StateMarker::Mux as u8
207 },
208 "constructed state must match the expect_proxy branch"
209 );
210 debug_assert!(
214 !state.failed(),
215 "a newly created session must not start in FailedUpgrade"
216 );
217
218 let metrics = SessionMetrics::new(Some(wait_time));
219 let session = HttpSession {
220 configured_backend_timeout,
221 configured_connect_timeout,
222 configured_frontend_timeout,
223 frontend_token: token,
224 has_been_closed: false,
225 last_event: Instant::now(),
226 listener,
227 metrics,
228 pool,
229 proxy,
230 state,
231 };
232 debug_assert_eq!(
233 session.frontend_token, token,
234 "frontend token must be the slab token used for registration"
235 );
236 #[cfg(debug_assertions)]
237 session.check_invariants();
238 Ok(session)
239 }
240
241 #[cfg(debug_assertions)]
254 fn check_invariants(&self) {
255 let marker = self.state.marker();
256 debug_assert!(
257 matches!(
258 marker,
259 StateMarker::Expect | StateMarker::Mux | StateMarker::WebSocket
260 ),
261 "session marker must be a legal H1 stage (Expect/Mux/WebSocket), got {marker:?}"
262 );
263 debug_assert!(
267 !self.state.failed() || self.has_been_closed,
268 "FailedUpgrade state must be reaped by close(), never left live"
269 );
270 }
271
272 pub fn upgrade(&mut self) -> SessionIsToBeClosed {
273 debug!("{} upgrade", log_context!(self));
274 let from_marker = self.state.marker();
280 let new_state = match self.state.take() {
281 HttpStateMachine::Mux(mux) => self.upgrade_mux(mux),
282 HttpStateMachine::Expect(expect) => self.upgrade_expect(expect),
283 HttpStateMachine::WebSocket(ws) => self.upgrade_websocket(ws),
284 HttpStateMachine::FailedUpgrade(_) => {
285 error!(
289 "{} upgrade called on FailedUpgrade state; closing session",
290 log_context!(self)
291 );
292 None
293 }
294 };
295
296 match new_state {
297 Some(state) => {
298 debug_assert!(
302 matches!(
303 (from_marker, state.marker()),
304 (StateMarker::Expect, StateMarker::Mux)
305 | (StateMarker::Mux, StateMarker::WebSocket)
306 | (StateMarker::WebSocket, StateMarker::WebSocket)
307 ),
308 "illegal protocol-upgrade transition {from_marker:?} -> {:?}",
309 state.marker()
310 );
311 debug_assert!(
312 !state.failed(),
313 "a successful upgrade must not install a FailedUpgrade state"
314 );
315 self.state = state;
316 #[cfg(debug_assertions)]
317 self.check_invariants();
318 false
319 }
320 None => {
322 debug_assert!(
326 self.state.failed(),
327 "a failed upgrade must leave the session in FailedUpgrade"
328 );
329 true
330 }
331 }
332 }
333
334 fn upgrade_expect(
335 &mut self,
336 expect: ExpectProxyProtocol<TcpStream>,
337 ) -> Option<HttpStateMachine> {
338 debug!("{} switching to HTTP", log_context!(self));
339 match expect
340 .addresses
341 .as_ref()
342 .map(|add| (add.destination(), add.source()))
343 {
344 Some((Some(public_address), Some(session_address))) => {
345 let session_ulid = rusty_ulid::Ulid::generate();
346 let frontend = mux::Connection::new_h1_server(
347 session_ulid,
348 crate::socket::SessionTcpStream::new(
349 expect.frontend,
350 session_ulid,
351 Some(session_address),
352 ),
353 expect.container_frontend_timeout.duration(),
354 );
355 let router = mux::Router::new(
356 self.configured_backend_timeout,
357 self.configured_connect_timeout,
358 );
359 let mut context = mux::Context::new(
360 session_ulid,
361 self.pool.clone(),
362 self.listener.clone(),
363 Some(session_address),
364 public_address,
365 );
366 if context.create_stream(expect.request_id, 1 << 16).is_none() {
367 error!(
368 "{} expect upgrade failed: could not create stream",
369 log_context!(self)
370 );
371 return None;
372 }
373 let mut mux = Mux {
374 configured_frontend_timeout: self.configured_frontend_timeout,
375 frontend_token: self.frontend_token,
376 frontend,
377 router,
378 context,
379 session_ulid,
380 timeouts: mux::MuxTimeouts::new(expect.container_frontend_timeout),
381 backend_registry: mux::BackendRegistry::default(),
382 backends: Rc::clone(&self.proxy.borrow().backends),
387 };
388 mux.frontend.readiness_mut().event = expect.frontend_readiness.event;
389
390 debug_assert_eq!(
394 mux.frontend_token, self.frontend_token,
395 "expect upgrade must preserve the frontend token"
396 );
397 debug_assert_eq!(
400 mux.context.streams.len(),
401 1,
402 "a freshly upgraded Mux owns exactly the request stream"
403 );
404
405 gauge_add!(names::protocol::PROXY_EXPECT, -1);
409 gauge_add!(names::protocol::HTTP, 1);
410 Some(HttpStateMachine::Mux(mux))
411 }
412 _ => {
413 debug!(
414 "{} expect upgrade failed: bad header {:?}",
415 log_context!(self),
416 expect.addresses
417 );
418 None
419 }
420 }
421 }
422
423 fn upgrade_mux(&mut self, mut mux: MuxClear) -> Option<HttpStateMachine> {
424 debug!("{} mux switching to ws", log_context!(self));
425 let Some(stream) = mux.context.streams.pop() else {
426 error!(
427 "{} upgrade_mux: no stream attached to the mux session, closing",
428 log_context!(self)
429 );
430 return None;
431 };
432 let mut container_frontend_timeout = mux.timeouts.frontend;
440 let (frontend_readiness, frontend_socket) = match mux.frontend {
441 mux::Connection::H1(mux::ConnectionH1 {
442 readiness, socket, ..
443 }) => (readiness, socket),
444 mux::Connection::H2(_) => {
445 error!(
446 "{} only h1<->h1 connections can upgrade to websocket",
447 log_context!(self)
448 );
449 return None;
450 }
451 };
452
453 let mux::StreamState::Linked(back_token) = stream.state else {
454 error!(
455 "{} upgrading stream should be linked to a backend",
456 log_context!(self)
457 );
458 return None;
459 };
460 debug_assert!(
466 mux.router.backends.contains_key(&back_token),
467 "a Linked stream's back token must index a connected backend"
468 );
469 let backends_before = mux.router.backends.len();
470 let Some(backend) = mux.router.backends.remove(&back_token) else {
471 error!(
472 "{} upgrade_mux: backend for token {:?} is missing (already disconnected?), closing",
473 log_context!(self),
474 back_token
475 );
476 return None;
477 };
478 let mut container_backend_timeout = mux
479 .timeouts
480 .backends
481 .remove(&back_token)
482 .unwrap_or_else(|| TimeoutContainer::new_empty(mux.router.configured_backend_timeout));
483 let (cluster_id, backend_id, backend_readiness, backend_socket) = match backend {
484 mux::Connection::H1(mux::ConnectionH1 {
485 position: mux::Position::Client(cluster_id, backend, mux::BackendStatus::Connected),
486 readiness,
487 socket,
488 ..
489 }) => (cluster_id, backend, readiness, socket),
490 mux::Connection::H1(_) => {
491 error!(
492 "{} the backend disconnected just after upgrade, abort",
493 log_context!(self)
494 );
495 return None;
496 }
497 mux::Connection::H2(_) => {
498 error!(
499 "{} only h1<->h1 connections can upgrade to websocket",
500 log_context!(self)
501 );
502 return None;
503 }
504 };
505
506 let Some(backend) = mux.backend_registry.handle(&backend_id).cloned() else {
511 error!(
512 "{} upgrade_mux: backend {:?} names a slot this session never minted, closing",
513 log_context!(self),
514 backend_id.backend_id
515 );
516 return None;
517 };
518 let metric_incarnation = backend_id.metric_incarnation();
519 let backend_id = backend_id.backend_id.to_string();
520
521 debug_assert!(
524 !mux.router.backends.contains_key(&back_token),
525 "the upgraded backend must be evicted from the router map"
526 );
527 debug_assert_eq!(
528 mux.router.backends.len(),
529 backends_before - 1,
530 "removing the backend must drop the backend count by exactly one"
531 );
532
533 let ws_context = stream.context.websocket_context();
534
535 container_frontend_timeout.reset();
536 container_backend_timeout.reset();
537
538 let backend_socket = backend_socket.stream;
543 let mut pipe = Pipe::new(
544 stream.back.storage.buffer,
545 Some(backend_id),
546 Some(backend_socket),
547 Some(backend),
548 Some(container_backend_timeout),
549 Some(container_frontend_timeout),
550 Some(cluster_id),
551 stream.front.storage.buffer,
552 self.frontend_token,
553 frontend_socket,
554 self.listener.clone(),
555 Protocol::HTTP,
556 stream.context.session_id,
557 stream.context.id,
558 stream.context.session_address,
559 ws_context,
560 );
561 pipe.set_cluster_metrics_incarnation(metric_incarnation);
562
563 pipe.restore_readiness_events(frontend_readiness.event, backend_readiness.event);
564 pipe.set_back_token(back_token);
567 debug_assert_eq!(
568 pipe.back_token(),
569 vec![back_token],
570 "websocket pipe must carry exactly the upgraded backend token"
571 );
572
573 gauge_add!(names::protocol::HTTP, -1);
580 gauge_add!(names::protocol::WS, 1);
581 gauge_add!(names::websocket::ACTIVE_REQUESTS, 1);
582 Some(HttpStateMachine::WebSocket(pipe))
583 }
584
585 fn upgrade_websocket(
586 &self,
587 ws: Pipe<crate::socket::SessionTcpStream, HttpListener>,
588 ) -> Option<HttpStateMachine> {
589 error!(
591 "{} upgrade called on WS, this should not happen",
592 log_context!(self)
593 );
594 Some(HttpStateMachine::WebSocket(ws))
595 }
596}
597
598impl ProxySession for HttpSession {
599 fn close(&mut self) {
600 if self.has_been_closed {
601 return;
602 }
603 debug_assert!(
605 !self.has_been_closed,
606 "close past the guard must run on a not-yet-closed session"
607 );
608
609 trace!("{} closing HTTP session", log_context!(self));
610 self.metrics.service_stop();
611
612 match self.state.marker() {
614 StateMarker::Expect => gauge_add!(names::protocol::PROXY_EXPECT, -1),
615 StateMarker::Mux => gauge_add!(names::protocol::HTTP, -1),
616 StateMarker::WebSocket => {
617 gauge_add!(names::protocol::WS, -1);
618 gauge_add!(names::websocket::ACTIVE_REQUESTS, -1);
619 }
620 }
621
622 if self.state.failed() {
623 match self.state.marker() {
624 StateMarker::Expect => incr!(names::http::UPGRADE_EXPECT_FAILED),
625 StateMarker::Mux => incr!(names::http::UPGRADE_MUX_FAILED),
626 StateMarker::WebSocket => incr!(names::http::UPGRADE_WS_FAILED),
627 }
628 self.state.close(self.proxy.clone(), &mut self.metrics);
632 self.proxy.borrow().remove_session(self.frontend_token);
633 self.has_been_closed = true;
634 debug_assert!(
635 self.has_been_closed,
636 "failed-upgrade close path must mark the session closed"
637 );
638 return;
639 }
640
641 self.state.cancel_timeouts();
642 self.state.close(self.proxy.clone(), &mut self.metrics);
644
645 let peer_closed =
648 matches!(&self.state, HttpStateMachine::Mux(mux) if mux.frontend_peer_closed());
649 let front_socket = self.state.front_socket();
650 if let Err(e) = mux::shutdown_write(front_socket, peer_closed) {
656 if e.kind() != ErrorKind::NotConnected {
658 error!(
659 "{} error shutting down front socket({:?}): {:?}",
660 log_context!(self),
661 front_socket,
662 e
663 )
664 }
665 }
666
667 let proxy = self.proxy.borrow();
676 proxy.remove_session(self.frontend_token);
677
678 self.has_been_closed = true;
679 debug_assert!(
680 self.has_been_closed,
681 "close must leave the session marked closed (idempotency latch)"
682 );
683 }
684
685 fn timeout(&mut self, token: Token) -> SessionIsToBeClosed {
686 let state_result = self.state.timeout(token, &mut self.metrics);
687 state_result == StateResult::CloseSession
688 }
689
690 fn needs_ready_pass(&self) -> bool {
691 matches!(&self.state, HttpStateMachine::Mux(mux) if mux.has_pending_backend_failure())
692 }
693
694 fn protocol(&self) -> Protocol {
695 Protocol::HTTP
696 }
697
698 fn update_readiness(&mut self, token: Token, events: Ready) {
699 trace!(
700 "{} token {:?} got event {}",
701 log_context!(self),
702 token,
703 super::ready_to_string(events)
704 );
705 self.last_event = Instant::now();
706 self.metrics.wait_start();
707 self.state.update_readiness(token, events);
708 }
709
710 fn ready(&mut self, session: Rc<RefCell<dyn ProxySession>>) -> SessionIsToBeClosed {
711 self.metrics.service_start();
712
713 let session_result =
714 self.state
715 .ready(session.clone(), self.proxy.clone(), &mut self.metrics);
716
717 let to_be_closed = match session_result {
718 SessionResult::Close => true,
719 SessionResult::Continue => false,
720 SessionResult::Upgrade => match self.upgrade() {
721 false => self.ready(session),
722 true => true,
723 },
724 };
725
726 self.metrics.service_stop();
727 #[cfg(debug_assertions)]
732 if !to_be_closed {
733 self.check_invariants();
734 }
735 to_be_closed
736 }
737
738 fn shutting_down(&mut self) -> SessionIsToBeClosed {
739 self.state.shutting_down()
740 }
741
742 fn last_event(&self) -> Instant {
743 self.last_event
744 }
745
746 fn print_session(&self) {
747 self.state.print_state("HTTP");
748 error!("{} Metrics: {:?}", log_context!(self), self.metrics);
749 }
750
751 fn frontend_token(&self) -> Token {
752 self.frontend_token
753 }
754}
755
756pub type Hostname = String;
757
758pub struct HttpListener {
780 active: bool,
781 address: SocketAddr,
782 answers: Rc<RefCell<HttpAnswers>>,
783 config: HttpListenerConfig,
784 fronts: Router,
785 listener: Option<MioTcpListener>,
786 parked_listener: Option<MioTcpListener>,
800 nodelay_backlog: bool,
814 tags: BTreeMap<String, CachedTags>,
815 token: Token,
816}
817
818impl ListenerHandler for HttpListener {
819 fn get_addr(&self) -> &SocketAddr {
820 &self.address
821 }
822
823 fn get_tags(&self, key: &str) -> Option<&CachedTags> {
824 self.tags.get(key)
825 }
826
827 fn set_tags(&mut self, key: String, tags: Option<BTreeMap<String, String>>) {
828 match tags {
829 Some(tags) => self.tags.insert(key, CachedTags::new(tags)),
830 None => self.tags.remove(&key),
831 };
832 }
833
834 fn protocol(&self) -> Protocol {
835 Protocol::HTTP
836 }
837
838 fn public_address(&self) -> SocketAddr {
839 self.config
840 .public_address
841 .map(|addr| addr.into())
842 .unwrap_or(self.address)
843 }
844}
845
846impl L7ListenerHandler for HttpListener {
847 fn get_sticky_name(&self) -> &str {
848 &self.config.sticky_name
849 }
850
851 fn get_sozu_id_header(&self) -> &str {
852 self.config
853 .sozu_id_header
854 .as_deref()
855 .filter(|s| !s.is_empty())
856 .unwrap_or("Sozu-Id")
857 }
858
859 fn get_connect_timeout(&self) -> u32 {
860 self.config.connect_timeout
861 }
862
863 fn frontend_from_request(
865 &self,
866 host: &str,
867 uri: &str,
868 method: &Method,
869 ) -> Result<RouteResult, FrontendFromRequestError> {
870 let start = Instant::now();
871 let (remaining_input, (hostname, _)) = match hostname_and_port(host.as_bytes()) {
872 Ok(tuple) => tuple,
873 Err(parse_error) => {
874 return Err(FrontendFromRequestError::HostParse {
876 host: host.to_owned(),
877 error: parse_error.to_string(),
878 });
879 }
880 };
881 if remaining_input != &b""[..] {
882 return Err(FrontendFromRequestError::InvalidCharsAfterHost(
883 host.to_owned(),
884 ));
885 }
886
887 let host = unsafe { from_utf8_unchecked(hostname) };
902
903 let route = self.fronts.lookup(host, uri, method).map_err(|e| {
904 incr!(names::http::FAILED_BACKEND_MATCHING);
905 FrontendFromRequestError::NoClusterFound(e)
906 })?;
907
908 let now = Instant::now();
909
910 if let Some(cluster) = route.cluster_id.as_deref() {
911 time!(
912 names::event_loop::FRONTEND_MATCHING_TIME,
913 cluster,
914 (now - start).as_millis()
915 );
916 }
917
918 Ok(route)
919 }
920
921 fn get_answers(&self) -> &Rc<RefCell<HttpAnswers>> {
922 &self.answers
923 }
924
925 fn get_h2_flood_config(&self) -> crate::protocol::mux::H2FloodConfig {
926 crate::protocol::mux::H2FloodConfig::from_optional(
934 self.config.h2_max_rst_stream_per_window,
935 self.config.h2_max_ping_per_window,
936 self.config.h2_max_settings_per_window,
937 self.config.h2_max_empty_data_per_window,
938 self.config.h2_max_window_update_stream0_per_window,
939 self.config.h2_max_continuation_frames,
940 self.config.h2_max_glitch_count,
941 self.config.h2_max_rst_stream_lifetime,
942 self.config.h2_max_rst_stream_abusive_lifetime,
943 self.config.h2_max_rst_stream_emitted_lifetime,
944 self.config.h2_max_header_list_size,
945 self.config.h2_max_header_table_size,
946 self.config.h2_max_header_fields,
947 self.config.h2_stream_refusal_percent,
948 )
949 }
950
951 fn get_h2_connection_config(&self) -> crate::protocol::mux::H2ConnectionConfig {
952 crate::protocol::mux::H2ConnectionConfig::from_optional(
953 self.config.h2_initial_connection_window,
954 self.config.h2_max_concurrent_streams,
955 self.config.h2_stream_shrink_ratio,
956 )
957 }
958
959 fn get_h2_stream_idle_timeout(&self) -> std::time::Duration {
960 let seconds = self
967 .config
968 .h2_stream_idle_timeout_seconds
969 .map(|s| u64::from(s.max(1)))
970 .unwrap_or_else(|| u64::from(self.config.back_timeout).max(30));
971 std::time::Duration::from_secs(seconds)
972 }
973
974 fn get_h2_graceful_shutdown_deadline(&self) -> Option<std::time::Duration> {
975 match self.config.h2_graceful_shutdown_deadline_seconds {
976 None => Some(std::time::Duration::from_secs(5)),
977 Some(0) => None,
978 Some(s) => Some(std::time::Duration::from_secs(u64::from(s))),
979 }
980 }
981
982 fn get_elide_x_real_ip(&self) -> bool {
983 self.config.elide_x_real_ip.unwrap_or(false)
984 }
985
986 fn get_send_x_real_ip(&self) -> bool {
987 self.config.send_x_real_ip.unwrap_or(false)
988 }
989
990 fn get_forwarded_headers(&self) -> ForwardedHeaders {
991 self.config.forwarded_headers()
994 }
995}
996
997pub struct HttpProxy {
998 backends: Rc<RefCell<BackendMap>>,
999 clusters: HashMap<ClusterId, Cluster>,
1000 listeners: HashMap<Token, Rc<RefCell<HttpListener>>>,
1001 pool: Rc<RefCell<Pool>>,
1002 registry: Registry,
1003 sessions: Rc<RefCell<SessionManager>>,
1004}
1005
1006impl HttpProxy {
1007 pub fn new(
1008 registry: Registry,
1009 sessions: Rc<RefCell<SessionManager>>,
1010 pool: Rc<RefCell<Pool>>,
1011 backends: Rc<RefCell<BackendMap>>,
1012 ) -> HttpProxy {
1013 HttpProxy {
1014 backends,
1015 clusters: HashMap::new(),
1016 listeners: HashMap::new(),
1017 pool,
1018 registry,
1019 sessions,
1020 }
1021 }
1022
1023 pub fn add_listener(
1024 &mut self,
1025 config: HttpListenerConfig,
1026 token: Token,
1027 ) -> Result<Token, ProxyError> {
1028 if self.listeners.contains_key(&token) {
1029 return Err(ProxyError::ListenerAlreadyPresent);
1030 }
1031 let mut http_listener =
1032 HttpListener::new(config, token).map_err(ProxyError::AddListener)?;
1033 if let Some(sibling) = self
1038 .listeners_at(http_listener.address)
1039 .ok()
1040 .and_then(|l| l.into_iter().next())
1041 {
1042 let sibling = sibling.borrow();
1043 http_listener.fronts = sibling.fronts.clone();
1044 http_listener.tags = sibling.tags.clone();
1045 }
1046 match self.listeners.entry(token) {
1047 Entry::Vacant(entry) => {
1048 entry.insert(Rc::new(RefCell::new(http_listener)));
1049 Ok(token)
1050 }
1051 _ => Err(ProxyError::ListenerAlreadyPresent),
1052 }
1053 }
1054
1055 pub fn get_listener(&self, token: &Token) -> Option<Rc<RefCell<HttpListener>>> {
1056 self.listeners.get(token).cloned()
1057 }
1058
1059 pub fn remove_listener(&mut self, remove: RemoveListener) -> Result<(), ProxyError> {
1060 let len = self.listeners.len();
1061 let remove_address = remove.listener_key();
1062 self.listeners
1063 .retain(|_, l| !l.borrow().is(&remove_address));
1064
1065 if !self.listeners.len() < len {
1066 info!(
1067 "{} no HTTP listener to remove at {}",
1068 log_module_context!(),
1069 remove_address
1070 );
1071 }
1072 Ok(())
1073 }
1074
1075 pub fn inherited_socket_fate(&self, addr: &ListenerKey) -> crate::InheritedSocketFate {
1083 use crate::InheritedSocketFate;
1084 match self
1085 .listeners
1086 .values()
1087 .find(|listener| listener.borrow().is(addr))
1088 {
1089 None => InheritedSocketFate::Unclaimed,
1090 Some(listener) if listener.borrow().active => InheritedSocketFate::Refused,
1091 Some(_) => InheritedSocketFate::Adopted,
1092 }
1093 }
1094
1095 pub fn activate_listener(
1096 &self,
1097 addr: &ListenerKey,
1098 tcp_listener: Option<MioTcpListener>,
1099 ) -> Result<Token, ProxyError> {
1100 let listener = self
1101 .listeners
1102 .values()
1103 .find(|listener| listener.borrow().is(addr))
1104 .ok_or(ProxyError::NoListenerFound(addr.clone()))?;
1105
1106 listener
1107 .borrow_mut()
1108 .activate(&self.registry, tcp_listener)
1109 .map_err(|listener_error| ProxyError::ListenerActivation {
1110 address: addr.address,
1111 listener_error,
1112 })
1113 }
1114
1115 pub fn listener_token(&self, address: &ListenerKey) -> Option<Token> {
1124 self.listeners
1125 .iter()
1126 .find(|(_, listener)| listener.borrow().is(address))
1127 .map(|(token, _)| *token)
1128 }
1129
1130 pub fn give_back_listeners(&mut self) -> Vec<(ListenerKey, MioTcpListener)> {
1131 self.listeners
1132 .values()
1133 .filter_map(|listener| {
1134 let mut owned = listener.borrow_mut();
1135 if let Some(listener) = owned.listener.take() {
1136 owned.active = false;
1139 return Some((owned.key(), listener));
1140 }
1141
1142 None
1143 })
1144 .collect()
1145 }
1146
1147 pub fn give_back_listener(
1148 &mut self,
1149 address: &ListenerKey,
1150 ) -> Result<(Token, MioTcpListener), ProxyError> {
1151 let listener = self
1152 .listeners
1153 .values()
1154 .find(|listener| listener.borrow().is(address))
1155 .ok_or(ProxyError::NoListenerFound(address.clone()))?;
1156
1157 let mut owned = listener.borrow_mut();
1158
1159 let taken_listener = owned
1160 .listener
1161 .take()
1162 .ok_or(ProxyError::UnactivatedListener)?;
1163
1164 owned.active = false;
1167
1168 Ok((owned.token, taken_listener))
1169 }
1170
1171 fn listeners_at(
1175 &self,
1176 address: SocketAddr,
1177 ) -> Result<Vec<Rc<RefCell<HttpListener>>>, ProxyError> {
1178 let mut listeners: Vec<_> = self
1179 .listeners
1180 .iter()
1181 .filter(|(_, listener)| listener.borrow().address == address)
1182 .map(|(token, listener)| (*token, listener.clone()))
1183 .collect();
1184 listeners.sort_by_key(|(token, _)| *token);
1186 let listeners: Vec<_> = listeners
1187 .into_iter()
1188 .map(|(_, listener)| listener)
1189 .collect();
1190 if listeners.is_empty() {
1191 return Err(ProxyError::NoListenerFound(address.into()));
1192 }
1193 Ok(listeners)
1194 }
1195
1196 pub fn update_listener(&mut self, patch: UpdateHttpListenerConfig) -> Result<(), ProxyError> {
1198 let address: std::net::SocketAddr = patch.address.into();
1199 let listener = self
1200 .listeners
1201 .values()
1202 .find(|l| l.borrow().address == address)
1203 .ok_or(ProxyError::NoListenerFound(address.into()))?;
1204 listener
1205 .borrow_mut()
1206 .update_config(&patch)
1207 .map_err(|listener_error| ProxyError::ListenerActivation {
1208 address,
1209 listener_error,
1210 })
1211 }
1212
1213 pub fn add_cluster(&mut self, mut cluster: Cluster) -> Result<(), ProxyError> {
1214 let mut overrides = cluster.answers.clone();
1217 if let Some(answer_503) = cluster.answer_503.take() {
1218 overrides.entry("503".to_owned()).or_insert(answer_503);
1219 }
1220 if !overrides.is_empty() {
1221 for listener in self.listeners.values() {
1222 listener
1223 .borrow()
1224 .answers
1225 .borrow_mut()
1226 .add_cluster_answers(&cluster.cluster_id, &overrides)
1227 .map_err(|(name, error)| {
1228 ProxyError::AddCluster(ListenerError::TemplateParse(name, error))
1229 })?;
1230 }
1231 }
1232 self.clusters
1233 .insert(cluster.cluster_id.as_str().into(), cluster);
1234 Ok(())
1235 }
1236
1237 pub fn remove_cluster(&mut self, cluster_id: &str) -> Result<(), ProxyError> {
1238 self.clusters.remove(cluster_id);
1239
1240 for listener in self.listeners.values() {
1241 listener
1242 .borrow()
1243 .answers
1244 .borrow_mut()
1245 .remove_cluster_answers(cluster_id);
1246 }
1247 Ok(())
1248 }
1249
1250 pub fn add_http_frontend(&mut self, front: RequestHttpFrontend) -> Result<(), ProxyError> {
1251 if front.hsts.is_some() {
1266 incr!(names::http::HSTS_SUPPRESSED_PLAINTEXT);
1267 return Err(ProxyError::HstsOnPlainHttp(front.address.into()));
1268 }
1269
1270 let front = front.clone().to_frontend().map_err(|request_error| {
1271 ProxyError::WrongInputFrontend {
1272 front: Box::new(front),
1273 error: request_error.to_string(),
1274 }
1275 })?;
1276
1277 for listener in self.listeners_at(front.address)? {
1278 let mut listener = listener.borrow_mut();
1279 let hostname = front.hostname.to_owned();
1280 let tags = front.tags.to_owned();
1281
1282 listener
1283 .add_http_front(front.clone())
1284 .map_err(ProxyError::AddFrontend)?;
1285 listener.set_tags(hostname, tags);
1286 }
1287 Ok(())
1288 }
1289
1290 pub fn remove_http_frontend(&mut self, front: RequestHttpFrontend) -> Result<(), ProxyError> {
1291 let front = front.clone().to_frontend().map_err(|request_error| {
1292 ProxyError::WrongInputFrontend {
1293 front: Box::new(front),
1294 error: request_error.to_string(),
1295 }
1296 })?;
1297
1298 let mut result = Ok(());
1302 for listener in self.listeners_at(front.address)? {
1303 let mut listener = listener.borrow_mut();
1304 let hostname = front.hostname.to_owned();
1305
1306 let removed = listener
1307 .remove_http_front(front.clone())
1308 .map_err(ProxyError::RemoveFrontend);
1309 if result.is_ok() {
1310 result = removed;
1311 }
1312
1313 if !listener.fronts.has_hostname(&hostname) {
1314 listener.set_tags(hostname, None);
1315 }
1316 }
1317 result
1318 }
1319
1320 pub fn soft_stop(&mut self) -> Result<(), ProxyError> {
1321 let listeners = std::mem::take(&mut self.listeners);
1322 let mut socket_errors = vec![];
1323 for l in listeners.values() {
1324 if let Some(mut sock) = l.borrow_mut().listener.take() {
1325 debug!("{} deregistering socket {:?}", log_module_context!(), sock);
1326 if let Err(e) = self.registry.deregister(&mut sock) {
1327 let error = format!("socket {sock:?}: {e:?}");
1328 socket_errors.push(error);
1329 }
1330 }
1331 }
1332
1333 if !socket_errors.is_empty() {
1334 return Err(ProxyError::SoftStop {
1335 proxy_protocol: "HTTP".to_string(),
1336 error: format!("Error deregistering listen sockets: {socket_errors:?}"),
1337 });
1338 }
1339
1340 Ok(())
1341 }
1342
1343 pub fn hard_stop(&mut self) -> Result<(), ProxyError> {
1344 let mut listeners = std::mem::take(&mut self.listeners);
1345 let mut socket_errors = vec![];
1346 for (_, l) in listeners.drain() {
1347 if let Some(mut sock) = l.borrow_mut().listener.take() {
1348 debug!("{} deregistering socket {:?}", log_module_context!(), sock);
1349 if let Err(e) = self.registry.deregister(&mut sock) {
1350 let error = format!("socket {sock:?}: {e:?}");
1351 socket_errors.push(error);
1352 }
1353 }
1354 }
1355
1356 if !socket_errors.is_empty() {
1357 return Err(ProxyError::HardStop {
1358 proxy_protocol: "HTTP".to_string(),
1359 error: format!("Error deregistering listen sockets: {socket_errors:?}"),
1360 });
1361 }
1362
1363 Ok(())
1364 }
1365}
1366
1367impl HttpListener {
1368 pub fn key(&self) -> ListenerKey {
1371 ListenerKey::new(self.address, self.config.interface.as_deref())
1372 }
1373
1374 pub fn is(&self, key: &ListenerKey) -> bool {
1376 key.matches(&self.address, self.config.interface.as_deref())
1377 }
1378
1379 pub fn new(config: HttpListenerConfig, token: Token) -> Result<HttpListener, ListenerError> {
1380 if let Some(v) = config.forwarded_headers {
1383 validate_forwarded_headers(v)?;
1384 }
1385 let answers = Self::build_answers(&config)?;
1386 Ok(HttpListener {
1387 active: false,
1388 address: config.address.into(),
1389 answers: Rc::new(RefCell::new(answers)),
1390 config,
1391 fronts: Router::new(),
1392 listener: None,
1393 parked_listener: None,
1394 nodelay_backlog: false,
1395 tags: BTreeMap::new(),
1396 token,
1397 })
1398 }
1399
1400 fn build_answers(config: &HttpListenerConfig) -> Result<HttpAnswers, ListenerError> {
1407 let mut answers_map = config.answers.clone();
1408 if let Some(ref legacy) = config.http_answers {
1409 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1410 }
1411 HttpAnswers::new(&answers_map)
1412 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))
1413 }
1414
1415 pub fn validate_config(config: &HttpListenerConfig) -> Result<(), ListenerError> {
1430 Self::build_answers(config)?;
1431 Ok(())
1432 }
1433
1434 pub fn activate(
1435 &mut self,
1436 registry: &Registry,
1437 tcp_listener: Option<MioTcpListener>,
1438 ) -> Result<Token, ListenerError> {
1439 if self.active {
1440 return Ok(self.token);
1441 }
1442 let address: SocketAddr = self.config.address.into();
1443
1444 let parked = self.parked_listener.take();
1450 let mut listener = match (tcp_listener, parked) {
1451 (Some(inherited), Some(parked)) => {
1452 warn!(
1460 "{} closing the socket parked on the HTTP listener for {}: an \
1461 inherited socket arrived for the same address and is the one being \
1462 activated",
1463 log_module_context!(),
1464 address
1465 );
1466 drop(parked);
1467 inherited
1468 }
1469 (Some(inherited), None) => inherited,
1470 (None, Some(parked)) => parked,
1471 (None, None) => server_bind(address, self.config.interface.as_deref()).map_err(
1472 |server_bind_error| ListenerError::Activation {
1473 address,
1474 error: server_bind_error.to_string(),
1475 },
1476 )?,
1477 };
1478
1479 if let Err(e) = SockRef::from(&listener).set_tcp_nodelay(true) {
1485 error!(
1486 "{} error setting nodelay on listen socket({:?}): {:?}",
1487 log_module_context!(),
1488 listener,
1489 e
1490 );
1491 }
1492
1493 let registration = registry
1494 .register(&mut listener, self.token, Interest::READABLE)
1495 .map_err(ListenerError::SocketRegistration);
1496 if let Err(error) = registration {
1497 self.parked_listener = Some(listener);
1507 return Err(error);
1508 }
1509
1510 self.listener = Some(listener);
1511 self.nodelay_backlog = true;
1512 self.active = true;
1513 Ok(self.token)
1514 }
1515
1516 pub fn update_config(&mut self, patch: &UpdateHttpListenerConfig) -> Result<(), ListenerError> {
1529 validate_h2_flood_knobs_http(patch)?;
1537 if let Some(ref hdr) = patch.sozu_id_header {
1538 validate_sozu_id_header(hdr)?;
1539 }
1540 if let Some(v) = patch.forwarded_headers {
1541 validate_forwarded_headers(v)?;
1542 }
1543 HttpAnswers::validate_patch_templates(patch.http_answers.as_ref(), &patch.answers)
1544 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?;
1545
1546 let mut config = self.config.clone();
1547
1548 if let Some(v) = patch.public_address {
1549 config.public_address = Some(v);
1550 }
1551 if let Some(v) = patch.expect_proxy {
1552 config.expect_proxy = v;
1553 }
1554 if let Some(ref v) = patch.sticky_name {
1555 config.sticky_name = v.to_owned();
1556 }
1557 if let Some(v) = patch.front_timeout {
1558 config.front_timeout = v;
1559 }
1560 if let Some(v) = patch.back_timeout {
1561 config.back_timeout = v;
1562 }
1563 if let Some(v) = patch.connect_timeout {
1564 config.connect_timeout = v;
1565 }
1566 if let Some(v) = patch.request_timeout {
1567 config.request_timeout = v;
1568 }
1569 if let Some(ref v) = patch.sozu_id_header {
1570 config.sozu_id_header = Some(v.to_owned());
1571 }
1572 if let Some(v) = patch.elide_x_real_ip {
1573 config.elide_x_real_ip = Some(v);
1574 }
1575 if let Some(v) = patch.send_x_real_ip {
1576 config.send_x_real_ip = Some(v);
1577 }
1578 if let Some(v) = patch.forwarded_headers {
1579 config.forwarded_headers = Some(v);
1580 }
1581
1582 if let Some(v) = patch.h2_max_rst_stream_per_window {
1584 config.h2_max_rst_stream_per_window = Some(v);
1585 }
1586 if let Some(v) = patch.h2_max_ping_per_window {
1587 config.h2_max_ping_per_window = Some(v);
1588 }
1589 if let Some(v) = patch.h2_max_settings_per_window {
1590 config.h2_max_settings_per_window = Some(v);
1591 }
1592 if let Some(v) = patch.h2_max_empty_data_per_window {
1593 config.h2_max_empty_data_per_window = Some(v);
1594 }
1595 if let Some(v) = patch.h2_max_continuation_frames {
1596 config.h2_max_continuation_frames = Some(v);
1597 }
1598 if let Some(v) = patch.h2_max_glitch_count {
1599 config.h2_max_glitch_count = Some(v);
1600 }
1601 if let Some(v) = patch.h2_initial_connection_window {
1602 config.h2_initial_connection_window = Some(v);
1603 }
1604 if let Some(v) = patch.h2_max_concurrent_streams {
1605 config.h2_max_concurrent_streams = Some(v);
1606 }
1607 if let Some(v) = patch.h2_stream_shrink_ratio {
1608 config.h2_stream_shrink_ratio = Some(v);
1609 }
1610 if let Some(v) = patch.h2_max_rst_stream_lifetime {
1611 config.h2_max_rst_stream_lifetime = Some(v);
1612 }
1613 if let Some(v) = patch.h2_max_rst_stream_abusive_lifetime {
1614 config.h2_max_rst_stream_abusive_lifetime = Some(v);
1615 }
1616 if let Some(v) = patch.h2_max_rst_stream_emitted_lifetime {
1617 config.h2_max_rst_stream_emitted_lifetime = Some(v);
1618 }
1619 if let Some(v) = patch.h2_max_header_list_size {
1620 config.h2_max_header_list_size = Some(v);
1621 }
1622 if let Some(v) = patch.h2_max_header_table_size {
1623 config.h2_max_header_table_size = Some(v);
1624 }
1625 if let Some(v) = patch.h2_max_header_fields {
1626 config.h2_max_header_fields = Some(v);
1627 }
1628 if let Some(v) = patch.h2_stream_refusal_percent {
1629 config.h2_stream_refusal_percent = Some(v);
1630 }
1631 if let Some(v) = patch.h2_stream_idle_timeout_seconds {
1632 config.h2_stream_idle_timeout_seconds = Some(v);
1633 }
1634 if let Some(v) = patch.h2_graceful_shutdown_deadline_seconds {
1635 config.h2_graceful_shutdown_deadline_seconds = Some(v);
1636 }
1637 if let Some(v) = patch.h2_max_window_update_stream0_per_window {
1638 config.h2_max_window_update_stream0_per_window = Some(v);
1639 }
1640
1641 let answers_changed = patch.http_answers.is_some() || !patch.answers.is_empty();
1646 let new_answers = if answers_changed {
1647 if let Some(ref new_answers) = patch.http_answers {
1648 crate::sozu_command::state::merge_custom_http_answers(
1649 &mut config.http_answers,
1650 new_answers,
1651 );
1652 }
1653 for (code, body) in &patch.answers {
1654 if !body.is_empty() {
1655 config.answers.insert(code.clone(), body.clone());
1656 }
1657 }
1658
1659 let mut answers_map = config.answers.clone();
1660 if let Some(ref legacy) = config.http_answers {
1661 crate::protocol::http::answers::merge_legacy_into_map(&mut answers_map, legacy);
1662 }
1663 Some(
1664 HttpAnswers::new(&answers_map)
1665 .map_err(|(name, error)| ListenerError::TemplateParse(name, error))?,
1666 )
1667 } else {
1668 None
1669 };
1670
1671 self.config = config;
1673 if let Some(mut new_answers) = new_answers {
1674 new_answers.cluster_answers = self.answers.borrow().cluster_answers.clone();
1692 self.answers = Rc::new(RefCell::new(new_answers));
1693 }
1694
1695 Ok(())
1696 }
1697
1698 pub fn add_http_front(&mut self, http_front: HttpFrontend) -> Result<(), ListenerError> {
1699 self.fronts
1700 .add_http_front(&http_front)
1701 .map_err(ListenerError::AddFrontend)
1702 }
1703
1704 pub fn remove_http_front(&mut self, http_front: HttpFrontend) -> Result<(), ListenerError> {
1705 debug!(
1706 "{} removing http_front {:?}",
1707 log_module_context!(),
1708 http_front
1709 );
1710 self.fronts
1711 .remove_http_front(&http_front)
1712 .map_err(ListenerError::RemoveFrontend)
1713 }
1714
1715 fn accept(&mut self) -> Result<(TcpStream, SocketAddr), AcceptError> {
1716 if let Some(ref sock) = self.listener {
1717 match sock.accept() {
1718 Ok((frontend_sock, peer)) => {
1719 if self.nodelay_backlog
1720 && let Err(e) = frontend_sock.set_nodelay(true)
1721 {
1722 error!(
1723 "{} error setting nodelay on front socket({:?}): {:?}",
1724 log_module_context!(),
1725 frontend_sock,
1726 e
1727 );
1728 }
1729 Ok((frontend_sock, peer))
1730 }
1731 Err(e) if e.kind() == ErrorKind::WouldBlock => {
1732 self.nodelay_backlog = false;
1734 Err(AcceptError::WouldBlock)
1735 }
1736 Err(e) => {
1737 error!("{} accept() IO error: {:?}", log_module_context!(), e);
1738 Err(AcceptError::IoError)
1739 }
1740 }
1741 } else {
1742 error!(
1743 "{} cannot accept connections, no listening socket available",
1744 log_module_context!()
1745 );
1746 Err(AcceptError::IoError)
1747 }
1748 }
1749}
1750
1751impl ProxyConfiguration for HttpProxy {
1752 fn notify(&mut self, request: WorkerRequest) -> WorkerResponse {
1753 let request_id = request.id.clone();
1754
1755 let result = match request.content.request_type {
1756 Some(RequestType::AddCluster(cluster)) => {
1757 debug!(
1758 "{} {} add cluster {:?}",
1759 log_module_context!(),
1760 request.id,
1761 cluster
1762 );
1763 self.add_cluster(cluster)
1764 }
1765 Some(RequestType::RemoveCluster(cluster_id)) => {
1766 debug!(
1767 "{} {} remove cluster {:?}",
1768 log_module_context!(),
1769 request_id,
1770 cluster_id
1771 );
1772 self.remove_cluster(&cluster_id)
1773 }
1774 Some(RequestType::AddHttpFrontend(front)) => {
1775 debug!(
1776 "{} {} add front {:?}",
1777 log_module_context!(),
1778 request_id,
1779 front
1780 );
1781 self.add_http_frontend(front)
1782 }
1783 Some(RequestType::RemoveHttpFrontend(front)) => {
1784 debug!(
1785 "{} {} remove front {:?}",
1786 log_module_context!(),
1787 request_id,
1788 front
1789 );
1790 self.remove_http_frontend(front)
1791 }
1792 Some(RequestType::RemoveListener(remove)) => {
1793 debug!(
1794 "{} removing HTTP listener at address {:?}",
1795 log_module_context!(),
1796 remove.address
1797 );
1798 self.remove_listener(remove)
1799 }
1800 Some(RequestType::SoftStop(_)) => {
1801 debug!(
1802 "{} {} processing soft shutdown",
1803 log_module_context!(),
1804 request_id
1805 );
1806 match self.soft_stop() {
1807 Ok(()) => {
1808 info!(
1809 "{} {} soft stop successful",
1810 log_module_context!(),
1811 request_id
1812 );
1813 return WorkerResponse::processing(request.id);
1814 }
1815 Err(e) => Err(e),
1816 }
1817 }
1818 Some(RequestType::HardStop(_)) => {
1819 debug!(
1820 "{} {} processing hard shutdown",
1821 log_module_context!(),
1822 request_id
1823 );
1824 match self.hard_stop() {
1825 Ok(()) => {
1826 info!(
1827 "{} {} hard stop successful",
1828 log_module_context!(),
1829 request_id
1830 );
1831 return WorkerResponse::processing(request.id);
1832 }
1833 Err(e) => Err(e),
1834 }
1835 }
1836 Some(RequestType::Status(_)) => {
1837 debug!("{} {} status", log_module_context!(), request_id);
1838 Ok(())
1839 }
1840 other_command => {
1841 debug!(
1842 "{} {} unsupported message for HTTP proxy, ignoring: {:?}",
1843 log_module_context!(),
1844 request.id,
1845 other_command
1846 );
1847 Err(ProxyError::UnsupportedMessage)
1848 }
1849 };
1850
1851 match result {
1852 Ok(()) => {
1853 debug!("{} {} successful", log_module_context!(), request_id);
1854 WorkerResponse::ok(request_id)
1855 }
1856 Err(proxy_error) => {
1857 debug!(
1858 "{} {} unsuccessful: {}",
1859 log_module_context!(),
1860 request_id,
1861 proxy_error
1862 );
1863 WorkerResponse::error(request_id, proxy_error)
1864 }
1865 }
1866 }
1867
1868 fn accept(&mut self, token: ListenToken) -> Result<(TcpStream, SocketAddr), AcceptError> {
1869 if let Some(listener) = self.listeners.get(&Token(token.0)) {
1870 listener.borrow_mut().accept()
1871 } else {
1872 Err(AcceptError::IoError)
1873 }
1874 }
1875
1876 fn create_session(
1877 &mut self,
1878 mut frontend_sock: TcpStream,
1879 peer: SocketAddr,
1880 listener_token: ListenToken,
1881 wait_time: Duration,
1882 proxy: Rc<RefCell<Self>>,
1883 ) -> Result<(), AcceptError> {
1884 let listener = self
1885 .listeners
1886 .get(&Token(listener_token.0))
1887 .cloned()
1888 .ok_or(AcceptError::IoError)?;
1889
1890 let mut session_manager = self.sessions.borrow_mut();
1894 let slab_len_before = session_manager.slab.len();
1895 let session_entry = session_manager.slab.vacant_entry();
1896 let session_token = Token(session_entry.key());
1897 debug_assert_eq!(
1902 session_token.0,
1903 session_entry.key(),
1904 "session token must equal the slab vacant-entry key"
1905 );
1906 let owned = listener.borrow();
1907
1908 if let Err(register_error) = self.registry.register(
1909 &mut frontend_sock,
1910 session_token,
1911 Interest::READABLE | Interest::WRITABLE,
1912 ) {
1913 error!(
1914 "{} error registering listen socket({:?}): {:?}",
1915 log_module_context!(),
1916 frontend_sock,
1917 register_error
1918 );
1919 return Err(AcceptError::RegisterError);
1920 }
1921
1922 let public_address: SocketAddr = match owned.config.public_address {
1923 Some(pub_addr) => pub_addr.into(),
1924 None => owned.config.address.into(),
1925 };
1926
1927 let session = HttpSession::new(
1928 Duration::from_secs(owned.config.back_timeout as u64),
1929 Duration::from_secs(owned.config.connect_timeout as u64),
1930 Duration::from_secs(owned.config.front_timeout as u64),
1931 Duration::from_secs(owned.config.request_timeout as u64),
1932 owned.config.expect_proxy,
1933 listener.clone(),
1934 Rc::downgrade(&self.pool),
1935 proxy,
1936 Rc::clone(&self.backends),
1939 public_address,
1940 frontend_sock,
1941 peer,
1942 session_token,
1943 wait_time,
1944 )?;
1945
1946 debug_assert_eq!(
1950 session.frontend_token, session_token,
1951 "session must own the frontend token it was created with"
1952 );
1953
1954 let session = Rc::new(RefCell::new(session));
1955 session_entry.insert(session);
1956 debug_assert_eq!(
1960 session_manager.slab.len(),
1961 slab_len_before + 1,
1962 "creating a session must occupy exactly one new slab slot"
1963 );
1964
1965 Ok(())
1966 }
1967}
1968
1969impl L7Proxy for HttpProxy {
1970 fn kind(&self) -> ListenerType {
1971 ListenerType::Http
1972 }
1973
1974 fn register_socket(
1975 &self,
1976 source: &mut TcpStream,
1977 token: Token,
1978 interest: Interest,
1979 ) -> Result<(), std::io::Error> {
1980 self.registry.register(source, token, interest)
1981 }
1982
1983 fn add_session(&self, session: Rc<RefCell<dyn ProxySession>>) -> Token {
1984 let mut session_manager = self.sessions.borrow_mut();
1985 let len_before = session_manager.slab.len();
1986 let entry = session_manager.slab.vacant_entry();
1987 let token = Token(entry.key());
1988 let _entry = entry.insert(session);
1989 debug_assert_eq!(
1992 session_manager.slab.len(),
1993 len_before + 1,
1994 "add_session must occupy exactly one new slab slot"
1995 );
1996 debug_assert!(
1997 session_manager.slab.contains(token.0),
1998 "the returned token must index the freshly inserted session"
1999 );
2000 token
2001 }
2002
2003 fn remove_session(&self, token: Token) -> bool {
2004 let mut sessions = self.sessions.borrow_mut();
2005 let was_present = sessions.slab.contains(token.0);
2006 let len_before = sessions.slab.len();
2007 sessions.untrack_all_cluster_ip(token);
2013 let removed = sessions.slab.try_remove(token.0).is_some();
2014 debug_assert_eq!(
2018 removed, was_present,
2019 "try_remove reports presence iff the slot was occupied"
2020 );
2021 debug_assert_eq!(
2022 sessions.slab.len(),
2023 len_before - removed as usize,
2024 "slab len drops by exactly one iff a session was removed"
2025 );
2026 debug_assert!(
2027 !sessions.slab.contains(token.0),
2028 "the slot must be free after remove_session"
2029 );
2030 removed
2031 }
2032
2033 fn clusters(&self) -> &HashMap<ClusterId, Cluster> {
2034 &self.clusters
2035 }
2036
2037 fn sessions(&self) -> Rc<RefCell<SessionManager>> {
2038 self.sessions.clone()
2039 }
2040}
2041
2042pub mod testing {
2043 use crate::testing::*;
2044
2045 pub fn start_http_worker(
2047 config: HttpListenerConfig,
2048 channel: ProxyChannel,
2049 max_buffers: usize,
2050 buffer_size: usize,
2051 ) -> anyhow::Result<()> {
2052 let address = config.address.into();
2053
2054 let ServerParts {
2055 event_loop,
2056 registry,
2057 sessions,
2058 pool,
2059 backends,
2060 client_scm_socket: _,
2061 server_scm_socket,
2062 server_config,
2063 } = prebuild_server(max_buffers, buffer_size, true)?;
2064
2065 let token = {
2066 let mut sessions = sessions.borrow_mut();
2067 let entry = sessions.slab.vacant_entry();
2068 let key = entry.key();
2069 let _ = entry.insert(Rc::new(RefCell::new(ListenSession {
2070 protocol: Protocol::HTTPListen,
2071 })));
2072 Token(key)
2073 };
2074
2075 let mut proxy = HttpProxy::new(registry, sessions.clone(), pool.clone(), backends.clone());
2076 proxy
2077 .add_listener(config, token)
2078 .with_context(|| "Failed at creating adding the listener")?;
2079 proxy
2080 .activate_listener(&address, None)
2081 .with_context(|| "Failed at creating activating the listener")?;
2082
2083 let mut server = Server::new(
2084 event_loop,
2085 channel,
2086 server_scm_socket,
2087 sessions,
2088 pool,
2089 backends,
2090 Some(proxy),
2091 None,
2092 None,
2093 server_config,
2094 None,
2095 false,
2096 )
2097 .with_context(|| "Failed at creating server")?;
2098
2099 debug!("{} starting event loop", log_module_context!());
2100 server.run();
2101 debug!("{} ending event loop", log_module_context!());
2102 Ok(())
2103 }
2104}
2105
2106#[cfg(test)]
2107mod tests {
2108 extern crate tiny_http;
2109
2110 use std::{
2111 io::{Read, Write},
2112 net::TcpStream,
2113 str,
2114 sync::{Arc, Barrier},
2115 thread,
2116 time::Duration,
2117 };
2118
2119 use sozu_command::proto::command::SocketAddress;
2120
2121 use super::{testing::start_http_worker, *};
2122 use crate::sozu_command::{
2123 channel::Channel,
2124 config::ListenerBuilder,
2125 proto::command::{
2126 CustomHttpAnswers, LoadBalancingParams, PathRule, RulePosition, SoftStop,
2127 WorkerRequest, request::RequestType,
2128 },
2129 response::{Backend, HttpFrontend},
2130 };
2131
2132 #[test]
2149 fn get_h2_flood_config_clamps_a_zero_threshold_that_bypassed_config_load() {
2150 let mut config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, 8080))
2151 .to_http(None)
2152 .expect("could not create listener config");
2153 config.h2_max_rst_stream_per_window = Some(0);
2156 config.h2_max_glitch_count = Some(0);
2157
2158 let listener =
2159 HttpListener::new(config, Token(0)).expect("could not build the HTTP listener");
2160 let flood_config = listener.get_h2_flood_config();
2161
2162 assert!(
2163 flood_config.max_rst_stream_per_window() >= 1,
2164 "max_rst_stream_per_window must be clamped to >= 1, got {}",
2165 flood_config.max_rst_stream_per_window()
2166 );
2167 assert!(
2168 flood_config.max_glitch_count() >= 1,
2169 "max_glitch_count must be clamped to >= 1, got {}",
2170 flood_config.max_glitch_count()
2171 );
2172 }
2173
2174 #[test]
2183 fn get_h2_flood_config_maps_every_listener_knob_to_its_own_threshold() {
2184 let mut config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, 8080))
2185 .to_http(None)
2186 .expect("could not create listener config");
2187 config.h2_max_rst_stream_per_window = Some(101);
2188 config.h2_max_ping_per_window = Some(102);
2189 config.h2_max_settings_per_window = Some(103);
2190 config.h2_max_empty_data_per_window = Some(104);
2191 config.h2_max_window_update_stream0_per_window = Some(105);
2192 config.h2_max_continuation_frames = Some(106);
2193 config.h2_max_glitch_count = Some(107);
2194 config.h2_max_rst_stream_lifetime = Some(108);
2195 config.h2_max_rst_stream_abusive_lifetime = Some(109);
2196 config.h2_max_rst_stream_emitted_lifetime = Some(110);
2197 config.h2_max_header_list_size = Some(111);
2198 config.h2_max_header_table_size = Some(112);
2199 config.h2_max_header_fields = Some(113);
2200 config.h2_stream_refusal_percent = Some(114);
2201
2202 let listener =
2203 HttpListener::new(config, Token(0)).expect("could not build the HTTP listener");
2204 let flood = listener.get_h2_flood_config();
2205
2206 assert_eq!(flood.max_rst_stream_per_window(), 101);
2207 assert_eq!(flood.max_ping_per_window(), 102);
2208 assert_eq!(flood.max_settings_per_window(), 103);
2209 assert_eq!(flood.max_empty_data_per_window(), 104);
2210 assert_eq!(flood.max_window_update_stream0_per_window(), 105);
2211 assert_eq!(flood.max_continuation_frames(), 106);
2212 assert_eq!(flood.max_glitch_count(), 107);
2213 assert_eq!(flood.max_rst_stream_lifetime(), 108);
2214 assert_eq!(flood.max_rst_stream_abusive_lifetime(), 109);
2215 assert_eq!(flood.max_rst_stream_emitted_lifetime(), 110);
2216 assert_eq!(flood.max_header_list_size(), 111);
2217 assert_eq!(flood.max_header_table_size(), 112);
2218 assert_eq!(flood.max_header_fields(), 113);
2219 assert_eq!(flood.stream_refusal_percent(), 114);
2220 }
2221
2222 #[test]
2223 fn round_trip() {
2224 setup_test_logger!();
2225 let front_port = crate::testing::provide_port();
2226 let backend_server = Arc::new(
2227 tiny_http::Server::http("127.0.0.1:0").expect("could not create tiny_http server"),
2228 );
2229 let backend_port = backend_server
2230 .server_addr()
2231 .to_ip()
2232 .expect("tiny_http server should bind to IP address")
2233 .port();
2234
2235 let barrier = Arc::new(Barrier::new(2));
2236
2237 let config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, front_port))
2238 .to_http(None)
2239 .expect("could not create listener config");
2240
2241 let (mut command, channel) =
2242 Channel::generate(1000, 10000).expect("should create a channel");
2243
2244 thread::scope(|s| {
2245 let backend_handle = backend_server.clone();
2246 let barrier_clone = barrier.to_owned();
2247 s.spawn(move || {
2248 setup_test_logger!();
2249 start_server(&backend_handle, barrier_clone);
2250 });
2251 barrier.wait();
2252
2253 s.spawn(move || {
2254 setup_test_logger!();
2255 start_http_worker(config, channel, 10, 16384)
2256 .expect("could not start the http server");
2257 });
2258
2259 let front = RequestHttpFrontend {
2260 cluster_id: Some("cluster_1".to_owned()),
2261 address: SocketAddress::new_v4(127, 0, 0, 1, front_port),
2262 hostname: "localhost".to_owned(),
2263 path: PathRule::prefix("/".to_owned()),
2264 ..Default::default()
2265 };
2266 command
2267 .write_message(&WorkerRequest {
2268 id: "ID_ABCD".to_owned(),
2269 content: RequestType::AddHttpFrontend(front).into(),
2270 })
2271 .expect("could not send AddHttpFrontend");
2272 let backend = Backend {
2273 cluster_id: "cluster_1".into(),
2274 backend_id: "cluster_1-0".to_owned(),
2275 address: SocketAddress::new_v4(127, 0, 0, 1, backend_port).into(),
2276 load_balancing_parameters: Some(LoadBalancingParams::default()),
2277 sticky_id: None,
2278 backup: None,
2279 };
2280 command
2281 .write_message(&WorkerRequest {
2282 id: "ID_EFGH".to_owned(),
2283 content: RequestType::AddBackend(backend.to_add_backend()).into(),
2284 })
2285 .expect("could not send AddBackend");
2286
2287 println!("test received: {:?}", command.read_message());
2288 println!("test received: {:?}", command.read_message());
2289
2290 let mut client =
2291 TcpStream::connect(("127.0.0.1", front_port)).expect("could not connect to sozu");
2292
2293 client
2294 .set_read_timeout(Some(Duration::new(1, 0)))
2295 .expect("could not set read timeout");
2296 let request = format!(
2297 "GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\nConnection: Close\r\n\r\n"
2298 );
2299 let w = client.write(request.as_bytes());
2300 println!("http client write: {w:?}");
2301
2302 barrier.wait();
2303 let mut buffer = [0; 4096];
2304 let mut index = 0;
2305
2306 let expected_len = 191;
2309
2310 loop {
2311 assert!(index <= expected_len);
2312 if index == expected_len {
2313 break;
2314 }
2315
2316 let r = client.read(&mut buffer[index..]);
2317 println!("http client read: {r:?}");
2318 match r {
2319 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2320 Ok(sz) => {
2321 index += sz;
2322 }
2323 }
2324 }
2325 println!(
2326 "Response: {}",
2327 str::from_utf8(&buffer[..index]).expect("could not make string from buffer")
2328 );
2329
2330 command
2332 .write_message(&WorkerRequest {
2333 id: "ID_STOP".to_owned(),
2334 content: RequestType::SoftStop(SoftStop {}).into(),
2335 })
2336 .expect("could not send SoftStop");
2337 backend_server.unblock();
2339 });
2340 }
2341
2342 #[test]
2343 fn keep_alive() {
2344 setup_test_logger!();
2345 let front_port = crate::testing::provide_port();
2346 let backend_server = Arc::new(
2347 tiny_http::Server::http("127.0.0.1:0").expect("could not create tiny_http server"),
2348 );
2349 let backend_port = backend_server
2350 .server_addr()
2351 .to_ip()
2352 .expect("tiny_http server should bind to IP address")
2353 .port();
2354
2355 let barrier = Arc::new(Barrier::new(2));
2356
2357 let config = ListenerBuilder::new_http(SocketAddress::new_v4(127, 0, 0, 1, front_port))
2358 .to_http(None)
2359 .expect("could not create listener config");
2360
2361 let (mut command, channel) =
2362 Channel::generate(1000, 10000).expect("should create a channel");
2363
2364 thread::scope(|s| {
2365 let backend_handle = backend_server.clone();
2366 let barrier_clone = barrier.to_owned();
2367 s.spawn(move || {
2368 setup_test_logger!();
2369 start_server(&backend_handle, barrier_clone);
2370 });
2371 barrier.wait();
2372
2373 s.spawn(move || {
2374 setup_test_logger!();
2375 start_http_worker(config, channel, 10, 16384)
2376 .expect("could not start the http server");
2377 });
2378
2379 let front = RequestHttpFrontend {
2380 address: SocketAddress::new_v4(127, 0, 0, 1, front_port),
2381 hostname: "localhost".to_owned(),
2382 path: PathRule::prefix("/".to_owned()),
2383 cluster_id: Some("cluster_1".to_owned()),
2384 ..Default::default()
2385 };
2386 command
2387 .write_message(&WorkerRequest {
2388 id: "ID_ABCD".to_owned(),
2389 content: RequestType::AddHttpFrontend(front).into(),
2390 })
2391 .expect("could not send AddHttpFrontend");
2392 let backend = Backend {
2393 address: SocketAddress::new_v4(127, 0, 0, 1, backend_port).into(),
2394 backend_id: "cluster_1-0".to_owned(),
2395 backup: None,
2396 cluster_id: "cluster_1".into(),
2397 load_balancing_parameters: Some(LoadBalancingParams::default()),
2398 sticky_id: None,
2399 };
2400 command
2401 .write_message(&WorkerRequest {
2402 id: "ID_EFGH".to_owned(),
2403 content: RequestType::AddBackend(backend.to_add_backend()).into(),
2404 })
2405 .expect("could not send AddBackend");
2406
2407 println!("test received: {:?}", command.read_message());
2408 println!("test received: {:?}", command.read_message());
2409
2410 let mut client =
2411 TcpStream::connect(("127.0.0.1", front_port)).expect("could not connect to sozu");
2412 client
2413 .set_read_timeout(Some(Duration::new(5, 0)))
2414 .expect("could not set read timeout");
2415
2416 let expected_len = 191;
2419
2420 let request = format!("GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\n\r\n");
2421 let w = client
2422 .write(request.as_bytes())
2423 .expect("could not write first request");
2424 println!("http client write: {w:?}");
2425 barrier.wait();
2426
2427 let mut buffer = [0; 4096];
2428 let mut index = 0;
2429
2430 loop {
2431 assert!(index <= expected_len);
2432 if index == expected_len {
2433 break;
2434 }
2435
2436 let r = client.read(&mut buffer[index..]);
2437 println!("http client read: {r:?}");
2438 match r {
2439 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2440 Ok(sz) => {
2441 index += sz;
2442 }
2443 }
2444 }
2445
2446 println!(
2447 "Response: {}",
2448 str::from_utf8(&buffer[..index]).expect("could not make string from buffer")
2449 );
2450
2451 println!("first request ended, will send second one");
2452 let request2 = format!("GET / HTTP/1.1\r\nHost: localhost:{front_port}\r\n\r\n");
2453 let w2 = client.write(request2.as_bytes());
2454 println!("http client write: {w2:?}");
2455 barrier.wait();
2456
2457 let mut buffer2 = [0; 4096];
2458 let mut index = 0;
2459
2460 loop {
2461 assert!(index <= expected_len);
2462 if index == expected_len {
2463 break;
2464 }
2465
2466 let r2 = client.read(&mut buffer2[index..]);
2467 println!("http client read: {r2:?}");
2468 match r2 {
2469 Err(e) => panic!("client request should not fail. Error: {e:?}"),
2470 Ok(sz) => {
2471 index += sz;
2472 }
2473 }
2474 }
2475 println!(
2476 "Response: {}",
2477 str::from_utf8(&buffer2[..index]).expect("could not make string from buffer")
2478 );
2479
2480 command
2482 .write_message(&WorkerRequest {
2483 id: "ID_STOP".to_owned(),
2484 content: RequestType::SoftStop(SoftStop {}).into(),
2485 })
2486 .expect("could not send SoftStop");
2487 backend_server.unblock();
2489 });
2490 }
2491
2492 use self::tiny_http::Response;
2493
2494 fn start_server(server: &tiny_http::Server, barrier: Arc<Barrier>) {
2495 let addr = server.server_addr();
2496 info!("starting web server on {:?}", addr);
2497 barrier.wait();
2498
2499 for request in server.incoming_requests() {
2500 info!(
2501 "backend web server got request -> method: {:?}, url: {:?}, headers: {:?}",
2502 request.method(),
2503 request.url(),
2504 request.headers()
2505 );
2506
2507 let response = Response::from_string("hello world");
2508 request
2509 .respond(response)
2510 .expect("could not respond to request");
2511 info!("backend web server sent response");
2512 barrier.wait();
2513 info!("server session stopped");
2514 }
2515
2516 println!("server on {addr:?} closed");
2517 }
2518
2519 #[test]
2520 fn frontend_from_request_test() {
2521 let cluster_id1 = ClusterId::from("cluster_1");
2522 let cluster_id2 = ClusterId::from("cluster_2");
2523 let cluster_id3 = ClusterId::from("cluster_3");
2524 let uri1 = "/".to_owned();
2525 let uri2 = "/yolo".to_owned();
2526 let uri3 = "/yolo/swag".to_owned();
2527
2528 let mut fronts = Router::new();
2529 fronts
2530 .add_http_front(&HttpFrontend {
2531 address: "0.0.0.0:80".parse().unwrap(),
2532 hostname: "lolcatho.st".to_owned(),
2533 method: None,
2534 path: PathRule::prefix(uri1),
2535 position: RulePosition::Tree,
2536 cluster_id: Some(cluster_id1),
2537 tags: None,
2538 redirect: None,
2539 redirect_scheme: None,
2540 redirect_template: None,
2541 rewrite_host: None,
2542 rewrite_path: None,
2543 rewrite_port: None,
2544 required_auth: None,
2545 headers: Vec::new(),
2546 hsts: None,
2547 })
2548 .expect("Could not add http frontend");
2549 fronts
2550 .add_http_front(&HttpFrontend {
2551 address: "0.0.0.0:80".parse().unwrap(),
2552 hostname: "lolcatho.st".to_owned(),
2553 method: None,
2554 path: PathRule::prefix(uri2),
2555 position: RulePosition::Tree,
2556 cluster_id: Some(cluster_id2),
2557 tags: None,
2558 redirect: None,
2559 redirect_scheme: None,
2560 redirect_template: None,
2561 rewrite_host: None,
2562 rewrite_path: None,
2563 rewrite_port: None,
2564 required_auth: None,
2565 headers: Vec::new(),
2566 hsts: None,
2567 })
2568 .expect("Could not add http frontend");
2569 fronts
2570 .add_http_front(&HttpFrontend {
2571 address: "0.0.0.0:80".parse().unwrap(),
2572 hostname: "lolcatho.st".to_owned(),
2573 method: None,
2574 path: PathRule::prefix(uri3),
2575 position: RulePosition::Tree,
2576 cluster_id: Some(cluster_id3),
2577 tags: None,
2578 redirect: None,
2579 redirect_scheme: None,
2580 redirect_template: None,
2581 rewrite_host: None,
2582 rewrite_path: None,
2583 rewrite_port: None,
2584 required_auth: None,
2585 headers: Vec::new(),
2586 hsts: None,
2587 })
2588 .expect("Could not add http frontend");
2589 fronts
2590 .add_http_front(&HttpFrontend {
2591 address: "0.0.0.0:80".parse().unwrap(),
2592 hostname: "other.domain".to_owned(),
2593 method: None,
2594 path: PathRule::prefix("/test".to_owned()),
2595 position: RulePosition::Tree,
2596 cluster_id: Some("cluster_1".into()),
2597 tags: None,
2598 redirect: None,
2599 redirect_scheme: None,
2600 redirect_template: None,
2601 rewrite_host: None,
2602 rewrite_path: None,
2603 rewrite_port: None,
2604 required_auth: None,
2605 headers: Vec::new(),
2606 hsts: None,
2607 })
2608 .expect("Could not add http frontend");
2609
2610 let address = SocketAddress::new_v4(127, 0, 0, 1, 1030);
2611
2612 let default_config = ListenerBuilder::new_http(address)
2613 .to_http(None)
2614 .expect("Could not create default HTTP listener config");
2615
2616 let listener = HttpListener {
2617 parked_listener: None,
2618 nodelay_backlog: false,
2619 listener: None,
2620 address: address.into(),
2621 fronts,
2622 answers: Rc::new(RefCell::new(HttpAnswers::new(&BTreeMap::new()).unwrap())),
2623 config: default_config,
2624 token: Token(0),
2625 active: true,
2626 tags: BTreeMap::new(),
2627 };
2628
2629 let frontend1 = listener.frontend_from_request("lolcatho.st", "/", &Method::Get);
2630 let frontend2 = listener.frontend_from_request("lolcatho.st", "/test", &Method::Get);
2631 let frontend3 = listener.frontend_from_request("lolcatho.st", "/yolo/test", &Method::Get);
2632 let frontend4 = listener.frontend_from_request("lolcatho.st", "/yolo/swag", &Method::Get);
2633 let frontend5 = listener.frontend_from_request("domain", "/", &Method::Get);
2634 assert_eq!(
2635 frontend1
2636 .expect("should find frontend")
2637 .cluster_id
2638 .as_deref(),
2639 Some("cluster_1")
2640 );
2641 assert_eq!(
2642 frontend2
2643 .expect("should find frontend")
2644 .cluster_id
2645 .as_deref(),
2646 Some("cluster_1")
2647 );
2648 assert_eq!(
2649 frontend3
2650 .expect("should find frontend")
2651 .cluster_id
2652 .as_deref(),
2653 Some("cluster_2")
2654 );
2655 assert_eq!(
2656 frontend4
2657 .expect("should find frontend")
2658 .cluster_id
2659 .as_deref(),
2660 Some("cluster_3")
2661 );
2662 assert!(frontend5.is_err());
2663 }
2664
2665 #[test]
2670 fn a_listener_with_an_unknown_forwarded_headers_value_is_refused() {
2671 let address = SocketAddress::new_v4(127, 0, 0, 1, 1041);
2672 let build = |forwarded_headers: Option<i32>| {
2673 let mut cfg = ListenerBuilder::new_http(address)
2674 .to_http(None)
2675 .expect("default HTTP listener config");
2676 cfg.forwarded_headers = forwarded_headers;
2677 HttpListener::new(cfg, Token(0))
2678 };
2679 assert!(build(Some(42)).is_err(), "an unknown mode must be refused");
2680 let listener = build(Some(ForwardedHeaders::Rfc7239 as i32)).expect("a known mode");
2681 assert_eq!(listener.get_forwarded_headers(), ForwardedHeaders::Rfc7239);
2682 }
2683
2684 #[test]
2685 fn h2_stream_idle_timeout_inherits_back_timeout() {
2686 let address = SocketAddress::new_v4(127, 0, 0, 1, 1040);
2687 let build = |back_timeout: u32, explicit: Option<u32>| -> HttpListener {
2688 let mut cfg = ListenerBuilder::new_http(address)
2689 .to_http(None)
2690 .expect("default HTTP listener config");
2691 cfg.back_timeout = back_timeout;
2692 cfg.h2_stream_idle_timeout_seconds = explicit;
2693 HttpListener::new(cfg, Token(0)).expect("build listener")
2694 };
2695
2696 assert_eq!(
2698 build(180, None).get_h2_stream_idle_timeout(),
2699 Duration::from_secs(180)
2700 );
2701
2702 assert_eq!(
2705 build(5, None).get_h2_stream_idle_timeout(),
2706 Duration::from_secs(30)
2707 );
2708
2709 assert_eq!(
2712 build(180, Some(10)).get_h2_stream_idle_timeout(),
2713 Duration::from_secs(10)
2714 );
2715 assert_eq!(
2716 build(5, Some(600)).get_h2_stream_idle_timeout(),
2717 Duration::from_secs(600)
2718 );
2719
2720 assert_eq!(
2722 build(180, Some(0)).get_h2_stream_idle_timeout(),
2723 Duration::from_secs(1)
2724 );
2725 }
2726
2727 #[test]
2748 fn a_listener_answers_reload_publishes_a_new_registry() {
2749 let address = SocketAddress::new_v4(127, 0, 0, 1, 1041);
2750 let config = ListenerBuilder::new_http(address)
2751 .to_http(None)
2752 .expect("default HTTP listener config");
2753 let mut listener = HttpListener::new(config, Token(0)).expect("build listener");
2754
2755 listener
2757 .answers
2758 .borrow_mut()
2759 .add_cluster_answers(
2760 "cluster_1",
2761 &BTreeMap::from([(
2762 "503".to_owned(),
2763 "HTTP/1.1 503 Service Unavailable\r\nContent-Length: 0\r\n\r\n".to_owned(),
2764 )]),
2765 )
2766 .expect("the cluster override must compile");
2767
2768 let captured = listener.get_answers().clone();
2770
2771 listener
2772 .update_config(&UpdateHttpListenerConfig {
2773 address,
2774 answers: BTreeMap::from([(
2775 "404".to_owned(),
2776 "HTTP/1.1 404 Not Found\r\nContent-Length: 0\r\n\r\n".to_owned(),
2777 )]),
2778 ..Default::default()
2779 })
2780 .expect("the answers patch must apply");
2781
2782 assert!(
2783 !Rc::ptr_eq(&captured, listener.get_answers()),
2784 "a reload must publish a NEW answer registry: rewriting the captured \
2785 one reaches every request already in flight"
2786 );
2787 assert!(
2788 captured.borrow().cluster_answers.contains_key("cluster_1"),
2789 "the registry captured before the reload must keep its cluster \
2790 overrides: a request in flight would otherwise lose its custom \
2791 pages mid-response"
2792 );
2793 assert!(
2794 listener
2795 .get_answers()
2796 .borrow()
2797 .cluster_answers
2798 .contains_key("cluster_1"),
2799 "the published registry must carry the cluster overrides forward"
2800 );
2801 }
2802
2803 #[test]
2815 fn a_rejected_patch_leaves_the_listener_unchanged() {
2816 let address = SocketAddress::new_v4(127, 0, 0, 1, 1042);
2817 let config = ListenerBuilder::new_http(address)
2818 .to_http(None)
2819 .expect("default HTTP listener config");
2820 let mut listener = HttpListener::new(config, Token(0)).expect("build listener");
2821
2822 let valid_prefix = UpdateHttpListenerConfig {
2823 address,
2824 front_timeout: Some(99),
2825 sozu_id_header: Some("X-Edge-Id".to_owned()),
2826 forwarded_headers: Some(ForwardedHeaders::Rfc7239 as i32),
2827 h2_max_rst_stream_per_window: Some(7),
2828 ..Default::default()
2829 };
2830 let rejected = [
2831 UpdateHttpListenerConfig {
2832 answers: BTreeMap::from([(
2833 "404".to_owned(),
2834 "not a valid http response".to_owned(),
2835 )]),
2836 ..valid_prefix.clone()
2837 },
2838 UpdateHttpListenerConfig {
2839 http_answers: Some(CustomHttpAnswers {
2840 answer_503: Some("not a valid http response".to_owned()),
2841 ..Default::default()
2842 }),
2843 ..valid_prefix.clone()
2844 },
2845 ];
2846 for patch in rejected {
2847 let config_before = listener.config.clone();
2848 let answers_before = listener.get_answers().clone();
2849 let error = listener
2850 .update_config(&patch)
2851 .expect_err("an unparseable template must be refused");
2852 assert!(
2853 matches!(error, ListenerError::TemplateParse(..)),
2854 "expected TemplateParse, got {error:?}"
2855 );
2856 assert_eq!(
2857 listener.config, config_before,
2858 "a refused patch must leave the listener configuration unchanged"
2859 );
2860 assert!(
2861 Rc::ptr_eq(&answers_before, listener.get_answers()),
2862 "a refused patch must not publish a new answer registry"
2863 );
2864 }
2865
2866 listener
2867 .update_config(&valid_prefix)
2868 .expect("the valid prefix alone must apply");
2869 assert_eq!(listener.config.front_timeout, 99);
2870 assert_eq!(listener.config.sozu_id_header.as_deref(), Some("X-Edge-Id"));
2871 }
2872
2873 #[cfg(target_os = "linux")]
2884 #[test]
2885 fn closed_sessions_leave_their_sockets_to_close() {
2886 use std::os::fd::AsRawFd;
2887
2888 use crate::protocol::mux::test_support::epoll_watches;
2889
2890 let address = SocketAddress::new_v4(127, 0, 0, 1, crate::testing::provide_port());
2891 let parts = crate::testing::prebuild_server(4, 16_384, false)
2892 .expect("test server parts must build");
2893 let registry = parts
2894 .registry
2895 .try_clone()
2896 .expect("the test registry must clone");
2897 let sessions = parts.sessions.clone();
2898 let listener_token = {
2899 let mut sessions = sessions.borrow_mut();
2900 let entry = sessions.slab.vacant_entry();
2901 let key = entry.key();
2902 entry.insert(Rc::new(RefCell::new(crate::server::ListenSession {
2903 protocol: Protocol::HTTPListen,
2904 })));
2905 Token(key)
2906 };
2907 let mut proxy = HttpProxy::new(parts.registry, parts.sessions, parts.pool, parts.backends);
2908 proxy
2909 .add_listener(
2910 ListenerBuilder::new_http(address)
2911 .to_http(None)
2912 .expect("test listener config must build"),
2913 listener_token,
2914 )
2915 .expect("test listener must register");
2916 let proxy = Rc::new(RefCell::new(proxy));
2917
2918 let peer_listener =
2919 std::net::TcpListener::bind("127.0.0.1:0").expect("bind the test peer listener");
2920 let _client = TcpStream::connect(
2921 peer_listener
2922 .local_addr()
2923 .expect("the test peer listener has an address"),
2924 )
2925 .expect("connect the test client");
2926 let (accepted, peer) = peer_listener.accept().expect("accept the test client");
2927 accepted
2928 .set_nonblocking(true)
2929 .expect("the front socket must go non-blocking");
2930 let front = mio::net::TcpStream::from_std(accepted);
2931 let front_fd = front.as_raw_fd();
2932
2933 let session_token = sessions.borrow().slab.vacant_key();
2934 proxy
2935 .borrow_mut()
2936 .create_session(
2937 front,
2938 peer,
2939 ListenToken(listener_token.0),
2940 Duration::ZERO,
2941 proxy.clone(),
2942 )
2943 .expect("the session must be created");
2944 assert!(
2945 sessions.borrow().slab.contains(session_token),
2946 "the session takes the slot that was vacant"
2947 );
2948 assert!(
2949 epoll_watches(®istry, front_fd),
2950 "precondition: the front socket is in the epoll set"
2951 );
2952
2953 let session = sessions.borrow_mut().slab.remove(session_token);
2955 session.borrow_mut().close();
2956 assert!(
2957 epoll_watches(®istry, front_fd),
2958 "HttpSession::close must not deregister a front socket it is about \
2959 to close: the close removes it, the EPOLL_CTL_DEL is a wasted syscall"
2960 );
2961
2962 drop(session);
2963 assert!(
2964 !epoll_watches(®istry, front_fd),
2965 "dropping the session closes the front socket's only descriptor, \
2966 which must take it out of the epoll set"
2967 );
2968 drop(parts.event_loop);
2969 }
2970
2971 #[test]
2986 fn a_steady_state_accepted_socket_inherits_nodelay_and_its_peer_address() {
2987 let address = SocketAddress::new_v4(127, 0, 0, 1, crate::testing::provide_port());
2988 let parts = crate::testing::prebuild_server(4, 16_384, false)
2989 .expect("test server parts must build");
2990 let listener_token = {
2991 let mut sessions = parts.sessions.borrow_mut();
2992 let entry = sessions.slab.vacant_entry();
2993 let key = entry.key();
2994 entry.insert(Rc::new(RefCell::new(crate::server::ListenSession {
2995 protocol: Protocol::HTTPListen,
2996 })));
2997 Token(key)
2998 };
2999 let mut proxy = HttpProxy::new(parts.registry, parts.sessions, parts.pool, parts.backends);
3000 proxy
3001 .add_listener(
3002 ListenerBuilder::new_http(address)
3003 .to_http(None)
3004 .expect("test listener config must build"),
3005 listener_token,
3006 )
3007 .expect("test listener must register");
3008 proxy
3009 .activate_listener(&address.into(), None)
3010 .expect("test listener must activate");
3011
3012 assert!(
3014 matches!(
3015 proxy.accept(ListenToken(listener_token.0)),
3016 Err(AcceptError::WouldBlock)
3017 ),
3018 "precondition: nothing is queued on a freshly bound listener"
3019 );
3020
3021 let client =
3022 TcpStream::connect(SocketAddr::from(address)).expect("connect the test client");
3023 let (accepted, peer) = proxy
3024 .accept(ListenToken(listener_token.0))
3025 .expect("the completed connection must be accepted");
3026
3027 assert_eq!(
3028 socket2::SockRef::from(&accepted).tcp_nodelay().ok(),
3029 Some(true),
3030 "a socket accepted in steady state must inherit TCP_NODELAY from its listener"
3031 );
3032 assert_eq!(
3033 peer,
3034 client.local_addr().expect("the test client has an address"),
3035 "the peer address handed over must be the client's"
3036 );
3037 drop(parts.event_loop);
3038 }
3039}
3040
3041#[cfg(test)]
3042mod listener_sibling_tests {
3043 use sozu_command::{
3044 config::ListenerBuilder,
3045 proto::command::{PathRule, RequestHttpFrontend, RulePosition, SocketAddress},
3046 };
3047
3048 use super::*;
3049 use crate::testing::{ServerParts, prebuild_server, provide_port};
3050
3051 fn proxy() -> HttpProxy {
3052 let ServerParts {
3053 registry,
3054 sessions,
3055 pool,
3056 backends,
3057 ..
3058 } = prebuild_server(16, 16384, false).expect("could not prebuild a test server");
3059 HttpProxy::new(registry, sessions, pool, backends)
3060 }
3061
3062 fn add(proxy: &mut HttpProxy, address: SocketAddress, interface: Option<&str>, token: usize) {
3063 let config = ListenerBuilder::new_http(address)
3064 .with_interface(interface)
3065 .to_http(None)
3066 .expect("could not build the listener config");
3067 proxy
3068 .add_listener(config, Token(token))
3069 .expect("could not add the listener");
3070 }
3071
3072 fn front(address: SocketAddress) -> RequestHttpFrontend {
3073 RequestHttpFrontend {
3074 cluster_id: Some("cluster-a".to_owned()),
3075 address,
3076 hostname: "example.com".to_owned(),
3077 path: PathRule::prefix("/".to_owned()),
3078 ..Default::default()
3079 }
3080 }
3081
3082 fn routes(proxy: &HttpProxy, token: usize) -> bool {
3083 proxy.listeners[&Token(token)]
3084 .borrow()
3085 .fronts
3086 .lookup("example.com", "/", &Method::Get)
3087 .is_ok()
3088 }
3089
3090 #[test]
3096 fn a_listener_added_next_to_a_sibling_takes_over_its_frontends() {
3097 let mut proxy = proxy();
3098 let address = SocketAddress::new_v4(0, 0, 0, 0, provide_port());
3099 add(&mut proxy, address, None, 0);
3100 proxy
3101 .add_http_frontend(front(address))
3102 .expect("add the frontend");
3103 add(&mut proxy, address, Some("lo"), 1);
3104
3105 assert!(routes(&proxy, 0));
3106 assert!(
3107 routes(&proxy, 1),
3108 "the listener added after the frontend must route it too"
3109 );
3110
3111 proxy
3112 .remove_http_frontend(front(address))
3113 .expect("remove the frontend");
3114 assert!(!routes(&proxy, 0));
3115 assert!(!routes(&proxy, 1));
3116 }
3117
3118 #[test]
3122 fn removing_a_frontend_reaches_every_listener_and_reports_a_failure() {
3123 let mut proxy = proxy();
3124 let address = SocketAddress::new_v4(0, 0, 0, 0, provide_port());
3125 add(&mut proxy, address, None, 0);
3126 add(&mut proxy, address, Some("lo"), 1);
3127 let pre = RequestHttpFrontend {
3130 position: RulePosition::Pre.into(),
3131 ..front(address)
3132 };
3133 let frontend = pre
3134 .clone()
3135 .to_frontend()
3136 .expect("the test frontend must convert");
3137 proxy.listeners[&Token(1)]
3138 .borrow_mut()
3139 .add_http_front(frontend)
3140 .expect("add the route to one listener");
3141
3142 assert!(
3143 proxy.remove_http_frontend(pre).is_err(),
3144 "the listener that lacked the route must report it"
3145 );
3146 assert!(
3147 !routes(&proxy, 1),
3148 "the failure on one listener must not spare its sibling's route"
3149 );
3150 }
3151}