1#![allow(dead_code)]
10use crate::connection::should_keep_alive;
49use crate::expect::{
50 CONTINUE_RESPONSE, ExpectHandler, ExpectResult, PreBodyValidator, PreBodyValidators,
51};
52use crate::http2;
53use crate::parser::{ParseError, ParseLimits, ParseStatus, Parser, StatefulParser};
54use crate::response::{ResponseWrite, ResponseWriter};
55use asupersync::io::{AsyncRead, AsyncWrite, ReadBuf};
56use asupersync::net::{TcpListener, TcpStream};
57use asupersync::runtime::{JoinHandle, Runtime, RuntimeHandle, SpawnError};
58use asupersync::signal::{GracefulOutcome, ShutdownController, ShutdownReceiver};
59use asupersync::stream::Stream;
60use asupersync::time::{timeout, timeout_at};
61use asupersync::{Budget, Cx, Time};
62use fastapi_core::app::App;
63use fastapi_core::{Method, Request, RequestContext, Response, StatusCode};
64use std::future::Future;
65use std::io;
66use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr};
67use std::pin::Pin;
68use std::sync::atomic::{AtomicBool, AtomicU64, Ordering};
69use std::sync::{Arc, Mutex, OnceLock};
70use std::task::Poll;
71use std::time::{Duration, Instant};
72
73static START_TIME: OnceLock<Instant> = OnceLock::new();
76
77fn current_time() -> Time {
82 let start = START_TIME.get_or_init(Instant::now);
83 let now = Instant::now();
84 if now < *start {
85 Time::ZERO
86 } else {
87 let elapsed = now.duration_since(*start);
88 Time::from_nanos(elapsed.as_nanos() as u64)
89 }
90}
91
92fn request_deadline_at(now: Time, request_timeout: Time) -> Time {
93 Time::from_nanos(now.as_nanos().saturating_add(request_timeout.as_nanos()))
94}
95
96fn request_deadline(request_timeout: Time) -> Time {
102 request_deadline_at(current_time(), request_timeout)
103}
104
105fn request_cx_from_parent(parent: &Cx, _budget: Budget) -> Cx {
106 parent.clone()
116}
117
118pub const DEFAULT_REQUEST_TIMEOUT_SECS: u64 = 30;
120
121pub const DEFAULT_READ_BUFFER_SIZE: usize = 8192;
123
124pub const DEFAULT_MAX_CONNECTIONS: usize = 0;
126
127pub const DEFAULT_KEEP_ALIVE_TIMEOUT_SECS: u64 = 75;
129
130pub const DEFAULT_MAX_REQUESTS_PER_CONNECTION: usize = 100;
132
133pub const DEFAULT_DRAIN_TIMEOUT_SECS: u64 = 30;
135
136struct CatchUnwind<F>(Pin<Box<F>>);
137
138impl<F: Future> CatchUnwind<F> {
139 fn new(future: F) -> Self {
140 Self(Box::pin(future))
141 }
142}
143
144impl<F: Future> Future for CatchUnwind<F> {
145 type Output = std::thread::Result<F::Output>;
146
147 fn poll(mut self: Pin<&mut Self>, cx: &mut std::task::Context<'_>) -> Poll<Self::Output> {
148 let inner = self.0.as_mut();
149 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| inner.poll(cx)));
150 match result {
151 Ok(Poll::Pending) => Poll::Pending,
152 Ok(Poll::Ready(output)) => Poll::Ready(Ok(output)),
153 Err(payload) => Poll::Ready(Err(payload)),
154 }
155 }
156}
157
158fn panic_payload_message(payload: &(dyn std::any::Any + Send)) -> String {
159 if let Some(message) = payload.downcast_ref::<&'static str>() {
160 (*message).to_string()
161 } else if let Some(message) = payload.downcast_ref::<String>() {
162 message.clone()
163 } else {
164 "non-string panic payload".to_string()
165 }
166}
167
168#[derive(Debug, Clone)]
196pub struct ServerConfig {
197 pub bind_addr: String,
199 pub request_timeout: Time,
201 pub max_connections: usize,
203 pub read_buffer_size: usize,
205 pub parse_limits: ParseLimits,
207 pub allowed_hosts: Vec<String>,
209 pub trust_x_forwarded_host: bool,
211 pub tcp_nodelay: bool,
213 pub keep_alive_timeout: Duration,
216 pub max_requests_per_connection: usize,
218 pub drain_timeout: Duration,
222 pub pre_body_validators: PreBodyValidators,
227}
228
229impl ServerConfig {
230 #[must_use]
232 pub fn new(bind_addr: impl Into<String>) -> Self {
233 Self {
234 bind_addr: bind_addr.into(),
235 request_timeout: Time::from_secs(DEFAULT_REQUEST_TIMEOUT_SECS),
236 max_connections: DEFAULT_MAX_CONNECTIONS,
237 read_buffer_size: DEFAULT_READ_BUFFER_SIZE,
238 parse_limits: ParseLimits::default(),
239 allowed_hosts: Vec::new(),
240 trust_x_forwarded_host: false,
241 tcp_nodelay: true,
242 keep_alive_timeout: Duration::from_secs(DEFAULT_KEEP_ALIVE_TIMEOUT_SECS),
243 max_requests_per_connection: DEFAULT_MAX_REQUESTS_PER_CONNECTION,
244 drain_timeout: Duration::from_secs(DEFAULT_DRAIN_TIMEOUT_SECS),
245 pre_body_validators: PreBodyValidators::new(),
246 }
247 }
248
249 #[must_use]
251 pub fn with_request_timeout(mut self, timeout: Time) -> Self {
252 self.request_timeout = timeout;
253 self
254 }
255
256 #[must_use]
258 pub fn with_request_timeout_secs(mut self, secs: u64) -> Self {
259 self.request_timeout = Time::from_secs(secs);
260 self
261 }
262
263 #[must_use]
265 pub fn with_max_connections(mut self, max: usize) -> Self {
266 self.max_connections = max;
267 self
268 }
269
270 #[must_use]
272 pub fn with_read_buffer_size(mut self, size: usize) -> Self {
273 self.read_buffer_size = size;
274 self
275 }
276
277 #[must_use]
279 pub fn with_parse_limits(mut self, limits: ParseLimits) -> Self {
280 self.parse_limits = limits;
281 self
282 }
283
284 #[must_use]
289 pub fn with_allowed_hosts<I, S>(mut self, hosts: I) -> Self
290 where
291 I: IntoIterator<Item = S>,
292 S: Into<String>,
293 {
294 self.allowed_hosts = hosts
296 .into_iter()
297 .map(|s| s.into().to_ascii_lowercase())
298 .collect();
299 self
300 }
301
302 #[must_use]
306 pub fn allow_host(mut self, host: impl Into<String>) -> Self {
307 self.allowed_hosts.push(host.into().to_ascii_lowercase());
309 self
310 }
311
312 #[must_use]
314 pub fn with_trust_x_forwarded_host(mut self, trust: bool) -> Self {
315 self.trust_x_forwarded_host = trust;
316 self
317 }
318
319 #[must_use]
321 pub fn with_tcp_nodelay(mut self, enabled: bool) -> Self {
322 self.tcp_nodelay = enabled;
323 self
324 }
325
326 #[must_use]
328 pub fn with_pre_body_validators(mut self, validators: PreBodyValidators) -> Self {
329 self.pre_body_validators = validators;
330 self
331 }
332
333 #[must_use]
335 pub fn with_pre_body_validator<V: PreBodyValidator + 'static>(mut self, validator: V) -> Self {
336 self.pre_body_validators.add(validator);
337 self
338 }
339
340 #[must_use]
345 pub fn with_keep_alive_timeout(mut self, timeout: Duration) -> Self {
346 self.keep_alive_timeout = timeout;
347 self
348 }
349
350 #[must_use]
352 pub fn with_keep_alive_timeout_secs(mut self, secs: u64) -> Self {
353 self.keep_alive_timeout = Duration::from_secs(secs);
354 self
355 }
356
357 #[must_use]
361 pub fn with_max_requests_per_connection(mut self, max: usize) -> Self {
362 self.max_requests_per_connection = max;
363 self
364 }
365
366 #[must_use]
372 pub fn with_drain_timeout(mut self, timeout: Duration) -> Self {
373 self.drain_timeout = timeout;
374 self
375 }
376
377 #[must_use]
379 pub fn with_drain_timeout_secs(mut self, secs: u64) -> Self {
380 self.drain_timeout = Duration::from_secs(secs);
381 self
382 }
383}
384
385impl Default for ServerConfig {
386 fn default() -> Self {
387 Self::new("127.0.0.1:8080")
388 }
389}
390
391#[derive(Debug)]
393pub enum ServerError {
394 Io(io::Error),
396 Parse(ParseError),
398 Http2(http2::Http2Error),
400 Shutdown,
402 ConnectionLimitReached,
404 KeepAliveTimeout,
406}
407
408impl std::fmt::Display for ServerError {
409 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
410 match self {
411 Self::Io(e) => write!(f, "IO error: {e}"),
412 Self::Parse(e) => write!(f, "Parse error: {e}"),
413 Self::Http2(e) => write!(f, "HTTP/2 error: {e}"),
414 Self::Shutdown => write!(f, "Server shutdown"),
415 Self::ConnectionLimitReached => write!(f, "Connection limit reached"),
416 Self::KeepAliveTimeout => write!(f, "Keep-alive timeout"),
417 }
418 }
419}
420
421impl std::error::Error for ServerError {
422 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
423 match self {
424 Self::Io(e) => Some(e),
425 Self::Parse(e) => Some(e),
426 Self::Http2(e) => Some(e),
427 _ => None,
428 }
429 }
430}
431
432#[derive(Debug, Clone, PartialEq, Eq)]
437enum HostValidationErrorKind {
438 Missing,
439 Invalid,
440 NotAllowed,
441}
442
443#[derive(Debug, Clone)]
444struct HostValidationError {
445 kind: HostValidationErrorKind,
446 detail: String,
447}
448
449impl HostValidationError {
450 fn missing() -> Self {
451 Self {
452 kind: HostValidationErrorKind::Missing,
453 detail: "missing Host header".to_string(),
454 }
455 }
456
457 fn invalid(detail: impl Into<String>) -> Self {
458 Self {
459 kind: HostValidationErrorKind::Invalid,
460 detail: detail.into(),
461 }
462 }
463
464 fn not_allowed(detail: impl Into<String>) -> Self {
465 Self {
466 kind: HostValidationErrorKind::NotAllowed,
467 detail: detail.into(),
468 }
469 }
470
471 fn response(&self) -> Response {
472 let message = match self.kind {
473 HostValidationErrorKind::Missing => "Bad Request: Host header required",
474 HostValidationErrorKind::Invalid => "Bad Request: invalid Host header",
475 HostValidationErrorKind::NotAllowed => "Bad Request: Host not allowed",
476 };
477 Response::with_status(StatusCode::BAD_REQUEST).body(fastapi_core::ResponseBody::Bytes(
478 message.as_bytes().to_vec(),
479 ))
480 }
481}
482
483#[derive(Debug, Clone, PartialEq, Eq)]
484struct HostHeader {
485 host: String,
486 port: Option<u16>,
487}
488
489fn validate_host_header(
490 request: &Request,
491 config: &ServerConfig,
492) -> Result<HostHeader, HostValidationError> {
493 let raw = extract_effective_host(request, config)?;
494 let parsed = parse_host_header(&raw)
495 .ok_or_else(|| HostValidationError::invalid(format!("invalid host value: {raw}")))?;
496
497 if !is_allowed_host(&parsed, &config.allowed_hosts) {
498 return Err(HostValidationError::not_allowed(format!(
499 "host not allowed: {}",
500 parsed.host
501 )));
502 }
503
504 Ok(parsed)
505}
506
507fn extract_effective_host(
508 request: &Request,
509 config: &ServerConfig,
510) -> Result<String, HostValidationError> {
511 if config.trust_x_forwarded_host {
512 if let Some(value) = header_value(request, "x-forwarded-host")? {
513 let forwarded = extract_first_list_value(&value)
514 .ok_or_else(|| HostValidationError::invalid("empty X-Forwarded-Host value"))?;
515 return Ok(forwarded.to_string());
516 }
517 }
518
519 match header_value(request, "host")? {
520 Some(value) => Ok(value),
521 None => Err(HostValidationError::missing()),
522 }
523}
524
525fn header_value(request: &Request, name: &str) -> Result<Option<String>, HostValidationError> {
526 request
527 .headers()
528 .get(name)
529 .map(|bytes| {
530 std::str::from_utf8(bytes)
531 .map(|s| s.trim().to_string())
532 .map_err(|_| {
533 HostValidationError::invalid(format!("invalid UTF-8 in {name} header"))
534 })
535 })
536 .transpose()
537}
538
539fn extract_first_list_value(value: &str) -> Option<&str> {
540 value.split(',').map(str::trim).find(|v| !v.is_empty())
541}
542
543fn parse_host_header(value: &str) -> Option<HostHeader> {
544 let value = value.trim();
545 if value.is_empty() {
546 return None;
547 }
548 if value.chars().any(|c| c.is_control() || c.is_whitespace()) {
549 return None;
550 }
551
552 if value.starts_with('[') {
553 let end = value.find(']')?;
554 let host = &value[1..end];
555 if host.is_empty() {
556 return None;
557 }
558 if host.parse::<Ipv6Addr>().is_err() {
559 return None;
560 }
561 let rest = &value[end + 1..];
562 let port = if rest.is_empty() {
563 None
564 } else {
565 let port_str = rest.strip_prefix(':')?;
566 parse_port(port_str)
567 };
568 return Some(HostHeader {
569 host: host.to_ascii_lowercase(),
570 port,
571 });
572 }
573
574 let mut parts = value.split(':');
575 let host = parts.next().unwrap_or("");
576 let port_part = parts.next();
577 if parts.next().is_some() {
578 return None;
580 }
581 if host.is_empty() {
582 return None;
583 }
584
585 let port = match port_part {
586 Some(p) => parse_port(p),
587 None => None,
588 };
589
590 if host.parse::<Ipv4Addr>().is_ok() || is_valid_hostname(host) {
591 Some(HostHeader {
592 host: host.to_ascii_lowercase(),
593 port,
594 })
595 } else {
596 None
597 }
598}
599
600fn parse_port(port: &str) -> Option<u16> {
601 if port.is_empty() || !port.chars().all(|c| c.is_ascii_digit()) {
602 return None;
603 }
604 let value = port.parse::<u16>().ok()?;
605 if value == 0 { None } else { Some(value) }
606}
607
608fn is_valid_hostname(host: &str) -> bool {
609 if host.len() > 253 {
611 return false;
612 }
613 for label in host.split('.') {
614 if label.is_empty() || label.len() > 63 {
615 return false;
616 }
617 let bytes = label.as_bytes();
618 if bytes.first() == Some(&b'-') || bytes.last() == Some(&b'-') {
619 return false;
620 }
621 if !label.chars().all(|c| c.is_ascii_alphanumeric() || c == '-') {
622 return false;
623 }
624 }
625 true
626}
627
628fn is_allowed_host(host: &HostHeader, allowed_hosts: &[String]) -> bool {
629 if allowed_hosts.is_empty() {
630 return true;
631 }
632
633 allowed_hosts
634 .iter()
635 .any(|pattern| host_matches_pattern(host, pattern))
636}
637
638fn host_matches_pattern(host: &HostHeader, pattern: &str) -> bool {
639 let pattern = pattern.trim();
641 if pattern.is_empty() {
642 return false;
643 }
644 if pattern == "*" {
645 return true;
646 }
647 if let Some(suffix) = pattern.strip_prefix("*.") {
648 if host.host == suffix {
650 return false;
651 }
652 return host.host.len() > suffix.len() + 1
653 && host.host.ends_with(suffix)
654 && host.host.as_bytes()[host.host.len() - suffix.len() - 1] == b'.';
655 }
656
657 if let Some(parsed) = parse_host_header(pattern) {
658 if parsed.host != host.host {
659 return false;
660 }
661 if let Some(port) = parsed.port {
662 return host.port == Some(port);
663 }
664 return true;
665 }
666
667 false
668}
669
670fn header_str<'a>(req: &'a Request, name: &str) -> Option<&'a str> {
671 req.headers()
672 .get(name)
673 .and_then(|v| std::str::from_utf8(v).ok())
674 .map(str::trim)
675}
676
677fn header_has_token(req: &Request, name: &str, token: &str) -> bool {
678 let Some(v) = header_str(req, name) else {
679 return false;
680 };
681 v.split(',')
682 .map(str::trim)
683 .any(|t| t.eq_ignore_ascii_case(token))
684}
685
686fn connection_has_token(req: &Request, token: &str) -> bool {
687 header_has_token(req, "connection", token)
688}
689
690fn is_websocket_upgrade_request(req: &Request) -> bool {
691 if req.method() != Method::Get {
692 return false;
693 }
694 if !header_has_token(req, "upgrade", "websocket") {
695 return false;
696 }
697 connection_has_token(req, "upgrade")
698}
699
700fn has_request_body_headers(req: &Request) -> bool {
701 if req.headers().contains("transfer-encoding") {
702 return true;
703 }
704 if let Some(v) = header_str(req, "content-length") {
705 if v.is_empty() {
706 return true;
707 }
708 match v.parse::<usize>() {
709 Ok(0) => false,
710 Ok(_) => true,
711 Err(_) => true,
712 }
713 } else {
714 false
715 }
716}
717
718impl From<io::Error> for ServerError {
719 fn from(e: io::Error) -> Self {
720 Self::Io(e)
721 }
722}
723
724impl From<ParseError> for ServerError {
725 fn from(e: ParseError) -> Self {
726 Self::Parse(e)
727 }
728}
729
730impl From<http2::Http2Error> for ServerError {
731 fn from(e: http2::Http2Error) -> Self {
732 Self::Http2(e)
733 }
734}
735
736pub async fn process_connection<H, Fut>(
745 cx: &Cx,
746 request_counter: &AtomicU64,
747 mut stream: TcpStream,
748 _peer_addr: SocketAddr,
749 config: &ServerConfig,
750 handler: H,
751) -> Result<(), ServerError>
752where
753 H: Fn(RequestContext, &mut Request) -> Fut,
754 Fut: Future<Output = Response>,
755{
756 let (proto, buffered) = sniff_protocol(&mut stream, config.keep_alive_timeout).await?;
757 if proto == SniffedProtocol::Http2PriorKnowledge {
758 return process_connection_http2(cx, request_counter, stream, config, handler).await;
759 }
760
761 let mut parser = StatefulParser::new().with_limits(config.parse_limits.clone());
762 if !buffered.is_empty() {
763 parser.feed(&buffered)?;
764 }
765 let mut read_buffer = vec![0u8; config.read_buffer_size];
766 let mut response_writer = ResponseWriter::new();
767 let mut requests_on_connection: usize = 0;
768 let max_requests = config.max_requests_per_connection;
769
770 loop {
771 if cx.is_cancel_requested() {
773 return Ok(());
774 }
775
776 let parse_result = parser.feed(&[])?;
778
779 let mut request = match parse_result {
780 ParseStatus::Complete { request, .. } => request,
781 ParseStatus::Incomplete => {
782 let keep_alive_timeout = config.keep_alive_timeout;
783
784 let bytes_read = if keep_alive_timeout.is_zero() {
785 read_into_buffer(&mut stream, &mut read_buffer).await?
786 } else {
787 match read_with_timeout(&mut stream, &mut read_buffer, keep_alive_timeout).await
788 {
789 Ok(0) => return Ok(()),
790 Ok(n) => n,
791 Err(e) if e.kind() == io::ErrorKind::TimedOut => {
792 cx.trace(&format!(
793 "Keep-alive timeout ({:?}) - closing idle connection",
794 keep_alive_timeout
795 ));
796 return Err(ServerError::KeepAliveTimeout);
797 }
798 Err(e) => return Err(ServerError::Io(e)),
799 }
800 };
801
802 if bytes_read == 0 {
803 return Ok(());
804 }
805
806 match parser.feed(&read_buffer[..bytes_read])? {
807 ParseStatus::Complete { request, .. } => request,
808 ParseStatus::Incomplete => continue,
809 }
810 }
811 };
812
813 requests_on_connection += 1;
814
815 let request_id = request_counter.fetch_add(1, Ordering::Relaxed);
817 let deadline = request_deadline_at(cx.now(), config.request_timeout);
818 let request_budget = Budget::new().with_deadline(deadline);
819 let request_cx = request_cx_from_parent(cx, request_budget);
820 let ctx = RequestContext::new(request_cx, request_id).with_deadline(deadline);
821
822 if let Err(err) = validate_host_header(&request, config) {
824 ctx.trace(&format!("Rejecting request: {}", err.detail));
825 let response = err.response().header("connection", b"close".to_vec());
826 let response_write = response_writer.write(response);
827 write_response(&mut stream, response_write).await?;
828 return Ok(());
829 }
830
831 if let Err(response) = config.pre_body_validators.validate_all(&request) {
833 let response = response.header("connection", b"close".to_vec());
834 let response_write = response_writer.write(response);
835 write_response(&mut stream, response_write).await?;
836 return Ok(());
837 }
838
839 match ExpectHandler::check_expect(&request) {
843 ExpectResult::NoExpectation => {
844 }
846 ExpectResult::ExpectsContinue => {
847 ctx.trace("Sending 100 Continue for Expect: 100-continue");
850 write_raw_response(&mut stream, CONTINUE_RESPONSE).await?;
851 }
852 ExpectResult::UnknownExpectation(value) => {
853 ctx.trace(&format!("Rejecting unknown Expect value: {}", value));
855 let response =
856 ExpectHandler::expectation_failed(format!("Unsupported Expect value: {value}"));
857 let response_write = response_writer.write(response);
858 write_response(&mut stream, response_write).await?;
859 return Ok(());
860 }
861 }
862
863 let client_wants_keep_alive = should_keep_alive(&request);
864 let at_max_requests = max_requests > 0 && requests_on_connection >= max_requests;
865 let mut server_will_keep_alive = client_wants_keep_alive && !at_max_requests;
866
867 let mut response = match timeout_at(deadline, handler(ctx, &mut request)).await {
876 Ok(response) => response,
877 Err(_elapsed) => {
878 server_will_keep_alive = false;
881 Response::with_status(StatusCode::GATEWAY_TIMEOUT).body(
882 fastapi_core::ResponseBody::Bytes(
883 b"Gateway Timeout: request processing exceeded time limit".to_vec(),
884 ),
885 )
886 }
887 };
888
889 response = if server_will_keep_alive {
890 response.header("connection", b"keep-alive".to_vec())
891 } else {
892 response.header("connection", b"close".to_vec())
893 };
894
895 let response_write = response_writer.write(response);
896 write_response(&mut stream, response_write).await?;
897
898 if let Some(tasks) = App::take_background_tasks(&mut request) {
899 tasks.execute_all().await;
900 }
901
902 if !server_will_keep_alive {
903 return Ok(());
904 }
905 }
906}
907
908async fn process_connection_http2<H, Fut>(
909 cx: &Cx,
910 request_counter: &AtomicU64,
911 stream: TcpStream,
912 config: &ServerConfig,
913 handler: H,
914) -> Result<(), ServerError>
915where
916 H: Fn(RequestContext, &mut Request) -> Fut,
917 Fut: Future<Output = Response>,
918{
919 const FLAG_END_HEADERS: u8 = 0x4;
920 const FLAG_ACK: u8 = 0x1;
921
922 let mut framed = http2::FramedH2::new(stream, Vec::new());
923 let mut hpack = http2::HpackDecoder::new();
924 let recv_max_frame_size: u32 = 16 * 1024;
925 let mut peer_max_frame_size: u32 = 16 * 1024;
926 let mut flow_control = http2::H2FlowControl::new();
927
928 let first = framed.read_frame(recv_max_frame_size).await?;
929 if first.header.frame_type() != http2::FrameType::Settings
930 || first.header.stream_id != 0
931 || (first.header.flags & FLAG_ACK) != 0
932 {
933 return Err(http2::Http2Error::Protocol("expected client SETTINGS after preface").into());
934 }
935 apply_http2_settings_with_fc(
936 &mut hpack,
937 &mut peer_max_frame_size,
938 Some(&mut flow_control),
939 &first.payload,
940 )?;
941
942 framed
943 .write_frame(http2::FrameType::Settings, 0, 0, SERVER_SETTINGS_PAYLOAD)
944 .await?;
945 framed
946 .write_frame(http2::FrameType::Settings, FLAG_ACK, 0, &[])
947 .await?;
948
949 let default_body_limit = config.parse_limits.max_request_size;
950 let mut last_stream_id: u32 = 0;
951
952 loop {
953 if cx.is_cancel_requested() {
954 let _ = send_goaway(&mut framed, last_stream_id, h2_error_code::NO_ERROR).await;
955 return Ok(());
956 }
957
958 let frame = framed.read_frame(recv_max_frame_size).await?;
959 match frame.header.frame_type() {
960 http2::FrameType::Settings => {
961 let is_ack = validate_settings_frame(
962 frame.header.stream_id,
963 frame.header.flags,
964 &frame.payload,
965 )?;
966 if is_ack {
967 continue;
968 }
969 apply_http2_settings_with_fc(
970 &mut hpack,
971 &mut peer_max_frame_size,
972 Some(&mut flow_control),
973 &frame.payload,
974 )?;
975 framed
976 .write_frame(http2::FrameType::Settings, FLAG_ACK, 0, &[])
977 .await?;
978 }
979 http2::FrameType::Ping => {
980 if frame.header.stream_id != 0 || frame.payload.len() != 8 {
981 return Err(http2::Http2Error::Protocol("invalid PING frame").into());
982 }
983 if (frame.header.flags & FLAG_ACK) == 0 {
984 framed
985 .write_frame(http2::FrameType::Ping, FLAG_ACK, 0, &frame.payload)
986 .await?;
987 }
988 }
989 http2::FrameType::Goaway => {
990 validate_goaway_payload(&frame.payload)?;
991 return Ok(());
992 }
993 http2::FrameType::PushPromise => {
994 return Err(
995 http2::Http2Error::Protocol("PUSH_PROMISE not supported by server").into(),
996 );
997 }
998 http2::FrameType::Headers => {
999 let stream_id = frame.header.stream_id;
1000 if stream_id == 0 {
1001 return Err(
1002 http2::Http2Error::Protocol("HEADERS must not be on stream 0").into(),
1003 );
1004 }
1005 if stream_id % 2 == 0 {
1006 return Err(http2::Http2Error::Protocol(
1007 "client-initiated stream ID must be odd",
1008 )
1009 .into());
1010 }
1011 if stream_id <= last_stream_id {
1012 return Err(http2::Http2Error::Protocol(
1013 "stream ID must be greater than previous",
1014 )
1015 .into());
1016 }
1017 last_stream_id = stream_id;
1018 let (end_stream, mut header_block) =
1019 extract_header_block_fragment(frame.header.flags, &frame.payload)?;
1020
1021 if (frame.header.flags & FLAG_END_HEADERS) == 0 {
1022 loop {
1023 let cont = framed.read_frame(recv_max_frame_size).await?;
1024 if cont.header.frame_type() != http2::FrameType::Continuation
1025 || cont.header.stream_id != stream_id
1026 {
1027 return Err(http2::Http2Error::Protocol(
1028 "expected CONTINUATION for header block",
1029 )
1030 .into());
1031 }
1032 header_block.extend_from_slice(&cont.payload);
1033 if header_block.len() > MAX_HEADER_BLOCK_SIZE {
1034 return Err(http2::Http2Error::Protocol(
1035 "header block exceeds maximum size",
1036 )
1037 .into());
1038 }
1039 if (cont.header.flags & FLAG_END_HEADERS) != 0 {
1040 break;
1041 }
1042 }
1043 }
1044
1045 let headers = hpack
1046 .decode(&header_block)
1047 .map_err(http2::Http2Error::from)?;
1048 let mut request = request_from_h2_headers(headers)?;
1049
1050 if !end_stream {
1051 let mut body = Vec::new();
1052 let mut stream_reset = false;
1053 let mut stream_received: u32 = 0;
1054 loop {
1055 let f = framed.read_frame(recv_max_frame_size).await?;
1056 match f.header.frame_type() {
1057 http2::FrameType::Data if f.header.stream_id == 0 => {
1058 return Err(http2::Http2Error::Protocol(
1059 "DATA must not be on stream 0",
1060 )
1061 .into());
1062 }
1063 http2::FrameType::Data if f.header.stream_id == stream_id => {
1064 let (data, data_end_stream) =
1065 extract_data_payload(f.header.flags, &f.payload)?;
1066 if body.len().saturating_add(data.len()) > default_body_limit {
1067 return Err(http2::Http2Error::Protocol(
1068 "request body exceeds configured limit",
1069 )
1070 .into());
1071 }
1072 body.extend_from_slice(data);
1073
1074 let data_len = u32::try_from(data.len()).unwrap_or(u32::MAX);
1077 stream_received += data_len;
1078 let conn_inc = flow_control.data_received_connection(data_len);
1079 let stream_inc = flow_control.stream_window_update(stream_received);
1080 if stream_inc > 0 {
1081 stream_received = 0;
1082 }
1083 send_window_updates(&mut framed, conn_inc, stream_id, stream_inc)
1084 .await?;
1085
1086 if data_end_stream {
1087 break;
1088 }
1089 }
1090 http2::FrameType::RstStream => {
1091 validate_rst_stream_payload(f.header.stream_id, &f.payload)?;
1092 if f.header.stream_id == stream_id {
1093 stream_reset = true;
1094 break;
1095 }
1096 }
1097 http2::FrameType::PushPromise => {
1098 return Err(http2::Http2Error::Protocol(
1099 "PUSH_PROMISE not supported by server",
1100 )
1101 .into());
1102 }
1103 http2::FrameType::Settings
1104 | http2::FrameType::Ping
1105 | http2::FrameType::Goaway
1106 | http2::FrameType::WindowUpdate
1107 | http2::FrameType::Priority
1108 | http2::FrameType::Unknown => {
1109 if f.header.frame_type() == http2::FrameType::Goaway {
1110 validate_goaway_payload(&f.payload)?;
1111 return Ok(());
1112 }
1113 if f.header.frame_type() == http2::FrameType::Priority {
1114 validate_priority_payload(f.header.stream_id, &f.payload)?;
1115 }
1116 if f.header.frame_type() == http2::FrameType::WindowUpdate {
1117 validate_window_update_payload(&f.payload)?;
1118 let increment = u32::from_be_bytes([
1119 f.payload[0],
1120 f.payload[1],
1121 f.payload[2],
1122 f.payload[3],
1123 ]) & 0x7FFF_FFFF;
1124 if f.header.stream_id == 0 {
1125 apply_send_conn_window_update(
1126 &mut flow_control,
1127 increment,
1128 )?;
1129 }
1130 }
1131 if f.header.frame_type() == http2::FrameType::Ping {
1132 if f.header.stream_id != 0 || f.payload.len() != 8 {
1133 return Err(http2::Http2Error::Protocol(
1134 "invalid PING frame",
1135 )
1136 .into());
1137 }
1138 if (f.header.flags & FLAG_ACK) == 0 {
1139 framed
1140 .write_frame(
1141 http2::FrameType::Ping,
1142 FLAG_ACK,
1143 0,
1144 &f.payload,
1145 )
1146 .await?;
1147 }
1148 }
1149 if f.header.frame_type() == http2::FrameType::Settings {
1150 let is_ack = validate_settings_frame(
1151 f.header.stream_id,
1152 f.header.flags,
1153 &f.payload,
1154 )?;
1155 if !is_ack {
1156 apply_http2_settings_with_fc(
1157 &mut hpack,
1158 &mut peer_max_frame_size,
1159 Some(&mut flow_control),
1160 &f.payload,
1161 )?;
1162 framed
1163 .write_frame(
1164 http2::FrameType::Settings,
1165 FLAG_ACK,
1166 0,
1167 &[],
1168 )
1169 .await?;
1170 }
1171 }
1172 }
1173 _ => {
1174 return Err(http2::Http2Error::Protocol(
1175 "unsupported frame while reading request body",
1176 )
1177 .into());
1178 }
1179 }
1180 }
1181 if stream_reset {
1182 continue;
1183 }
1184 request.set_body(fastapi_core::Body::Bytes(body));
1185 }
1186
1187 let request_id = request_counter.fetch_add(1, Ordering::Relaxed);
1188 let request_budget =
1189 Budget::new().with_deadline(request_deadline(config.request_timeout));
1190 let request_cx = request_cx_from_parent(cx, request_budget);
1191 let ctx = RequestContext::new(request_cx, request_id);
1192
1193 if let Err(err) = validate_host_header(&request, config) {
1194 let response = err.response();
1195 process_connection_http2_write_response(
1196 &mut framed,
1197 response,
1198 stream_id,
1199 peer_max_frame_size,
1200 recv_max_frame_size,
1201 Some(&mut flow_control),
1202 )
1203 .await?;
1204 continue;
1205 }
1206
1207 if let Err(response) = config.pre_body_validators.validate_all(&request) {
1208 process_connection_http2_write_response(
1209 &mut framed,
1210 response,
1211 stream_id,
1212 peer_max_frame_size,
1213 recv_max_frame_size,
1214 Some(&mut flow_control),
1215 )
1216 .await?;
1217 continue;
1218 }
1219
1220 let response = handler(ctx, &mut request).await;
1221 process_connection_http2_write_response(
1222 &mut framed,
1223 response,
1224 stream_id,
1225 peer_max_frame_size,
1226 recv_max_frame_size,
1227 Some(&mut flow_control),
1228 )
1229 .await?;
1230
1231 if let Some(tasks) = App::take_background_tasks(&mut request) {
1232 tasks.execute_all().await;
1233 }
1234 }
1235 http2::FrameType::WindowUpdate => {
1236 validate_window_update_payload(&frame.payload)?;
1237 let increment = u32::from_be_bytes([
1238 frame.payload[0],
1239 frame.payload[1],
1240 frame.payload[2],
1241 frame.payload[3],
1242 ]) & 0x7FFF_FFFF;
1243 if frame.header.stream_id == 0 {
1244 apply_send_conn_window_update(&mut flow_control, increment)?;
1245 }
1246 }
1247 _ => {
1248 handle_h2_idle_frame(&frame)?;
1249 }
1250 }
1251 }
1252}
1253
1254async fn process_connection_http2_write_response(
1255 framed: &mut http2::FramedH2,
1256 response: Response,
1257 stream_id: u32,
1258 mut peer_max_frame_size: u32,
1259 recv_max_frame_size: u32,
1260 mut flow_control: Option<&mut http2::H2FlowControl>,
1261) -> Result<(), ServerError> {
1262 use std::future::poll_fn;
1263
1264 const FLAG_END_STREAM: u8 = 0x1;
1265 const FLAG_END_HEADERS: u8 = 0x4;
1266
1267 let (status, mut headers, mut body) = response.into_parts();
1268 if !status.allows_body() {
1269 body = fastapi_core::ResponseBody::Empty;
1270 }
1271
1272 let mut add_content_length = matches!(body, fastapi_core::ResponseBody::Bytes(_));
1273 for (name, _) in &headers {
1274 if name.eq_ignore_ascii_case("content-length") {
1275 add_content_length = false;
1276 break;
1277 }
1278 }
1279 if add_content_length {
1280 headers.push((
1281 "content-length".to_string(),
1282 body.len().to_string().into_bytes(),
1283 ));
1284 }
1285
1286 let mut block: Vec<u8> = Vec::new();
1287 let status_bytes = status.as_u16().to_string().into_bytes();
1288 http2::hpack_encode_literal_without_indexing(&mut block, b":status", &status_bytes);
1289 for (name, value) in &headers {
1290 if is_h2_forbidden_header_name(name) {
1291 continue;
1292 }
1293 let n = name.to_ascii_lowercase();
1294 http2::hpack_encode_literal_without_indexing(&mut block, n.as_bytes(), value);
1295 }
1296
1297 let max = usize::try_from(peer_max_frame_size).unwrap_or(16 * 1024);
1298 let mut headers_flags = FLAG_END_HEADERS;
1299 if body.is_empty() {
1300 headers_flags |= FLAG_END_STREAM;
1301 }
1302
1303 if block.len() <= max {
1304 framed
1305 .write_frame(http2::FrameType::Headers, headers_flags, stream_id, &block)
1306 .await?;
1307 } else {
1308 let mut first_flags = 0u8;
1310 if body.is_empty() {
1311 first_flags |= FLAG_END_STREAM;
1312 }
1313 let (first, rest) = block.split_at(max);
1314 framed
1315 .write_frame(http2::FrameType::Headers, first_flags, stream_id, first)
1316 .await?;
1317 let mut remaining = rest;
1318 while remaining.len() > max {
1319 let (chunk, r) = remaining.split_at(max);
1320 framed
1321 .write_frame(http2::FrameType::Continuation, 0, stream_id, chunk)
1322 .await?;
1323 remaining = r;
1324 }
1325 framed
1326 .write_frame(
1327 http2::FrameType::Continuation,
1328 FLAG_END_HEADERS,
1329 stream_id,
1330 remaining,
1331 )
1332 .await?;
1333 }
1334
1335 let mut stream_send_window: i64 = flow_control
1337 .as_ref()
1338 .map_or(i64::MAX, |fc| i64::from(fc.peer_initial_window_size()));
1339
1340 match body {
1341 fastapi_core::ResponseBody::Empty => Ok(()),
1342 fastapi_core::ResponseBody::Bytes(bytes) => {
1343 if bytes.is_empty() {
1344 return Ok(());
1345 }
1346 let mut remaining = bytes.as_slice();
1347 while !remaining.is_empty() {
1348 let max = usize::try_from(peer_max_frame_size).unwrap_or(16 * 1024);
1349 let send_len = remaining.len().min(max);
1350
1351 let send_len = h2_fc_clamp_send(
1352 framed,
1353 &mut flow_control,
1354 &mut stream_send_window,
1355 stream_id,
1356 send_len,
1357 &mut peer_max_frame_size,
1358 recv_max_frame_size,
1359 )
1360 .await?;
1361
1362 let (chunk, r) = remaining.split_at(send_len);
1363 let flags = if r.is_empty() { FLAG_END_STREAM } else { 0 };
1364 framed
1365 .write_frame(http2::FrameType::Data, flags, stream_id, chunk)
1366 .await?;
1367 remaining = r;
1368 }
1369 Ok(())
1370 }
1371 fastapi_core::ResponseBody::Stream(mut s) => {
1372 loop {
1373 let next = poll_fn(|cx| Pin::new(&mut s).poll_next(cx)).await;
1374 match next {
1375 Some(chunk) => {
1376 let mut remaining = chunk.as_slice();
1377 while !remaining.is_empty() {
1378 let max = usize::try_from(peer_max_frame_size).unwrap_or(16 * 1024);
1379 let send_len = remaining.len().min(max);
1380 let send_len = h2_fc_clamp_send(
1381 framed,
1382 &mut flow_control,
1383 &mut stream_send_window,
1384 stream_id,
1385 send_len,
1386 &mut peer_max_frame_size,
1387 recv_max_frame_size,
1388 )
1389 .await?;
1390
1391 let (c, r) = remaining.split_at(send_len);
1392 framed
1393 .write_frame(http2::FrameType::Data, 0, stream_id, c)
1394 .await?;
1395 remaining = r;
1396 }
1397 }
1398 None => {
1399 framed
1400 .write_frame(http2::FrameType::Data, FLAG_END_STREAM, stream_id, &[])
1401 .await?;
1402 break;
1403 }
1404 }
1405 }
1406 Ok(())
1407 }
1408 }
1409}
1410
1411async fn h2_fc_clamp_send(
1416 framed: &mut http2::FramedH2,
1417 flow_control: &mut Option<&mut http2::H2FlowControl>,
1418 stream_send_window: &mut i64,
1419 stream_id: u32,
1420 desired: usize,
1421 peer_max_frame_size: &mut u32,
1422 recv_max_frame_size: u32,
1423) -> Result<usize, ServerError> {
1424 let fc = match flow_control.as_mut() {
1425 Some(fc) => fc,
1426 None => return Ok(desired),
1427 };
1428
1429 loop {
1430 let conn_avail = usize::try_from(fc.send_conn_window().max(0)).unwrap_or(0);
1431 let stream_avail = usize::try_from((*stream_send_window).max(0)).unwrap_or(0);
1432 let peer_max = usize::try_from(*peer_max_frame_size).unwrap_or(16 * 1024);
1433 let allowed = desired.min(conn_avail).min(stream_avail).min(peer_max);
1434
1435 if allowed > 0 {
1436 let send = allowed;
1437 fc.consume_send_conn_window(u32::try_from(send).unwrap_or(u32::MAX));
1438 *stream_send_window -= i64::try_from(send).unwrap_or(i64::MAX);
1439 return Ok(send);
1440 }
1441
1442 let frame = framed.read_frame(recv_max_frame_size).await?;
1444 match frame.header.frame_type() {
1445 http2::FrameType::WindowUpdate => {
1446 apply_peer_window_update_for_send(
1447 fc,
1448 stream_send_window,
1449 stream_id,
1450 frame.header.stream_id,
1451 &frame.payload,
1452 )?;
1453 }
1454 http2::FrameType::Ping => {
1455 if frame.header.stream_id != 0 || frame.payload.len() != 8 {
1456 return Err(ServerError::Http2(http2::Http2Error::Protocol(
1457 "invalid PING frame",
1458 )));
1459 }
1460 if frame.header.flags & 0x1 == 0 {
1461 framed
1462 .write_frame(http2::FrameType::Ping, 0x1, 0, &frame.payload)
1463 .await?;
1464 }
1465 }
1466 http2::FrameType::Settings => {
1467 let is_ack = validate_settings_frame(
1468 frame.header.stream_id,
1469 frame.header.flags,
1470 &frame.payload,
1471 )?;
1472 if !is_ack {
1473 apply_peer_settings_for_send(
1474 fc,
1475 stream_send_window,
1476 peer_max_frame_size,
1477 &frame.payload,
1478 )?;
1479 framed
1481 .write_frame(http2::FrameType::Settings, 0x1, 0, &[])
1482 .await?;
1483 }
1484 }
1485 http2::FrameType::Goaway => {
1486 validate_goaway_payload(&frame.payload)?;
1487 return Err(ServerError::Http2(http2::Http2Error::Protocol(
1488 "received GOAWAY while writing response",
1489 )));
1490 }
1491 http2::FrameType::RstStream => {
1492 validate_rst_stream_payload(frame.header.stream_id, &frame.payload)?;
1493 if frame.header.stream_id == stream_id {
1494 return Err(ServerError::Http2(http2::Http2Error::Protocol(
1495 "stream reset by peer during response",
1496 )));
1497 }
1498 }
1499 _ => { }
1500 }
1501 }
1502}
1503
1504pub struct TcpServer {
1510 config: ServerConfig,
1511 request_counter: Arc<AtomicU64>,
1512 connection_counter: Arc<AtomicU64>,
1514 draining: Arc<AtomicBool>,
1516 connection_handles: Mutex<Vec<JoinHandle<()>>>,
1518 shutdown_controller: Arc<ShutdownController>,
1520 metrics_counters: Arc<MetricsCounters>,
1522}
1523
1524struct ConnectionSlotGuard {
1525 counter: Arc<AtomicU64>,
1526}
1527
1528impl ConnectionSlotGuard {
1529 fn new(counter: Arc<AtomicU64>) -> Self {
1530 Self { counter }
1531 }
1532}
1533
1534impl Drop for ConnectionSlotGuard {
1535 fn drop(&mut self) {
1536 self.counter.fetch_sub(1, Ordering::Relaxed);
1537 }
1538}
1539
1540impl std::fmt::Debug for TcpServer {
1541 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1542 f.debug_struct("TcpServer")
1543 .field("config", &self.config)
1544 .field("request_counter", &self.request_counter)
1545 .field("connection_counter", &self.connection_counter)
1546 .field("draining", &self.draining)
1547 .field(
1548 "connection_handles",
1549 &self.connection_handles.lock().map_or(0, |h| h.len()),
1550 )
1551 .field("shutdown_controller", &self.shutdown_controller)
1552 .field("metrics_counters", &self.metrics_counters)
1553 .finish()
1554 }
1555}
1556
1557impl TcpServer {
1558 #[must_use]
1560 pub fn new(config: ServerConfig) -> Self {
1561 Self {
1562 config,
1563 request_counter: Arc::new(AtomicU64::new(0)),
1564 connection_counter: Arc::new(AtomicU64::new(0)),
1565 draining: Arc::new(AtomicBool::new(false)),
1566 connection_handles: Mutex::new(Vec::new()),
1567 shutdown_controller: Arc::new(ShutdownController::new()),
1568 metrics_counters: Arc::new(MetricsCounters::new()),
1569 }
1570 }
1571
1572 fn clone_for_connection_task(&self) -> Self {
1573 Self {
1574 config: self.config.clone(),
1575 request_counter: Arc::clone(&self.request_counter),
1576 connection_counter: Arc::clone(&self.connection_counter),
1577 draining: Arc::clone(&self.draining),
1578 connection_handles: Mutex::new(Vec::new()),
1579 shutdown_controller: Arc::clone(&self.shutdown_controller),
1580 metrics_counters: Arc::clone(&self.metrics_counters),
1581 }
1582 }
1583
1584 #[must_use]
1586 pub fn config(&self) -> &ServerConfig {
1587 &self.config
1588 }
1589
1590 fn next_request_id(&self) -> u64 {
1592 self.request_counter.fetch_add(1, Ordering::Relaxed)
1593 }
1594
1595 #[must_use]
1597 pub fn current_connections(&self) -> u64 {
1598 self.connection_counter.load(Ordering::Relaxed)
1599 }
1600
1601 #[must_use]
1603 pub fn metrics(&self) -> ServerMetrics {
1604 ServerMetrics {
1605 active_connections: self.connection_counter.load(Ordering::Relaxed),
1606 total_accepted: self.metrics_counters.total_accepted.load(Ordering::Relaxed),
1607 total_rejected: self.metrics_counters.total_rejected.load(Ordering::Relaxed),
1608 total_timed_out: self
1609 .metrics_counters
1610 .total_timed_out
1611 .load(Ordering::Relaxed),
1612 total_requests: self.request_counter.load(Ordering::Relaxed),
1613 bytes_in: self.metrics_counters.bytes_in.load(Ordering::Relaxed),
1614 bytes_out: self.metrics_counters.bytes_out.load(Ordering::Relaxed),
1615 }
1616 }
1617
1618 fn record_bytes_in(&self, n: u64) {
1620 self.metrics_counters
1621 .bytes_in
1622 .fetch_add(n, Ordering::Relaxed);
1623 }
1624
1625 fn record_bytes_out(&self, n: u64) {
1627 self.metrics_counters
1628 .bytes_out
1629 .fetch_add(n, Ordering::Relaxed);
1630 }
1631
1632 fn try_acquire_connection(&self) -> bool {
1637 let max = self.config.max_connections;
1638 if max == 0 {
1639 self.connection_counter.fetch_add(1, Ordering::Relaxed);
1641 self.metrics_counters
1642 .total_accepted
1643 .fetch_add(1, Ordering::Relaxed);
1644 return true;
1645 }
1646
1647 let mut current = self.connection_counter.load(Ordering::Relaxed);
1649 loop {
1650 if current >= max as u64 {
1651 self.metrics_counters
1652 .total_rejected
1653 .fetch_add(1, Ordering::Relaxed);
1654 return false;
1655 }
1656 match self.connection_counter.compare_exchange_weak(
1657 current,
1658 current + 1,
1659 Ordering::AcqRel,
1660 Ordering::Relaxed,
1661 ) {
1662 Ok(_) => {
1663 self.metrics_counters
1664 .total_accepted
1665 .fetch_add(1, Ordering::Relaxed);
1666 return true;
1667 }
1668 Err(actual) => current = actual,
1669 }
1670 }
1671 }
1672
1673 fn release_connection(&self) {
1675 self.connection_counter.fetch_sub(1, Ordering::Relaxed);
1676 }
1677
1678 #[must_use]
1680 pub fn is_draining(&self) -> bool {
1681 self.draining.load(Ordering::Acquire)
1682 }
1683
1684 pub fn start_drain(&self) {
1691 self.draining.store(true, Ordering::Release);
1692 }
1693
1694 pub async fn wait_for_drain(&self, timeout: Duration, poll_interval: Option<Duration>) -> bool {
1704 let start = Instant::now();
1705 let poll_interval = poll_interval.unwrap_or(Duration::from_millis(10));
1706
1707 while self.current_connections() > 0 {
1708 if start.elapsed() >= timeout {
1709 return false;
1710 }
1711 std::thread::sleep(poll_interval);
1721 }
1722 true
1723 }
1724
1725 pub async fn drain(&self) -> u64 {
1733 self.start_drain();
1734 let drained = self.wait_for_drain(self.config.drain_timeout, None).await;
1735 if drained {
1736 0
1737 } else {
1738 self.current_connections()
1739 }
1740 }
1741
1742 #[must_use]
1747 pub fn shutdown_controller(&self) -> &Arc<ShutdownController> {
1748 &self.shutdown_controller
1749 }
1750
1751 #[must_use]
1756 pub fn subscribe_shutdown(&self) -> ShutdownReceiver {
1757 self.shutdown_controller.subscribe()
1758 }
1759
1760 pub fn shutdown(&self) {
1769 self.start_drain();
1770 self.shutdown_controller.shutdown();
1771 }
1772
1773 #[must_use]
1775 pub fn is_shutting_down(&self) -> bool {
1776 self.shutdown_controller.is_shutting_down() || self.is_draining()
1777 }
1778
1779 pub async fn serve_with_shutdown<H, Fut>(
1809 &self,
1810 cx: &Cx,
1811 mut shutdown: ShutdownReceiver,
1812 handler: H,
1813 ) -> Result<GracefulOutcome<()>, ServerError>
1814 where
1815 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
1816 Fut: Future<Output = Response> + Send + 'static,
1817 {
1818 let bind_addr = self.config.bind_addr.clone();
1819 let listener = TcpListener::bind(bind_addr).await?;
1820 let local_addr = listener.local_addr()?;
1821
1822 cx.trace(&format!(
1823 "Server listening on {local_addr} (with graceful shutdown)"
1824 ));
1825
1826 let result = self
1828 .accept_loop_with_shutdown(cx, listener, handler, &mut shutdown)
1829 .await;
1830
1831 match result {
1832 Ok(outcome) => {
1833 if outcome.is_shutdown() {
1834 cx.trace("Shutdown signal received, draining connections");
1835 self.start_drain();
1836 self.drain_connection_tasks(cx).await;
1837 }
1838 Ok(outcome)
1839 }
1840 Err(e) => Err(e),
1841 }
1842 }
1843
1844 async fn accept_loop_with_shutdown<H, Fut>(
1846 &self,
1847 cx: &Cx,
1848 listener: TcpListener,
1849 handler: H,
1850 shutdown: &mut ShutdownReceiver,
1851 ) -> Result<GracefulOutcome<()>, ServerError>
1852 where
1853 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
1854 Fut: Future<Output = Response> + Send + 'static,
1855 {
1856 let handler = Arc::new(handler);
1857
1858 loop {
1859 if shutdown.is_shutting_down() {
1861 return Ok(GracefulOutcome::ShutdownSignaled);
1862 }
1863 if cx.is_cancel_requested() || self.is_draining() {
1864 return Ok(GracefulOutcome::ShutdownSignaled);
1865 }
1866
1867 let (mut stream, peer_addr) = match listener.accept().await {
1869 Ok(conn) => conn,
1870 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
1871 continue;
1872 }
1873 Err(e) => {
1874 cx.trace(&format!("Accept error: {e}"));
1875 if is_fatal_accept_error(&e) {
1876 self.drain_connection_tasks(cx).await;
1877 return Err(ServerError::Io(e));
1878 }
1879 continue;
1880 }
1881 };
1882
1883 if !self.try_acquire_connection() {
1885 cx.trace(&format!(
1886 "Connection limit reached ({}), rejecting {peer_addr}",
1887 self.config.max_connections
1888 ));
1889
1890 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
1891 .header("connection", b"close".to_vec())
1892 .body(fastapi_core::ResponseBody::Bytes(
1893 b"503 Service Unavailable: connection limit reached".to_vec(),
1894 ));
1895 let mut writer = crate::response::ResponseWriter::new();
1896 let response_bytes = writer.write(response);
1897 let _ = write_response(&mut stream, response_bytes).await;
1898 continue;
1899 }
1900
1901 if self.config.tcp_nodelay {
1903 let _ = stream.set_nodelay(true);
1904 }
1905
1906 cx.trace(&format!(
1907 "Accepted connection from {peer_addr} ({}/{})",
1908 self.current_connections(),
1909 if self.config.max_connections == 0 {
1910 "∞".to_string()
1911 } else {
1912 self.config.max_connections.to_string()
1913 }
1914 ));
1915
1916 let request_id = self.next_request_id();
1917 let request_budget =
1918 Budget::new().with_deadline(request_deadline(self.config.request_timeout));
1919 let request_cx = request_cx_from_parent(cx, request_budget);
1920 let ctx = RequestContext::new(request_cx, request_id);
1921
1922 let result = self
1924 .handle_connection(&ctx, stream, peer_addr, &*handler)
1925 .await;
1926
1927 self.release_connection();
1928
1929 if let Err(e) = result {
1930 cx.trace(&format!("Connection error from {peer_addr}: {e}"));
1931 }
1932 }
1933 }
1934
1935 pub async fn serve<H, Fut>(&self, cx: &Cx, handler: H) -> Result<(), ServerError>
1949 where
1950 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
1951 Fut: Future<Output = Response> + Send + 'static,
1952 {
1953 let bind_addr = self.config.bind_addr.clone();
1954 let listener = TcpListener::bind(bind_addr).await?;
1955 let local_addr = listener.local_addr()?;
1956
1957 cx.trace(&format!("Server listening on {local_addr}"));
1958
1959 self.accept_loop(cx, listener, handler).await
1960 }
1961
1962 pub async fn serve_on<H, Fut>(
1966 &self,
1967 cx: &Cx,
1968 listener: TcpListener,
1969 handler: H,
1970 ) -> Result<(), ServerError>
1971 where
1972 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
1973 Fut: Future<Output = Response> + Send + 'static,
1974 {
1975 self.accept_loop(cx, listener, handler).await
1976 }
1977
1978 pub async fn serve_handler(
1999 &self,
2000 cx: &Cx,
2001 handler: Arc<dyn fastapi_core::Handler>,
2002 ) -> Result<(), ServerError> {
2003 let bind_addr = self.config.bind_addr.clone();
2004 let listener = TcpListener::bind(bind_addr).await?;
2005 let local_addr = listener.local_addr()?;
2006
2007 cx.trace(&format!("Server listening on {local_addr}"));
2008
2009 self.accept_loop_handler(cx, listener, handler).await
2010 }
2011
2012 pub async fn serve_app(&self, cx: &Cx, app: Arc<App>) -> Result<(), ServerError> {
2017 let bind_addr = self.config.bind_addr.clone();
2018 let listener = TcpListener::bind(bind_addr).await?;
2019 let local_addr = listener.local_addr()?;
2020
2021 cx.trace(&format!("Server listening on {local_addr}"));
2022 self.accept_loop_app(cx, listener, app).await
2023 }
2024
2025 pub async fn serve_app_concurrent(&self, cx: &Cx, app: Arc<App>) -> Result<(), ServerError> {
2036 let bind_addr = self.config.bind_addr.clone();
2037 let listener = TcpListener::bind(bind_addr).await?;
2038 let local_addr = listener.local_addr()?;
2039
2040 cx.trace(&format!(
2041 "Server listening on {local_addr} (concurrent app mode)"
2042 ));
2043 self.accept_loop_app_concurrent(cx, listener, app).await
2044 }
2045
2046 pub async fn serve_on_handler(
2048 &self,
2049 cx: &Cx,
2050 listener: TcpListener,
2051 handler: Arc<dyn fastapi_core::Handler>,
2052 ) -> Result<(), ServerError> {
2053 self.accept_loop_handler(cx, listener, handler).await
2054 }
2055
2056 pub async fn serve_on_app(
2062 &self,
2063 cx: &Cx,
2064 listener: TcpListener,
2065 app: Arc<App>,
2066 ) -> Result<(), ServerError> {
2067 self.accept_loop_app(cx, listener, app).await
2068 }
2069
2070 pub async fn serve_on_app_concurrent(
2078 &self,
2079 cx: &Cx,
2080 listener: TcpListener,
2081 app: Arc<App>,
2082 ) -> Result<(), ServerError> {
2083 self.accept_loop_app_concurrent(cx, listener, app).await
2084 }
2085
2086 async fn accept_loop_app(
2087 &self,
2088 cx: &Cx,
2089 listener: TcpListener,
2090 app: Arc<App>,
2091 ) -> Result<(), ServerError> {
2092 loop {
2093 if cx.is_cancel_requested() {
2094 cx.trace("Server shutdown requested");
2095 return Ok(());
2096 }
2097 if self.is_draining() {
2098 cx.trace("Server draining, stopping accept loop");
2099 return Err(ServerError::Shutdown);
2100 }
2101
2102 let (mut stream, peer_addr) = match listener.accept().await {
2103 Ok(conn) => conn,
2104 Err(e) if e.kind() == io::ErrorKind::WouldBlock => continue,
2105 Err(e) => {
2106 cx.trace(&format!("Accept error: {e}"));
2107 if is_fatal_accept_error(&e) {
2108 return Err(ServerError::Io(e));
2109 }
2110 continue;
2111 }
2112 };
2113
2114 if !self.try_acquire_connection() {
2115 cx.trace(&format!(
2116 "Connection limit reached ({}), rejecting {peer_addr}",
2117 self.config.max_connections
2118 ));
2119
2120 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
2121 .header("connection", b"close".to_vec())
2122 .body(fastapi_core::ResponseBody::Bytes(
2123 b"503 Service Unavailable: connection limit reached".to_vec(),
2124 ));
2125 let mut writer = crate::response::ResponseWriter::new();
2126 let response_bytes = writer.write(response);
2127 let _ = write_response(&mut stream, response_bytes).await;
2128 continue;
2129 }
2130
2131 if self.config.tcp_nodelay {
2132 let _ = stream.set_nodelay(true);
2133 }
2134
2135 cx.trace(&format!(
2136 "Accepted connection from {peer_addr} ({}/{})",
2137 self.current_connections(),
2138 if self.config.max_connections == 0 {
2139 "∞".to_string()
2140 } else {
2141 self.config.max_connections.to_string()
2142 }
2143 ));
2144
2145 let result = self
2146 .handle_connection_app(cx, stream, peer_addr, app.as_ref())
2147 .await;
2148
2149 self.release_connection();
2150
2151 if let Err(e) = result {
2152 cx.trace(&format!("Connection error from {peer_addr}: {e}"));
2153 }
2154 }
2155 }
2156
2157 async fn accept_loop_app_concurrent(
2158 &self,
2159 cx: &Cx,
2160 listener: TcpListener,
2161 app: Arc<App>,
2162 ) -> Result<(), ServerError> {
2163 let runtime_handle = Runtime::current_handle()
2164 .expect("serve_app_concurrent must be called inside an asupersync runtime");
2165 let accept_poll_interval = Duration::from_millis(50);
2166
2167 loop {
2168 self.cleanup_completed_handles(cx).await;
2169
2170 if cx.is_cancel_requested() || self.is_draining() {
2171 cx.trace("Server shutting down, draining app connections");
2172 self.drain_connection_tasks(cx).await;
2173 return Ok(());
2174 }
2175
2176 let accept_future = Box::pin(listener.accept());
2177 let (mut stream, peer_addr) =
2178 match timeout(current_time(), accept_poll_interval, accept_future).await {
2179 Ok(Ok(conn)) => conn,
2180 Ok(Err(e)) if e.kind() == io::ErrorKind::WouldBlock => continue,
2181 Ok(Err(e)) => {
2182 cx.trace(&format!("Accept error: {e}"));
2183 if is_fatal_accept_error(&e) {
2184 return Err(ServerError::Io(e));
2185 }
2186 continue;
2187 }
2188 Err(_elapsed) => continue,
2189 };
2190
2191 if !self.try_acquire_connection() {
2192 cx.trace(&format!(
2193 "Connection limit reached ({}), rejecting {peer_addr}",
2194 self.config.max_connections
2195 ));
2196
2197 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
2198 .header("connection", b"close".to_vec())
2199 .body(fastapi_core::ResponseBody::Bytes(
2200 b"503 Service Unavailable: connection limit reached".to_vec(),
2201 ));
2202 let mut writer = crate::response::ResponseWriter::new();
2203 let response_bytes = writer.write(response);
2204 let _ = write_response(&mut stream, response_bytes).await;
2205 continue;
2206 }
2207
2208 if self.config.tcp_nodelay {
2209 let _ = stream.set_nodelay(true);
2210 }
2211
2212 cx.trace(&format!(
2213 "Accepted connection from {peer_addr} ({}/{})",
2214 self.current_connections(),
2215 if self.config.max_connections == 0 {
2216 "∞".to_string()
2217 } else {
2218 self.config.max_connections.to_string()
2219 }
2220 ));
2221
2222 match self.spawn_connection_app_task(
2223 &runtime_handle,
2224 cx,
2225 stream,
2226 peer_addr,
2227 Arc::clone(&app),
2228 ) {
2229 Ok(handle) => {
2230 if let Ok(mut handles) = self.connection_handles.lock() {
2231 handles.push(handle);
2232 }
2233 self.cleanup_completed_handles(cx).await;
2234 }
2235 Err(e) => {
2236 cx.trace(&format!("Failed to spawn app connection task: {e:?}"));
2237 }
2238 }
2239 }
2240 }
2241
2242 async fn accept_loop_handler(
2244 &self,
2245 cx: &Cx,
2246 listener: TcpListener,
2247 handler: Arc<dyn fastapi_core::Handler>,
2248 ) -> Result<(), ServerError> {
2249 loop {
2250 if cx.is_cancel_requested() {
2252 cx.trace("Server shutdown requested");
2253 return Ok(());
2254 }
2255
2256 if self.is_draining() {
2258 cx.trace("Server draining, stopping accept loop");
2259 return Err(ServerError::Shutdown);
2260 }
2261
2262 let (mut stream, peer_addr) = match listener.accept().await {
2264 Ok(conn) => conn,
2265 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
2266 continue;
2267 }
2268 Err(e) => {
2269 cx.trace(&format!("Accept error: {e}"));
2270 if is_fatal_accept_error(&e) {
2271 return Err(ServerError::Io(e));
2272 }
2273 continue;
2274 }
2275 };
2276
2277 if !self.try_acquire_connection() {
2279 cx.trace(&format!(
2280 "Connection limit reached ({}), rejecting {peer_addr}",
2281 self.config.max_connections
2282 ));
2283
2284 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
2285 .header("connection", b"close".to_vec())
2286 .body(fastapi_core::ResponseBody::Bytes(
2287 b"503 Service Unavailable: connection limit reached".to_vec(),
2288 ));
2289 let mut writer = crate::response::ResponseWriter::new();
2290 let response_bytes = writer.write(response);
2291 let _ = write_response(&mut stream, response_bytes).await;
2292 continue;
2293 }
2294
2295 if self.config.tcp_nodelay {
2297 let _ = stream.set_nodelay(true);
2298 }
2299
2300 cx.trace(&format!(
2301 "Accepted connection from {peer_addr} ({}/{})",
2302 self.current_connections(),
2303 if self.config.max_connections == 0 {
2304 "∞".to_string()
2305 } else {
2306 self.config.max_connections.to_string()
2307 }
2308 ));
2309
2310 let result = self
2312 .handle_connection_handler(cx, stream, peer_addr, &*handler)
2313 .await;
2314
2315 self.release_connection();
2316
2317 if let Err(e) = result {
2318 cx.trace(&format!("Connection error from {peer_addr}: {e}"));
2319 }
2320 }
2321 }
2322
2323 #[allow(clippy::too_many_lines)]
2339 pub async fn serve_concurrent<H, Fut>(&self, cx: &Cx, handler: H) -> Result<(), ServerError>
2340 where
2341 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
2342 Fut: Future<Output = Response> + Send + 'static,
2343 {
2344 let bind_addr = self.config.bind_addr.clone();
2345 let listener = TcpListener::bind(bind_addr).await?;
2346 let local_addr = listener.local_addr()?;
2347
2348 cx.trace(&format!(
2349 "Server listening on {local_addr} (concurrent mode)"
2350 ));
2351
2352 let handler = Arc::new(handler);
2353
2354 self.accept_loop_concurrent(cx, listener, handler).await
2355 }
2356
2357 async fn accept_loop_concurrent<H, Fut>(
2359 &self,
2360 cx: &Cx,
2361 listener: TcpListener,
2362 handler: Arc<H>,
2363 ) -> Result<(), ServerError>
2364 where
2365 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
2366 Fut: Future<Output = Response> + Send + 'static,
2367 {
2368 let runtime_handle = Runtime::current_handle()
2369 .expect("serve_concurrent must be called inside an asupersync runtime");
2370 let accept_poll_interval = Duration::from_millis(50);
2371
2372 loop {
2373 self.cleanup_completed_handles(cx).await;
2374
2375 if cx.is_cancel_requested() || self.is_draining() {
2377 cx.trace("Server shutting down, draining connections");
2378 self.drain_connection_tasks(cx).await;
2379 return Ok(());
2380 }
2381
2382 let accept_future = Box::pin(listener.accept());
2385 let (mut stream, peer_addr) =
2386 match timeout(current_time(), accept_poll_interval, accept_future).await {
2387 Ok(Ok(conn)) => conn,
2388 Ok(Err(e)) if e.kind() == io::ErrorKind::WouldBlock => {
2389 continue;
2390 }
2391 Ok(Err(e)) => {
2392 cx.trace(&format!("Accept error: {e}"));
2393 if is_fatal_accept_error(&e) {
2394 return Err(ServerError::Io(e));
2395 }
2396 continue;
2397 }
2398 Err(_elapsed) => continue,
2399 };
2400
2401 if !self.try_acquire_connection() {
2403 cx.trace(&format!(
2404 "Connection limit reached ({}), rejecting {peer_addr}",
2405 self.config.max_connections
2406 ));
2407
2408 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
2409 .header("connection", b"close".to_vec())
2410 .body(fastapi_core::ResponseBody::Bytes(
2411 b"503 Service Unavailable: connection limit reached".to_vec(),
2412 ));
2413 let mut writer = crate::response::ResponseWriter::new();
2414 let response_bytes = writer.write(response);
2415 let _ = write_response(&mut stream, response_bytes).await;
2416 continue;
2417 }
2418
2419 if self.config.tcp_nodelay {
2421 let _ = stream.set_nodelay(true);
2422 }
2423
2424 cx.trace(&format!(
2425 "Accepted connection from {peer_addr} ({}/{})",
2426 self.current_connections(),
2427 if self.config.max_connections == 0 {
2428 "∞".to_string()
2429 } else {
2430 self.config.max_connections.to_string()
2431 }
2432 ));
2433
2434 match self.spawn_connection_task(
2436 &runtime_handle,
2437 cx,
2438 stream,
2439 peer_addr,
2440 Arc::clone(&handler),
2441 ) {
2442 Ok(handle) => {
2443 if let Ok(mut handles) = self.connection_handles.lock() {
2445 handles.push(handle);
2446 }
2447 self.cleanup_completed_handles(cx).await;
2449 }
2450 Err(e) => {
2451 cx.trace(&format!("Failed to spawn connection task: {e:?}"));
2452 }
2453 }
2454 }
2455 }
2456
2457 fn spawn_connection_task<H, Fut>(
2462 &self,
2463 handle: &RuntimeHandle,
2464 cx: &Cx,
2465 stream: TcpStream,
2466 peer_addr: SocketAddr,
2467 handler: Arc<H>,
2468 ) -> Result<JoinHandle<()>, SpawnError>
2469 where
2470 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
2471 Fut: Future<Output = Response> + Send + 'static,
2472 {
2473 let config = self.config.clone();
2474 let connection_cx = cx.clone();
2475 let request_counter = Arc::clone(&self.request_counter);
2476 let connection_counter = Arc::clone(&self.connection_counter);
2477 let connection_slot = ConnectionSlotGuard::new(connection_counter);
2478
2479 handle.try_spawn(async move {
2480 let _connection_slot = connection_slot;
2481 let result = process_connection(
2482 &connection_cx,
2483 &request_counter,
2484 stream,
2485 peer_addr,
2486 &config,
2487 |ctx, req| handler(ctx, req),
2488 )
2489 .await;
2490
2491 if let Err(e) = result {
2492 eprintln!("Connection error from {peer_addr}: {e}");
2494 }
2495 })
2496 }
2497
2498 fn spawn_connection_app_task(
2499 &self,
2500 handle: &RuntimeHandle,
2501 cx: &Cx,
2502 stream: TcpStream,
2503 peer_addr: SocketAddr,
2504 app: Arc<App>,
2505 ) -> Result<JoinHandle<()>, SpawnError> {
2506 let server = self.clone_for_connection_task();
2507 let connection_cx = cx.clone();
2508 let connection_counter = Arc::clone(&self.connection_counter);
2509 let connection_slot = ConnectionSlotGuard::new(connection_counter);
2510
2511 handle.try_spawn(async move {
2512 let _connection_slot = connection_slot;
2513 let result = server
2514 .handle_connection_app(&connection_cx, stream, peer_addr, app.as_ref())
2515 .await;
2516
2517 if let Err(e) = result {
2518 eprintln!("Connection error from {peer_addr}: {e}");
2519 }
2520 })
2521 }
2522
2523 fn take_finished_connection_handles(&self) -> Vec<JoinHandle<()>> {
2524 if let Ok(mut handles) = self.connection_handles.lock() {
2525 let mut finished = Vec::new();
2526 let mut idx = 0;
2527 while idx < handles.len() {
2528 if handles[idx].is_finished() {
2529 finished.push(handles.swap_remove(idx));
2530 } else {
2531 idx += 1;
2532 }
2533 }
2534 finished
2535 } else {
2536 Vec::new()
2537 }
2538 }
2539
2540 async fn cleanup_completed_handles(&self, cx: &Cx) {
2542 for handle in self.take_finished_connection_handles() {
2543 if let Err(payload) = CatchUnwind::new(handle).await {
2544 let message = panic_payload_message(payload.as_ref());
2545 cx.trace(&format!("Connection task panicked: {message}"));
2546 eprintln!("Connection task panicked: {message}");
2547 }
2548 }
2549 }
2550
2551 async fn drain_connection_tasks(&self, cx: &Cx) {
2553 let drain_timeout = self.config.drain_timeout;
2554 let start = Instant::now();
2555
2556 cx.trace(&format!(
2557 "Draining {} connection tasks (timeout: {:?})",
2558 self.connection_handles.lock().map_or(0, |h| h.len()),
2559 drain_timeout
2560 ));
2561
2562 while start.elapsed() < drain_timeout {
2564 self.cleanup_completed_handles(cx).await;
2565
2566 let remaining = self
2567 .connection_handles
2568 .lock()
2569 .map_or(0, |h| h.iter().filter(|t| !t.is_finished()).count());
2570
2571 if remaining == 0 {
2572 self.cleanup_completed_handles(cx).await;
2573 cx.trace("All connection tasks drained successfully");
2574 return;
2575 }
2576
2577 asupersync::runtime::yield_now().await;
2579 }
2580
2581 self.cleanup_completed_handles(cx).await;
2582 cx.trace(&format!(
2583 "Drain timeout reached with {} tasks still running; lingering connection tasks will continue in the background",
2584 self.connection_handles
2585 .lock()
2586 .map_or(0, |h| h.iter().filter(|t| !t.is_finished()).count())
2587 ));
2588 }
2589
2590 async fn handle_connection_app(
2591 &self,
2592 cx: &Cx,
2593 mut stream: TcpStream,
2594 peer_addr: SocketAddr,
2595 app: &App,
2596 ) -> Result<(), ServerError> {
2597 let (proto, buffered) = sniff_protocol(&mut stream, self.config.keep_alive_timeout).await?;
2598 if !buffered.is_empty() {
2599 self.record_bytes_in(buffered.len() as u64);
2600 }
2601
2602 if proto == SniffedProtocol::Http2PriorKnowledge {
2603 return self
2604 .handle_connection_app_http2(cx, stream, peer_addr, app)
2605 .await;
2606 }
2607
2608 let mut parser = StatefulParser::new().with_limits(self.config.parse_limits.clone());
2609 if !buffered.is_empty() {
2610 parser.feed(&buffered)?;
2611 }
2612 let mut read_buffer = vec![0u8; self.config.read_buffer_size];
2613 let mut response_writer = ResponseWriter::new();
2614 let mut requests_on_connection: usize = 0;
2615 let max_requests = self.config.max_requests_per_connection;
2616
2617 loop {
2618 if cx.is_cancel_requested() {
2619 return Ok(());
2620 }
2621
2622 let parse_result = parser.feed(&[])?;
2623 let mut request = match parse_result {
2624 ParseStatus::Complete { request, .. } => request,
2625 ParseStatus::Incomplete => {
2626 let keep_alive_timeout = self.config.keep_alive_timeout;
2627 let bytes_read = if keep_alive_timeout.is_zero() {
2628 read_into_buffer(&mut stream, &mut read_buffer).await?
2629 } else {
2630 match read_with_timeout(&mut stream, &mut read_buffer, keep_alive_timeout)
2631 .await
2632 {
2633 Ok(0) => return Ok(()),
2634 Ok(n) => n,
2635 Err(e) if e.kind() == io::ErrorKind::TimedOut => {
2636 self.metrics_counters
2637 .total_timed_out
2638 .fetch_add(1, Ordering::Relaxed);
2639 return Err(ServerError::KeepAliveTimeout);
2640 }
2641 Err(e) => return Err(ServerError::Io(e)),
2642 }
2643 };
2644
2645 if bytes_read == 0 {
2646 return Ok(());
2647 }
2648
2649 self.record_bytes_in(bytes_read as u64);
2650
2651 match parser.feed(&read_buffer[..bytes_read])? {
2652 ParseStatus::Complete { request, .. } => request,
2653 ParseStatus::Incomplete => continue,
2654 }
2655 }
2656 };
2657
2658 requests_on_connection += 1;
2659
2660 let request_id = self.request_counter.fetch_add(1, Ordering::Relaxed);
2661
2662 let deadline = request_deadline_at(cx.now(), self.config.request_timeout);
2664 let request_budget = Budget::new().with_deadline(deadline);
2665 let request_cx = request_cx_from_parent(cx, request_budget);
2666 let overrides = app.dependency_overrides();
2667 let ctx = RequestContext::with_overrides_and_body_limit(
2668 request_cx,
2669 request_id,
2670 overrides,
2671 app.config().max_body_size,
2672 )
2673 .with_deadline(deadline);
2674
2675 if let Err(err) = validate_host_header(&request, &self.config) {
2677 ctx.trace(&format!(
2678 "Rejecting request from {peer_addr}: {}",
2679 err.detail
2680 ));
2681 let response = err.response().header("connection", b"close".to_vec());
2682 let response_write = response_writer.write(response);
2683 write_response(&mut stream, response_write).await?;
2684 return Ok(());
2685 }
2686
2687 if let Err(response) = self.config.pre_body_validators.validate_all(&request) {
2689 let response = response.header("connection", b"close".to_vec());
2690 let response_write = response_writer.write(response);
2691 write_response(&mut stream, response_write).await?;
2692 return Ok(());
2693 }
2694
2695 if is_websocket_upgrade_request(&request)
2700 && app.websocket_route_count() > 0
2701 && app.has_websocket_route(request.path())
2702 {
2703 if has_request_body_headers(&request) {
2705 let response = Response::with_status(StatusCode::BAD_REQUEST)
2706 .header("connection", b"close".to_vec())
2707 .body(fastapi_core::ResponseBody::Bytes(
2708 b"Bad Request: websocket handshake must not include a body".to_vec(),
2709 ));
2710 let response_write = response_writer.write(response);
2711 write_response(&mut stream, response_write).await?;
2712 return Ok(());
2713 }
2714
2715 let Some(key) = header_str(&request, "sec-websocket-key") else {
2716 let response = Response::with_status(StatusCode::BAD_REQUEST)
2717 .header("connection", b"close".to_vec())
2718 .body(fastapi_core::ResponseBody::Bytes(
2719 b"Bad Request: missing Sec-WebSocket-Key".to_vec(),
2720 ));
2721 let response_write = response_writer.write(response);
2722 write_response(&mut stream, response_write).await?;
2723 return Ok(());
2724 };
2725 let accept = match fastapi_core::websocket_accept_from_key(key) {
2726 Ok(v) => v,
2727 Err(_) => {
2728 let response = Response::with_status(StatusCode::BAD_REQUEST)
2729 .header("connection", b"close".to_vec())
2730 .body(fastapi_core::ResponseBody::Bytes(
2731 b"Bad Request: invalid Sec-WebSocket-Key".to_vec(),
2732 ));
2733 let response_write = response_writer.write(response);
2734 write_response(&mut stream, response_write).await?;
2735 return Ok(());
2736 }
2737 };
2738
2739 if header_str(&request, "sec-websocket-version") != Some("13") {
2740 let response = Response::with_status(StatusCode::BAD_REQUEST)
2741 .header("sec-websocket-version", b"13".to_vec())
2742 .header("connection", b"close".to_vec())
2743 .body(fastapi_core::ResponseBody::Bytes(
2744 b"Bad Request: unsupported Sec-WebSocket-Version".to_vec(),
2745 ));
2746 let response_write = response_writer.write(response);
2747 write_response(&mut stream, response_write).await?;
2748 return Ok(());
2749 }
2750
2751 let response = Response::with_status(StatusCode::SWITCHING_PROTOCOLS)
2752 .header("upgrade", b"websocket".to_vec())
2753 .header("connection", b"Upgrade".to_vec())
2754 .header("sec-websocket-accept", accept.into_bytes());
2755 let response_write = response_writer.write(response);
2756 if let ResponseWrite::Full(ref bytes) = response_write {
2757 self.record_bytes_out(bytes.len() as u64);
2758 }
2759 write_response(&mut stream, response_write).await?;
2760
2761 let buffered = parser.take_buffered();
2763
2764 let ws_root_cx = request_cx_from_parent(cx, Budget::new());
2766 let ws_ctx = RequestContext::with_overrides_and_body_limit(
2767 ws_root_cx,
2768 request_id,
2769 app.dependency_overrides(),
2770 app.config().max_body_size,
2771 );
2772
2773 let ws = fastapi_core::WebSocket::new(stream, buffered);
2774 let _ = app.handle_websocket(&ws_ctx, &mut request, ws).await;
2775 return Ok(());
2776 }
2777
2778 match ExpectHandler::check_expect(&request) {
2780 ExpectResult::NoExpectation => {}
2781 ExpectResult::ExpectsContinue => {
2782 ctx.trace("Sending 100 Continue for Expect: 100-continue");
2783 write_raw_response(&mut stream, CONTINUE_RESPONSE).await?;
2784 }
2785 ExpectResult::UnknownExpectation(value) => {
2786 ctx.trace(&format!("Rejecting unknown Expect value: {}", value));
2787 let response = ExpectHandler::expectation_failed(format!(
2788 "Unsupported Expect value: {value}"
2789 ));
2790 let response_write = response_writer.write(response);
2791 write_response(&mut stream, response_write).await?;
2792 return Ok(());
2793 }
2794 }
2795
2796 let client_wants_keep_alive = should_keep_alive(&request);
2797 let mut server_will_keep_alive = client_wants_keep_alive
2798 && (max_requests == 0 || requests_on_connection < max_requests);
2799
2800 let mut response = match timeout_at(deadline, app.handle(&ctx, &mut request)).await {
2811 Ok(response) => response,
2812 Err(_elapsed) => {
2813 server_will_keep_alive = false;
2816 Response::with_status(StatusCode::GATEWAY_TIMEOUT).body(
2817 fastapi_core::ResponseBody::Bytes(
2818 b"Gateway Timeout: request processing exceeded time limit".to_vec(),
2819 ),
2820 )
2821 }
2822 };
2823
2824 response = if server_will_keep_alive {
2825 response.header("connection", b"keep-alive".to_vec())
2826 } else {
2827 response.header("connection", b"close".to_vec())
2828 };
2829
2830 let response_write = response_writer.write(response);
2831 if let ResponseWrite::Full(ref bytes) = response_write {
2832 self.record_bytes_out(bytes.len() as u64);
2833 }
2834 write_response(&mut stream, response_write).await?;
2835
2836 if let Some(tasks) = App::take_background_tasks(&mut request) {
2837 tasks.execute_all().await;
2838 }
2839
2840 if !server_will_keep_alive {
2841 return Ok(());
2842 }
2843 }
2844 }
2845
2846 async fn handle_connection_app_http2(
2847 &self,
2848 cx: &Cx,
2849 stream: TcpStream,
2850 _peer_addr: SocketAddr,
2851 app: &App,
2852 ) -> Result<(), ServerError> {
2853 const FLAG_END_STREAM: u8 = 0x1;
2854 const FLAG_END_HEADERS: u8 = 0x4;
2855 const FLAG_ACK: u8 = 0x1;
2856
2857 let mut framed = http2::FramedH2::new(stream, Vec::new());
2858 let mut hpack = http2::HpackDecoder::new();
2859 let recv_max_frame_size: u32 = 16 * 1024; let mut peer_max_frame_size: u32 = 16 * 1024;
2861 let mut flow_control = http2::H2FlowControl::new();
2862
2863 let first = framed.read_frame(recv_max_frame_size).await?;
2864 self.record_bytes_in((http2::FrameHeader::LEN + first.payload.len()) as u64);
2865
2866 if first.header.frame_type() != http2::FrameType::Settings
2867 || first.header.stream_id != 0
2868 || (first.header.flags & FLAG_ACK) != 0
2869 {
2870 return Err(
2871 http2::Http2Error::Protocol("expected client SETTINGS after preface").into(),
2872 );
2873 }
2874
2875 apply_http2_settings_with_fc(
2876 &mut hpack,
2877 &mut peer_max_frame_size,
2878 Some(&mut flow_control),
2879 &first.payload,
2880 )?;
2881
2882 framed
2884 .write_frame(http2::FrameType::Settings, 0, 0, SERVER_SETTINGS_PAYLOAD)
2885 .await?;
2886 self.record_bytes_out(http2::FrameHeader::LEN as u64);
2887
2888 framed
2889 .write_frame(http2::FrameType::Settings, FLAG_ACK, 0, &[])
2890 .await?;
2891 self.record_bytes_out(http2::FrameHeader::LEN as u64);
2892 let mut last_stream_id: u32 = 0;
2893
2894 loop {
2895 if cx.is_cancel_requested() {
2896 let _ = send_goaway(&mut framed, last_stream_id, h2_error_code::NO_ERROR).await;
2897 return Ok(());
2898 }
2899
2900 let frame = framed.read_frame(recv_max_frame_size).await?;
2901 self.record_bytes_in((http2::FrameHeader::LEN + frame.payload.len()) as u64);
2902
2903 match frame.header.frame_type() {
2904 http2::FrameType::Settings => {
2905 let is_ack = validate_settings_frame(
2906 frame.header.stream_id,
2907 frame.header.flags,
2908 &frame.payload,
2909 )?;
2910 if is_ack {
2911 continue;
2913 }
2914 apply_http2_settings_with_fc(
2915 &mut hpack,
2916 &mut peer_max_frame_size,
2917 Some(&mut flow_control),
2918 &frame.payload,
2919 )?;
2920 framed
2922 .write_frame(http2::FrameType::Settings, FLAG_ACK, 0, &[])
2923 .await?;
2924 self.record_bytes_out(http2::FrameHeader::LEN as u64);
2925 }
2926 http2::FrameType::Ping => {
2927 if frame.header.stream_id != 0 || frame.payload.len() != 8 {
2929 return Err(http2::Http2Error::Protocol("invalid PING frame").into());
2930 }
2931 if (frame.header.flags & FLAG_ACK) == 0 {
2932 framed
2933 .write_frame(http2::FrameType::Ping, FLAG_ACK, 0, &frame.payload)
2934 .await?;
2935 self.record_bytes_out((http2::FrameHeader::LEN + 8) as u64);
2936 }
2937 }
2938 http2::FrameType::Goaway => {
2939 validate_goaway_payload(&frame.payload)?;
2940 return Ok(());
2941 }
2942 http2::FrameType::PushPromise => {
2943 return Err(http2::Http2Error::Protocol(
2944 "PUSH_PROMISE not supported by server",
2945 )
2946 .into());
2947 }
2948 http2::FrameType::Headers => {
2949 let stream_id = frame.header.stream_id;
2950 if stream_id == 0 {
2951 return Err(
2952 http2::Http2Error::Protocol("HEADERS must not be on stream 0").into(),
2953 );
2954 }
2955 if stream_id % 2 == 0 {
2956 return Err(http2::Http2Error::Protocol(
2957 "client-initiated stream ID must be odd",
2958 )
2959 .into());
2960 }
2961 if stream_id <= last_stream_id {
2962 return Err(http2::Http2Error::Protocol(
2963 "stream ID must be greater than previous",
2964 )
2965 .into());
2966 }
2967 last_stream_id = stream_id;
2968 let (end_stream, mut header_block) =
2969 extract_header_block_fragment(frame.header.flags, &frame.payload)?;
2970
2971 if (frame.header.flags & FLAG_END_HEADERS) == 0 {
2973 loop {
2974 let cont = framed.read_frame(recv_max_frame_size).await?;
2975 self.record_bytes_in(
2976 (http2::FrameHeader::LEN + cont.payload.len()) as u64,
2977 );
2978 if cont.header.frame_type() != http2::FrameType::Continuation
2979 || cont.header.stream_id != stream_id
2980 {
2981 return Err(http2::Http2Error::Protocol(
2982 "expected CONTINUATION for header block",
2983 )
2984 .into());
2985 }
2986 header_block.extend_from_slice(&cont.payload);
2987 if header_block.len() > MAX_HEADER_BLOCK_SIZE {
2988 return Err(http2::Http2Error::Protocol(
2989 "header block exceeds maximum size",
2990 )
2991 .into());
2992 }
2993 if (cont.header.flags & FLAG_END_HEADERS) != 0 {
2994 break;
2995 }
2996 }
2997 }
2998
2999 let headers = hpack
3000 .decode(&header_block)
3001 .map_err(http2::Http2Error::from)?;
3002 let mut request = request_from_h2_headers(headers)?;
3003 request.set_version(fastapi_core::HttpVersion::Http2);
3004
3005 if !end_stream {
3007 let max = app.config().max_body_size;
3008 let mut body = Vec::new();
3009 let mut stream_reset = false;
3010 let mut stream_received: u32 = 0;
3011 loop {
3012 let f = framed.read_frame(recv_max_frame_size).await?;
3013 self.record_bytes_in(
3014 (http2::FrameHeader::LEN + f.payload.len()) as u64,
3015 );
3016 match f.header.frame_type() {
3017 http2::FrameType::Data if f.header.stream_id == 0 => {
3018 return Err(http2::Http2Error::Protocol(
3019 "DATA must not be on stream 0",
3020 )
3021 .into());
3022 }
3023 http2::FrameType::Data if f.header.stream_id == stream_id => {
3024 let (data, data_end_stream) =
3025 extract_data_payload(f.header.flags, &f.payload)?;
3026 if body.len().saturating_add(data.len()) > max {
3027 return Err(http2::Http2Error::Protocol(
3028 "request body exceeds configured max_body_size",
3029 )
3030 .into());
3031 }
3032 body.extend_from_slice(data);
3033
3034 let data_len = u32::try_from(data.len()).unwrap_or(u32::MAX);
3037 stream_received += data_len;
3038 let conn_inc = flow_control.data_received_connection(data_len);
3039 let stream_inc =
3040 flow_control.stream_window_update(stream_received);
3041 if stream_inc > 0 {
3042 stream_received = 0;
3043 }
3044 send_window_updates(
3045 &mut framed,
3046 conn_inc,
3047 stream_id,
3048 stream_inc,
3049 )
3050 .await?;
3051
3052 if data_end_stream {
3053 break;
3054 }
3055 }
3056 http2::FrameType::RstStream => {
3057 validate_rst_stream_payload(f.header.stream_id, &f.payload)?;
3058 if f.header.stream_id == stream_id {
3059 stream_reset = true;
3060 break;
3061 }
3062 }
3063 http2::FrameType::PushPromise => {
3064 return Err(http2::Http2Error::Protocol(
3065 "PUSH_PROMISE not supported by server",
3066 )
3067 .into());
3068 }
3069 http2::FrameType::Settings
3070 | http2::FrameType::Ping
3071 | http2::FrameType::Goaway
3072 | http2::FrameType::WindowUpdate
3073 | http2::FrameType::Priority
3074 | http2::FrameType::Unknown => {
3075 if f.header.frame_type() == http2::FrameType::Goaway {
3076 validate_goaway_payload(&f.payload)?;
3077 return Ok(());
3078 }
3079 if f.header.frame_type() == http2::FrameType::Priority {
3080 validate_priority_payload(f.header.stream_id, &f.payload)?;
3081 }
3082 if f.header.frame_type() == http2::FrameType::WindowUpdate {
3083 validate_window_update_payload(&f.payload)?;
3084 let increment = u32::from_be_bytes([
3085 f.payload[0],
3086 f.payload[1],
3087 f.payload[2],
3088 f.payload[3],
3089 ]) & 0x7FFF_FFFF;
3090 if f.header.stream_id == 0 {
3091 apply_send_conn_window_update(
3092 &mut flow_control,
3093 increment,
3094 )?;
3095 }
3096 }
3097 if f.header.frame_type() == http2::FrameType::Ping {
3098 if f.header.stream_id != 0 || f.payload.len() != 8 {
3099 return Err(http2::Http2Error::Protocol(
3100 "invalid PING frame",
3101 )
3102 .into());
3103 }
3104 if (f.header.flags & FLAG_ACK) == 0 {
3105 framed
3106 .write_frame(
3107 http2::FrameType::Ping,
3108 FLAG_ACK,
3109 0,
3110 &f.payload,
3111 )
3112 .await?;
3113 self.record_bytes_out(
3114 (http2::FrameHeader::LEN + 8) as u64,
3115 );
3116 }
3117 }
3118 if f.header.frame_type() == http2::FrameType::Settings {
3119 let is_ack = validate_settings_frame(
3120 f.header.stream_id,
3121 f.header.flags,
3122 &f.payload,
3123 )?;
3124 if !is_ack {
3125 apply_http2_settings_with_fc(
3126 &mut hpack,
3127 &mut peer_max_frame_size,
3128 Some(&mut flow_control),
3129 &f.payload,
3130 )?;
3131 framed
3132 .write_frame(
3133 http2::FrameType::Settings,
3134 FLAG_ACK,
3135 0,
3136 &[],
3137 )
3138 .await?;
3139 self.record_bytes_out(http2::FrameHeader::LEN as u64);
3140 }
3141 }
3142 }
3143 _ => {
3144 return Err(http2::Http2Error::Protocol(
3145 "unsupported frame while reading request body",
3146 )
3147 .into());
3148 }
3149 }
3150 }
3151 if stream_reset {
3152 continue;
3153 }
3154 request.set_body(fastapi_core::Body::Bytes(body));
3155 }
3156
3157 let request_id = self.request_counter.fetch_add(1, Ordering::Relaxed);
3158 let request_budget =
3159 Budget::new().with_deadline(request_deadline(self.config.request_timeout));
3160 let request_cx = request_cx_from_parent(cx, request_budget);
3161 let overrides = app.dependency_overrides();
3162 let ctx = RequestContext::with_overrides_and_body_limit(
3163 request_cx,
3164 request_id,
3165 overrides,
3166 app.config().max_body_size,
3167 );
3168
3169 if let Err(err) = validate_host_header(&request, &self.config) {
3170 ctx.trace(&format!("Rejecting HTTP/2 request: {}", err.detail));
3171 let response = err.response();
3172 self.write_h2_response(
3173 &mut framed,
3174 response,
3175 stream_id,
3176 peer_max_frame_size,
3177 recv_max_frame_size,
3178 Some(&mut flow_control),
3179 )
3180 .await?;
3181 continue;
3182 }
3183
3184 if let Err(response) = self.config.pre_body_validators.validate_all(&request) {
3185 self.write_h2_response(
3186 &mut framed,
3187 response,
3188 stream_id,
3189 peer_max_frame_size,
3190 recv_max_frame_size,
3191 Some(&mut flow_control),
3192 )
3193 .await?;
3194 continue;
3195 }
3196
3197 let response = app.handle(&ctx, &mut request).await;
3198
3199 self.write_h2_response(
3201 &mut framed,
3202 response,
3203 stream_id,
3204 peer_max_frame_size,
3205 recv_max_frame_size,
3206 Some(&mut flow_control),
3207 )
3208 .await?;
3209
3210 if let Some(tasks) = App::take_background_tasks(&mut request) {
3211 tasks.execute_all().await;
3212 }
3213
3214 asupersync::runtime::yield_now().await;
3216 }
3217 http2::FrameType::WindowUpdate => {
3218 validate_window_update_payload(&frame.payload)?;
3219 let increment = u32::from_be_bytes([
3220 frame.payload[0],
3221 frame.payload[1],
3222 frame.payload[2],
3223 frame.payload[3],
3224 ]) & 0x7FFF_FFFF;
3225 if frame.header.stream_id == 0 {
3226 apply_send_conn_window_update(&mut flow_control, increment)?;
3227 }
3228 }
3229 _ => {
3230 handle_h2_idle_frame(&frame)?;
3231 }
3232 }
3233 }
3234 }
3235
3236 async fn write_h2_response(
3237 &self,
3238 framed: &mut http2::FramedH2,
3239 response: Response,
3240 stream_id: u32,
3241 mut peer_max_frame_size: u32,
3242 recv_max_frame_size: u32,
3243 mut flow_control: Option<&mut http2::H2FlowControl>,
3244 ) -> Result<(), ServerError> {
3245 use std::future::poll_fn;
3246
3247 const FLAG_END_STREAM: u8 = 0x1;
3248 const FLAG_END_HEADERS: u8 = 0x4;
3249
3250 let (status, mut headers, mut body) = response.into_parts();
3251 if !status.allows_body() {
3252 body = fastapi_core::ResponseBody::Empty;
3253 }
3254
3255 let mut add_content_length = matches!(body, fastapi_core::ResponseBody::Bytes(_));
3256 for (name, _) in &headers {
3257 if name.eq_ignore_ascii_case("content-length") {
3258 add_content_length = false;
3259 break;
3260 }
3261 }
3262
3263 if add_content_length {
3264 let len = body.len();
3265 headers.push(("content-length".to_string(), len.to_string().into_bytes()));
3266 }
3267
3268 let mut block: Vec<u8> = Vec::new();
3270 let status_bytes = status.as_u16().to_string().into_bytes();
3271 http2::hpack_encode_literal_without_indexing(&mut block, b":status", &status_bytes);
3272
3273 for (name, value) in &headers {
3274 if is_h2_forbidden_header_name(name) {
3275 continue;
3276 }
3277 let n = name.to_ascii_lowercase();
3278 http2::hpack_encode_literal_without_indexing(&mut block, n.as_bytes(), value);
3279 }
3280
3281 let max = usize::try_from(peer_max_frame_size).unwrap_or(16 * 1024);
3283 if block.len() <= max {
3284 let mut flags = FLAG_END_HEADERS;
3285 if body.is_empty() {
3286 flags |= FLAG_END_STREAM;
3287 }
3288 framed
3289 .write_frame(http2::FrameType::Headers, flags, stream_id, &block)
3290 .await?;
3291 self.record_bytes_out((http2::FrameHeader::LEN + block.len()) as u64);
3292 } else {
3293 let mut flags = 0u8;
3294 if body.is_empty() {
3295 flags |= FLAG_END_STREAM;
3296 }
3297 let (first, rest) = block.split_at(max);
3298 framed
3299 .write_frame(http2::FrameType::Headers, flags, stream_id, first)
3300 .await?;
3301 self.record_bytes_out((http2::FrameHeader::LEN + first.len()) as u64);
3302
3303 let mut remaining = rest;
3304 while remaining.len() > max {
3305 let (chunk, r) = remaining.split_at(max);
3306 framed
3307 .write_frame(http2::FrameType::Continuation, 0, stream_id, chunk)
3308 .await?;
3309 self.record_bytes_out((http2::FrameHeader::LEN + chunk.len()) as u64);
3310 remaining = r;
3311 }
3312 framed
3313 .write_frame(
3314 http2::FrameType::Continuation,
3315 FLAG_END_HEADERS,
3316 stream_id,
3317 remaining,
3318 )
3319 .await?;
3320 self.record_bytes_out((http2::FrameHeader::LEN + remaining.len()) as u64);
3321 }
3322
3323 let mut stream_send_window: i64 = flow_control
3325 .as_ref()
3326 .map_or(i64::MAX, |fc| i64::from(fc.peer_initial_window_size()));
3327
3328 match body {
3330 fastapi_core::ResponseBody::Empty => Ok(()),
3331 fastapi_core::ResponseBody::Bytes(bytes) => {
3332 if bytes.is_empty() {
3333 return Ok(());
3334 }
3335 let mut remaining = bytes.as_slice();
3336 while !remaining.is_empty() {
3337 let max = usize::try_from(peer_max_frame_size).unwrap_or(16 * 1024);
3338 let send_len = remaining.len().min(max);
3339 let send_len = h2_fc_clamp_send(
3340 framed,
3341 &mut flow_control,
3342 &mut stream_send_window,
3343 stream_id,
3344 send_len,
3345 &mut peer_max_frame_size,
3346 recv_max_frame_size,
3347 )
3348 .await?;
3349
3350 let (chunk, r) = remaining.split_at(send_len);
3351 let flags = if r.is_empty() { FLAG_END_STREAM } else { 0 };
3352 framed
3353 .write_frame(http2::FrameType::Data, flags, stream_id, chunk)
3354 .await?;
3355 self.record_bytes_out((http2::FrameHeader::LEN + chunk.len()) as u64);
3356 remaining = r;
3357 }
3358 Ok(())
3359 }
3360 fastapi_core::ResponseBody::Stream(mut s) => {
3361 loop {
3362 let next = poll_fn(|cx| Pin::new(&mut s).poll_next(cx)).await;
3363 match next {
3364 Some(chunk) => {
3365 let mut remaining = chunk.as_slice();
3366 while !remaining.is_empty() {
3367 let max = usize::try_from(peer_max_frame_size).unwrap_or(16 * 1024);
3368 let send_len = remaining.len().min(max);
3369 let send_len = h2_fc_clamp_send(
3370 framed,
3371 &mut flow_control,
3372 &mut stream_send_window,
3373 stream_id,
3374 send_len,
3375 &mut peer_max_frame_size,
3376 recv_max_frame_size,
3377 )
3378 .await?;
3379
3380 let (c, r) = remaining.split_at(send_len);
3381 framed
3382 .write_frame(http2::FrameType::Data, 0, stream_id, c)
3383 .await?;
3384 self.record_bytes_out((http2::FrameHeader::LEN + c.len()) as u64);
3385 remaining = r;
3386 }
3387 }
3388 None => {
3389 framed
3390 .write_frame(
3391 http2::FrameType::Data,
3392 FLAG_END_STREAM,
3393 stream_id,
3394 &[],
3395 )
3396 .await?;
3397 self.record_bytes_out(http2::FrameHeader::LEN as u64);
3398 break;
3399 }
3400 }
3401 }
3402 Ok(())
3403 }
3404 }
3405 }
3406
3407 async fn handle_connection_handler_http2(
3408 &self,
3409 cx: &Cx,
3410 stream: TcpStream,
3411 handler: &dyn fastapi_core::Handler,
3412 ) -> Result<(), ServerError> {
3413 const FLAG_END_HEADERS: u8 = 0x4;
3414 const FLAG_ACK: u8 = 0x1;
3415
3416 let mut framed = http2::FramedH2::new(stream, Vec::new());
3417 let mut hpack = http2::HpackDecoder::new();
3418 let recv_max_frame_size: u32 = 16 * 1024;
3419 let mut peer_max_frame_size: u32 = 16 * 1024;
3420 let mut flow_control = http2::H2FlowControl::new();
3421
3422 let first = framed.read_frame(recv_max_frame_size).await?;
3423 self.record_bytes_in((http2::FrameHeader::LEN + first.payload.len()) as u64);
3424
3425 if first.header.frame_type() != http2::FrameType::Settings
3426 || first.header.stream_id != 0
3427 || (first.header.flags & FLAG_ACK) != 0
3428 {
3429 return Err(
3430 http2::Http2Error::Protocol("expected client SETTINGS after preface").into(),
3431 );
3432 }
3433
3434 apply_http2_settings_with_fc(
3435 &mut hpack,
3436 &mut peer_max_frame_size,
3437 Some(&mut flow_control),
3438 &first.payload,
3439 )?;
3440
3441 framed
3442 .write_frame(http2::FrameType::Settings, 0, 0, SERVER_SETTINGS_PAYLOAD)
3443 .await?;
3444 self.record_bytes_out(http2::FrameHeader::LEN as u64);
3445
3446 framed
3447 .write_frame(http2::FrameType::Settings, FLAG_ACK, 0, &[])
3448 .await?;
3449 self.record_bytes_out(http2::FrameHeader::LEN as u64);
3450
3451 let default_body_limit = self.config.parse_limits.max_request_size;
3452 let mut last_stream_id: u32 = 0;
3453
3454 loop {
3455 if cx.is_cancel_requested() {
3456 let _ = send_goaway(&mut framed, last_stream_id, h2_error_code::NO_ERROR).await;
3457 return Ok(());
3458 }
3459
3460 let frame = framed.read_frame(recv_max_frame_size).await?;
3461 self.record_bytes_in((http2::FrameHeader::LEN + frame.payload.len()) as u64);
3462
3463 match frame.header.frame_type() {
3464 http2::FrameType::Settings => {
3465 let is_ack = validate_settings_frame(
3466 frame.header.stream_id,
3467 frame.header.flags,
3468 &frame.payload,
3469 )?;
3470 if is_ack {
3471 continue;
3472 }
3473 apply_http2_settings_with_fc(
3474 &mut hpack,
3475 &mut peer_max_frame_size,
3476 Some(&mut flow_control),
3477 &frame.payload,
3478 )?;
3479 framed
3480 .write_frame(http2::FrameType::Settings, FLAG_ACK, 0, &[])
3481 .await?;
3482 self.record_bytes_out(http2::FrameHeader::LEN as u64);
3483 }
3484 http2::FrameType::Ping => {
3485 if frame.header.stream_id != 0 || frame.payload.len() != 8 {
3486 return Err(http2::Http2Error::Protocol("invalid PING frame").into());
3487 }
3488 if (frame.header.flags & FLAG_ACK) == 0 {
3489 framed
3490 .write_frame(http2::FrameType::Ping, FLAG_ACK, 0, &frame.payload)
3491 .await?;
3492 self.record_bytes_out((http2::FrameHeader::LEN + 8) as u64);
3493 }
3494 }
3495 http2::FrameType::Goaway => {
3496 validate_goaway_payload(&frame.payload)?;
3497 return Ok(());
3498 }
3499 http2::FrameType::PushPromise => {
3500 return Err(http2::Http2Error::Protocol(
3501 "PUSH_PROMISE not supported by server",
3502 )
3503 .into());
3504 }
3505 http2::FrameType::Headers => {
3506 let stream_id = frame.header.stream_id;
3507 if stream_id == 0 {
3508 return Err(
3509 http2::Http2Error::Protocol("HEADERS must not be on stream 0").into(),
3510 );
3511 }
3512 if stream_id % 2 == 0 {
3513 return Err(http2::Http2Error::Protocol(
3514 "client-initiated stream ID must be odd",
3515 )
3516 .into());
3517 }
3518 if stream_id <= last_stream_id {
3519 return Err(http2::Http2Error::Protocol(
3520 "stream ID must be greater than previous",
3521 )
3522 .into());
3523 }
3524 last_stream_id = stream_id;
3525 let (end_stream, mut header_block) =
3526 extract_header_block_fragment(frame.header.flags, &frame.payload)?;
3527
3528 if (frame.header.flags & FLAG_END_HEADERS) == 0 {
3529 loop {
3530 let cont = framed.read_frame(recv_max_frame_size).await?;
3531 self.record_bytes_in(
3532 (http2::FrameHeader::LEN + cont.payload.len()) as u64,
3533 );
3534 if cont.header.frame_type() != http2::FrameType::Continuation
3535 || cont.header.stream_id != stream_id
3536 {
3537 return Err(http2::Http2Error::Protocol(
3538 "expected CONTINUATION for header block",
3539 )
3540 .into());
3541 }
3542 header_block.extend_from_slice(&cont.payload);
3543 if header_block.len() > MAX_HEADER_BLOCK_SIZE {
3544 return Err(http2::Http2Error::Protocol(
3545 "header block exceeds maximum size",
3546 )
3547 .into());
3548 }
3549 if (cont.header.flags & FLAG_END_HEADERS) != 0 {
3550 break;
3551 }
3552 }
3553 }
3554
3555 let headers = hpack
3556 .decode(&header_block)
3557 .map_err(http2::Http2Error::from)?;
3558 let mut request = request_from_h2_headers(headers)?;
3559
3560 if !end_stream {
3561 let mut body = Vec::new();
3562 let mut stream_reset = false;
3563 let mut stream_received: u32 = 0;
3564 loop {
3565 let f = framed.read_frame(recv_max_frame_size).await?;
3566 self.record_bytes_in(
3567 (http2::FrameHeader::LEN + f.payload.len()) as u64,
3568 );
3569 match f.header.frame_type() {
3570 http2::FrameType::Data if f.header.stream_id == 0 => {
3571 return Err(http2::Http2Error::Protocol(
3572 "DATA must not be on stream 0",
3573 )
3574 .into());
3575 }
3576 http2::FrameType::Data if f.header.stream_id == stream_id => {
3577 let (data, data_end_stream) =
3578 extract_data_payload(f.header.flags, &f.payload)?;
3579 if body.len().saturating_add(data.len()) > default_body_limit {
3580 return Err(http2::Http2Error::Protocol(
3581 "request body exceeds configured limit",
3582 )
3583 .into());
3584 }
3585 body.extend_from_slice(data);
3586
3587 let data_len = u32::try_from(data.len()).unwrap_or(u32::MAX);
3590 stream_received += data_len;
3591 let conn_inc = flow_control.data_received_connection(data_len);
3592 let stream_inc =
3593 flow_control.stream_window_update(stream_received);
3594 if stream_inc > 0 {
3595 stream_received = 0;
3596 }
3597 send_window_updates(
3598 &mut framed,
3599 conn_inc,
3600 stream_id,
3601 stream_inc,
3602 )
3603 .await?;
3604
3605 if data_end_stream {
3606 break;
3607 }
3608 }
3609 http2::FrameType::RstStream => {
3610 validate_rst_stream_payload(f.header.stream_id, &f.payload)?;
3611 if f.header.stream_id == stream_id {
3612 stream_reset = true;
3613 break;
3614 }
3615 }
3616 http2::FrameType::PushPromise => {
3617 return Err(http2::Http2Error::Protocol(
3618 "PUSH_PROMISE not supported by server",
3619 )
3620 .into());
3621 }
3622 http2::FrameType::Settings
3623 | http2::FrameType::Ping
3624 | http2::FrameType::Goaway
3625 | http2::FrameType::WindowUpdate
3626 | http2::FrameType::Priority
3627 | http2::FrameType::Unknown => {
3628 if f.header.frame_type() == http2::FrameType::Goaway {
3629 validate_goaway_payload(&f.payload)?;
3630 return Ok(());
3631 }
3632 if f.header.frame_type() == http2::FrameType::Priority {
3633 validate_priority_payload(f.header.stream_id, &f.payload)?;
3634 }
3635 if f.header.frame_type() == http2::FrameType::WindowUpdate {
3636 validate_window_update_payload(&f.payload)?;
3637 let increment = u32::from_be_bytes([
3638 f.payload[0],
3639 f.payload[1],
3640 f.payload[2],
3641 f.payload[3],
3642 ]) & 0x7FFF_FFFF;
3643 if f.header.stream_id == 0 {
3644 apply_send_conn_window_update(
3645 &mut flow_control,
3646 increment,
3647 )?;
3648 }
3649 }
3650 if f.header.frame_type() == http2::FrameType::Ping {
3651 if f.header.stream_id != 0 || f.payload.len() != 8 {
3652 return Err(http2::Http2Error::Protocol(
3653 "invalid PING frame",
3654 )
3655 .into());
3656 }
3657 if (f.header.flags & FLAG_ACK) == 0 {
3658 framed
3659 .write_frame(
3660 http2::FrameType::Ping,
3661 FLAG_ACK,
3662 0,
3663 &f.payload,
3664 )
3665 .await?;
3666 self.record_bytes_out(
3667 (http2::FrameHeader::LEN + 8) as u64,
3668 );
3669 }
3670 }
3671 if f.header.frame_type() == http2::FrameType::Settings {
3672 let is_ack = validate_settings_frame(
3673 f.header.stream_id,
3674 f.header.flags,
3675 &f.payload,
3676 )?;
3677 if !is_ack {
3678 apply_http2_settings_with_fc(
3679 &mut hpack,
3680 &mut peer_max_frame_size,
3681 Some(&mut flow_control),
3682 &f.payload,
3683 )?;
3684 framed
3685 .write_frame(
3686 http2::FrameType::Settings,
3687 FLAG_ACK,
3688 0,
3689 &[],
3690 )
3691 .await?;
3692 self.record_bytes_out(http2::FrameHeader::LEN as u64);
3693 }
3694 }
3695 }
3696 _ => {
3697 return Err(http2::Http2Error::Protocol(
3698 "unsupported frame while reading request body",
3699 )
3700 .into());
3701 }
3702 }
3703 }
3704 if stream_reset {
3705 continue;
3706 }
3707 request.set_body(fastapi_core::Body::Bytes(body));
3708 }
3709
3710 let request_id = self.request_counter.fetch_add(1, Ordering::Relaxed);
3711 let request_budget =
3712 Budget::new().with_deadline(request_deadline(self.config.request_timeout));
3713 let request_cx = request_cx_from_parent(cx, request_budget);
3714
3715 let overrides = handler
3716 .dependency_overrides()
3717 .unwrap_or_else(|| Arc::new(fastapi_core::DependencyOverrides::new()));
3718
3719 let ctx = RequestContext::with_overrides_and_body_limit(
3720 request_cx,
3721 request_id,
3722 overrides,
3723 default_body_limit,
3724 );
3725
3726 if let Err(err) = validate_host_header(&request, &self.config) {
3727 let response = err.response();
3728 self.write_h2_response(
3729 &mut framed,
3730 response,
3731 stream_id,
3732 peer_max_frame_size,
3733 recv_max_frame_size,
3734 Some(&mut flow_control),
3735 )
3736 .await?;
3737 continue;
3738 }
3739 if let Err(response) = self.config.pre_body_validators.validate_all(&request) {
3740 self.write_h2_response(
3741 &mut framed,
3742 response,
3743 stream_id,
3744 peer_max_frame_size,
3745 recv_max_frame_size,
3746 Some(&mut flow_control),
3747 )
3748 .await?;
3749 continue;
3750 }
3751
3752 let response = handler.call(&ctx, &mut request).await;
3753 self.write_h2_response(
3754 &mut framed,
3755 response,
3756 stream_id,
3757 peer_max_frame_size,
3758 recv_max_frame_size,
3759 Some(&mut flow_control),
3760 )
3761 .await?;
3762 }
3763 http2::FrameType::WindowUpdate => {
3764 validate_window_update_payload(&frame.payload)?;
3765 let increment = u32::from_be_bytes([
3766 frame.payload[0],
3767 frame.payload[1],
3768 frame.payload[2],
3769 frame.payload[3],
3770 ]) & 0x7FFF_FFFF;
3771 if frame.header.stream_id == 0 {
3772 apply_send_conn_window_update(&mut flow_control, increment)?;
3773 }
3774 }
3775 _ => {
3776 handle_h2_idle_frame(&frame)?;
3777 }
3778 }
3779 }
3780 }
3781
3782 async fn handle_connection_handler(
3787 &self,
3788 cx: &Cx,
3789 mut stream: TcpStream,
3790 _peer_addr: SocketAddr,
3791 handler: &dyn fastapi_core::Handler,
3792 ) -> Result<(), ServerError> {
3793 let (proto, buffered) = sniff_protocol(&mut stream, self.config.keep_alive_timeout).await?;
3794 if !buffered.is_empty() {
3795 self.record_bytes_in(buffered.len() as u64);
3796 }
3797 if proto == SniffedProtocol::Http2PriorKnowledge {
3798 return self
3799 .handle_connection_handler_http2(cx, stream, handler)
3800 .await;
3801 }
3802
3803 let mut parser = StatefulParser::new().with_limits(self.config.parse_limits.clone());
3804 if !buffered.is_empty() {
3805 parser.feed(&buffered)?;
3806 }
3807 let mut read_buffer = vec![0u8; self.config.read_buffer_size];
3808 let mut response_writer = ResponseWriter::new();
3809 let mut requests_on_connection: usize = 0;
3810 let max_requests = self.config.max_requests_per_connection;
3811
3812 loop {
3813 if cx.is_cancel_requested() {
3815 return Ok(());
3816 }
3817
3818 let parse_result = parser.feed(&[])?;
3820
3821 let mut request = match parse_result {
3822 ParseStatus::Complete { request, .. } => request,
3823 ParseStatus::Incomplete => {
3824 let keep_alive_timeout = self.config.keep_alive_timeout;
3825 let bytes_read = if keep_alive_timeout.is_zero() {
3826 read_into_buffer(&mut stream, &mut read_buffer).await?
3827 } else {
3828 match read_with_timeout(&mut stream, &mut read_buffer, keep_alive_timeout)
3829 .await
3830 {
3831 Ok(0) => return Ok(()),
3832 Ok(n) => n,
3833 Err(e) if e.kind() == io::ErrorKind::TimedOut => {
3834 self.metrics_counters
3835 .total_timed_out
3836 .fetch_add(1, Ordering::Relaxed);
3837 return Err(ServerError::KeepAliveTimeout);
3838 }
3839 Err(e) => return Err(ServerError::Io(e)),
3840 }
3841 };
3842
3843 if bytes_read == 0 {
3844 return Ok(());
3845 }
3846
3847 self.record_bytes_in(bytes_read as u64);
3848
3849 match parser.feed(&read_buffer[..bytes_read])? {
3850 ParseStatus::Complete { request, .. } => request,
3851 ParseStatus::Incomplete => continue,
3852 }
3853 }
3854 };
3855
3856 requests_on_connection += 1;
3857
3858 let request_id = self.request_counter.fetch_add(1, Ordering::Relaxed);
3860 let request_budget =
3861 Budget::new().with_deadline(request_deadline(self.config.request_timeout));
3862 let request_cx = request_cx_from_parent(cx, request_budget);
3863 let ctx = RequestContext::new(request_cx, request_id);
3864
3865 if let Err(err) = validate_host_header(&request, &self.config) {
3867 let response = err.response().header("connection", b"close".to_vec());
3868 let response_write = response_writer.write(response);
3869 write_response(&mut stream, response_write).await?;
3870 return Ok(());
3871 }
3872
3873 if let Err(response) = self.config.pre_body_validators.validate_all(&request) {
3875 let response = response.header("connection", b"close".to_vec());
3876 let response_write = response_writer.write(response);
3877 write_response(&mut stream, response_write).await?;
3878 return Ok(());
3879 }
3880
3881 match ExpectHandler::check_expect(&request) {
3883 ExpectResult::NoExpectation => {}
3884 ExpectResult::ExpectsContinue => {
3885 write_raw_response(&mut stream, CONTINUE_RESPONSE).await?;
3886 }
3887 ExpectResult::UnknownExpectation(_) => {
3888 let response =
3889 ExpectHandler::expectation_failed("Unsupported Expect value".to_string());
3890 let response_write = response_writer.write(response);
3891 write_response(&mut stream, response_write).await?;
3892 return Ok(());
3893 }
3894 }
3895
3896 let response = handler.call(&ctx, &mut request).await;
3898
3899 let client_wants_keep_alive = should_keep_alive(&request);
3901 let server_will_keep_alive = client_wants_keep_alive
3902 && (max_requests == 0 || requests_on_connection < max_requests);
3903
3904 let response = if server_will_keep_alive {
3905 response.header("connection", b"keep-alive".to_vec())
3906 } else {
3907 response.header("connection", b"close".to_vec())
3908 };
3909
3910 let response_write = response_writer.write(response);
3911 if let ResponseWrite::Full(ref bytes) = response_write {
3912 self.record_bytes_out(bytes.len() as u64);
3913 }
3914 write_response(&mut stream, response_write).await?;
3915
3916 if !server_will_keep_alive {
3917 return Ok(());
3918 }
3919 }
3920 }
3921
3922 async fn accept_loop<H, Fut>(
3924 &self,
3925 cx: &Cx,
3926 listener: TcpListener,
3927 handler: H,
3928 ) -> Result<(), ServerError>
3929 where
3930 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync + 'static,
3931 Fut: Future<Output = Response> + Send + 'static,
3932 {
3933 let handler = Arc::new(handler);
3934
3935 loop {
3936 if cx.is_cancel_requested() {
3938 cx.trace("Server shutdown requested");
3939 return Ok(());
3940 }
3941
3942 if self.is_draining() {
3944 cx.trace("Server draining, stopping accept loop");
3945 return Err(ServerError::Shutdown);
3946 }
3947
3948 let (mut stream, peer_addr) = match listener.accept().await {
3950 Ok(conn) => conn,
3951 Err(e) if e.kind() == io::ErrorKind::WouldBlock => {
3952 continue;
3954 }
3955 Err(e) => {
3956 cx.trace(&format!("Accept error: {e}"));
3957 if is_fatal_accept_error(&e) {
3960 return Err(ServerError::Io(e));
3961 }
3962 continue;
3963 }
3964 };
3965
3966 if !self.try_acquire_connection() {
3968 cx.trace(&format!(
3969 "Connection limit reached ({}), rejecting {peer_addr}",
3970 self.config.max_connections
3971 ));
3972
3973 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
3975 .header("connection", b"close".to_vec())
3976 .body(fastapi_core::ResponseBody::Bytes(
3977 b"503 Service Unavailable: connection limit reached".to_vec(),
3978 ));
3979 let mut writer = crate::response::ResponseWriter::new();
3980 let response_bytes = writer.write(response);
3981 let _ = write_response(&mut stream, response_bytes).await;
3982 continue;
3983 }
3984
3985 if self.config.tcp_nodelay {
3987 let _ = stream.set_nodelay(true);
3988 }
3989
3990 cx.trace(&format!(
3991 "Accepted connection from {peer_addr} ({}/{})",
3992 self.current_connections(),
3993 if self.config.max_connections == 0 {
3994 "∞".to_string()
3995 } else {
3996 self.config.max_connections.to_string()
3997 }
3998 ));
3999
4000 let request_id = self.next_request_id();
4005 let request_budget =
4006 Budget::new().with_deadline(request_deadline(self.config.request_timeout));
4007
4008 let request_cx = request_cx_from_parent(cx, request_budget);
4010 let ctx = RequestContext::new(request_cx, request_id);
4011
4012 let result = self
4014 .handle_connection(&ctx, stream, peer_addr, &*handler)
4015 .await;
4016
4017 self.release_connection();
4019
4020 if let Err(e) = result {
4021 cx.trace(&format!("Connection error from {peer_addr}: {e}"));
4022 }
4023 }
4024 }
4025
4026 async fn handle_connection<H, Fut>(
4032 &self,
4033 ctx: &RequestContext,
4034 stream: TcpStream,
4035 peer_addr: SocketAddr,
4036 handler: &H,
4037 ) -> Result<(), ServerError>
4038 where
4039 H: Fn(RequestContext, &mut Request) -> Fut + Send + Sync,
4040 Fut: Future<Output = Response> + Send,
4041 {
4042 process_connection(
4043 ctx.cx(),
4044 &self.request_counter,
4045 stream,
4046 peer_addr,
4047 &self.config,
4048 |ctx, req| handler(ctx, req),
4049 )
4050 .await
4051 }
4052}
4053
4054#[derive(Debug, Clone, PartialEq, Eq)]
4059pub struct ServerMetrics {
4060 pub active_connections: u64,
4062 pub total_accepted: u64,
4064 pub total_rejected: u64,
4066 pub total_timed_out: u64,
4068 pub total_requests: u64,
4070 pub bytes_in: u64,
4072 pub bytes_out: u64,
4074}
4075
4076#[derive(Debug)]
4081struct MetricsCounters {
4082 total_accepted: AtomicU64,
4083 total_rejected: AtomicU64,
4084 total_timed_out: AtomicU64,
4085 bytes_in: AtomicU64,
4086 bytes_out: AtomicU64,
4087}
4088
4089impl MetricsCounters {
4090 fn new() -> Self {
4091 Self {
4092 total_accepted: AtomicU64::new(0),
4093 total_rejected: AtomicU64::new(0),
4094 total_timed_out: AtomicU64::new(0),
4095 bytes_in: AtomicU64::new(0),
4096 bytes_out: AtomicU64::new(0),
4097 }
4098 }
4099}
4100
4101impl Default for TcpServer {
4102 fn default() -> Self {
4103 Self::new(ServerConfig::default())
4104 }
4105}
4106
4107fn is_fatal_accept_error(e: &io::Error) -> bool {
4109 matches!(
4111 e.kind(),
4112 io::ErrorKind::NotConnected | io::ErrorKind::InvalidInput
4113 )
4114}
4115
4116pub async fn read_into_buffer(stream: &mut TcpStream, buffer: &mut [u8]) -> io::Result<usize> {
4123 use std::future::poll_fn;
4124
4125 poll_fn(|cx| {
4126 let mut read_buf = ReadBuf::new(buffer);
4127 match Pin::new(&mut *stream).poll_read(cx, &mut read_buf) {
4128 Poll::Ready(Ok(())) => Poll::Ready(Ok(read_buf.filled().len())),
4129 Poll::Ready(Err(e)) => Poll::Ready(Err(e)),
4130 Poll::Pending => Poll::Pending,
4131 }
4132 })
4133 .await
4134}
4135
4136async fn read_with_timeout(
4154 stream: &mut TcpStream,
4155 buffer: &mut [u8],
4156 timeout_duration: Duration,
4157) -> io::Result<usize> {
4158 let now = current_time();
4160
4161 let read_future = Box::pin(read_into_buffer(stream, buffer));
4163
4164 match timeout(now, timeout_duration, read_future).await {
4166 Ok(result) => result,
4167 Err(_elapsed) => Err(io::Error::new(
4168 io::ErrorKind::TimedOut,
4169 "keep-alive timeout expired",
4170 )),
4171 }
4172}
4173
4174#[derive(Debug, Clone, Copy, PartialEq, Eq)]
4175enum SniffedProtocol {
4176 Http1,
4177 Http2PriorKnowledge,
4178}
4179
4180async fn sniff_protocol(
4184 stream: &mut TcpStream,
4185 keep_alive_timeout: Duration,
4186) -> io::Result<(SniffedProtocol, Vec<u8>)> {
4187 let mut buffered: Vec<u8> = Vec::new();
4188 let preface = http2::PREFACE;
4189
4190 while buffered.len() < preface.len() {
4191 let mut tmp = vec![0u8; preface.len() - buffered.len()];
4192 let n = if keep_alive_timeout.is_zero() {
4193 read_into_buffer(stream, &mut tmp).await?
4194 } else {
4195 read_with_timeout(stream, &mut tmp, keep_alive_timeout).await?
4196 };
4197 if n == 0 {
4198 return Ok((SniffedProtocol::Http1, buffered));
4200 }
4201
4202 buffered.extend_from_slice(&tmp[..n]);
4203 if !preface.starts_with(&buffered) {
4204 return Ok((SniffedProtocol::Http1, buffered));
4205 }
4206 }
4207
4208 Ok((SniffedProtocol::Http2PriorKnowledge, buffered))
4209}
4210
4211const SETTINGS_HEADER_TABLE_SIZE: u16 = 0x1;
4212const SETTINGS_ENABLE_PUSH: u16 = 0x2;
4213const SETTINGS_MAX_CONCURRENT_STREAMS: u16 = 0x3;
4214const SETTINGS_INITIAL_WINDOW_SIZE: u16 = 0x4;
4215const SETTINGS_MAX_FRAME_SIZE: u16 = 0x5;
4216const SETTINGS_MAX_HEADER_LIST_SIZE: u16 = 0x6;
4217
4218fn apply_http2_settings(
4219 hpack: &mut http2::HpackDecoder,
4220 max_frame_size: &mut u32,
4221 payload: &[u8],
4222) -> Result<(), http2::Http2Error> {
4223 apply_http2_settings_with_fc(hpack, max_frame_size, None, payload)
4224}
4225
4226fn apply_http2_settings_with_fc(
4227 hpack: &mut http2::HpackDecoder,
4228 max_frame_size: &mut u32,
4229 mut flow_control: Option<&mut http2::H2FlowControl>,
4230 payload: &[u8],
4231) -> Result<(), http2::Http2Error> {
4232 if payload.len() % 6 != 0 {
4234 return Err(http2::Http2Error::Protocol(
4235 "SETTINGS length must be a multiple of 6",
4236 ));
4237 }
4238
4239 for chunk in payload.chunks_exact(6) {
4240 let id = u16::from_be_bytes([chunk[0], chunk[1]]);
4241 let value = u32::from_be_bytes([chunk[2], chunk[3], chunk[4], chunk[5]]);
4242 match id {
4243 SETTINGS_HEADER_TABLE_SIZE => {
4244 let capped = (value as usize).min(MAX_HPACK_TABLE_SIZE);
4246 hpack.set_dynamic_table_max_size(capped);
4247 }
4248 SETTINGS_MAX_CONCURRENT_STREAMS => {
4249 }
4251 SETTINGS_INITIAL_WINDOW_SIZE => {
4252 if value > 0x7FFF_FFFF {
4255 return Err(http2::Http2Error::Protocol(
4256 "SETTINGS_INITIAL_WINDOW_SIZE exceeds maximum",
4257 ));
4258 }
4259 if let Some(ref mut fc) = flow_control {
4260 fc.set_peer_initial_window_size(value);
4264 }
4265 }
4266 SETTINGS_MAX_FRAME_SIZE => {
4267 if !(16_384..=16_777_215).contains(&value) {
4269 return Err(http2::Http2Error::Protocol(
4270 "invalid SETTINGS_MAX_FRAME_SIZE",
4271 ));
4272 }
4273 *max_frame_size = value;
4274 }
4275 SETTINGS_ENABLE_PUSH if value > 1 => {
4276 return Err(http2::Http2Error::Protocol(
4277 "SETTINGS_ENABLE_PUSH must be 0 or 1",
4278 ));
4279 }
4280 SETTINGS_ENABLE_PUSH => {
4281 }
4284 SETTINGS_MAX_HEADER_LIST_SIZE => {
4285 hpack.set_max_header_list_size(value as usize);
4287 }
4288 _ => {
4289 }
4291 }
4292 }
4293 Ok(())
4294}
4295
4296fn validate_settings_frame(
4297 stream_id: u32,
4298 flags: u8,
4299 payload: &[u8],
4300) -> Result<bool, http2::Http2Error> {
4301 const FLAG_ACK: u8 = 0x1;
4302 if stream_id != 0 {
4303 return Err(http2::Http2Error::Protocol("SETTINGS must be on stream 0"));
4304 }
4305
4306 let is_ack = (flags & FLAG_ACK) != 0;
4307 if is_ack && !payload.is_empty() {
4308 return Err(http2::Http2Error::Protocol(
4309 "SETTINGS ACK frame must have empty payload",
4310 ));
4311 }
4312
4313 Ok(is_ack)
4314}
4315
4316fn validate_window_update_payload(payload: &[u8]) -> Result<(), http2::Http2Error> {
4317 if payload.len() != 4 {
4318 return Err(http2::Http2Error::Protocol(
4319 "WINDOW_UPDATE payload must be 4 bytes",
4320 ));
4321 }
4322
4323 let raw = u32::from_be_bytes([payload[0], payload[1], payload[2], payload[3]]);
4324 let increment = raw & 0x7FFF_FFFF;
4325 if increment == 0 {
4326 return Err(http2::Http2Error::Protocol(
4327 "WINDOW_UPDATE increment must be non-zero",
4328 ));
4329 }
4330
4331 Ok(())
4332}
4333
4334fn handle_h2_idle_frame(frame: &http2::Frame) -> Result<(), http2::Http2Error> {
4335 match frame.header.frame_type() {
4336 http2::FrameType::RstStream => {
4337 validate_rst_stream_payload(frame.header.stream_id, &frame.payload)
4338 }
4339 http2::FrameType::Priority => {
4340 validate_priority_payload(frame.header.stream_id, &frame.payload)
4341 }
4342 http2::FrameType::Data => Err(http2::Http2Error::Protocol(
4343 "unexpected DATA frame outside active request stream",
4344 )),
4345 http2::FrameType::Continuation => Err(http2::Http2Error::Protocol(
4346 "unexpected CONTINUATION frame outside header block",
4347 )),
4348 http2::FrameType::Unknown => Ok(()),
4349 _ => Ok(()),
4350 }
4351}
4352
4353const MAX_FLOW_CONTROL_WINDOW: i64 = 0x7FFF_FFFF;
4355
4356const SERVER_SETTINGS_PAYLOAD: &[u8] = &[
4360 0x00, 0x03, 0x00, 0x00, 0x00, 0x01, ];
4363
4364const MAX_HPACK_TABLE_SIZE: usize = 64 * 1024;
4368
4369const MAX_HEADER_BLOCK_SIZE: usize = 128 * 1024;
4376
4377fn apply_send_conn_window_update(
4380 fc: &mut http2::H2FlowControl,
4381 increment: u32,
4382) -> Result<(), http2::Http2Error> {
4383 let new_window = fc.send_conn_window() + i64::from(increment);
4384 if new_window > MAX_FLOW_CONTROL_WINDOW {
4385 return Err(http2::Http2Error::Protocol(
4386 "WINDOW_UPDATE causes flow-control window to exceed 2^31-1",
4387 ));
4388 }
4389 fc.peer_window_update_connection(increment);
4390 Ok(())
4391}
4392
4393fn apply_peer_window_update_for_send(
4394 flow_control: &mut http2::H2FlowControl,
4395 stream_send_window: &mut i64,
4396 current_stream_id: u32,
4397 frame_stream_id: u32,
4398 payload: &[u8],
4399) -> Result<(), http2::Http2Error> {
4400 validate_window_update_payload(payload)?;
4401
4402 let increment =
4403 u32::from_be_bytes([payload[0], payload[1], payload[2], payload[3]]) & 0x7FFF_FFFF;
4404 if frame_stream_id == 0 {
4405 apply_send_conn_window_update(flow_control, increment)?;
4406 } else if frame_stream_id == current_stream_id {
4407 let new_window = *stream_send_window + i64::from(increment);
4408 if new_window > MAX_FLOW_CONTROL_WINDOW {
4409 return Err(http2::Http2Error::Protocol(
4410 "WINDOW_UPDATE causes flow-control window to exceed 2^31-1",
4411 ));
4412 }
4413 *stream_send_window = new_window;
4414 }
4415
4416 Ok(())
4417}
4418
4419fn apply_peer_settings_for_send(
4420 flow_control: &mut http2::H2FlowControl,
4421 stream_send_window: &mut i64,
4422 peer_max_frame_size: &mut u32,
4423 payload: &[u8],
4424) -> Result<(), http2::Http2Error> {
4425 if payload.len() % 6 != 0 {
4426 return Err(http2::Http2Error::Protocol(
4427 "SETTINGS length must be a multiple of 6",
4428 ));
4429 }
4430
4431 for chunk in payload.chunks_exact(6) {
4432 let id = u16::from_be_bytes([chunk[0], chunk[1]]);
4433 let value = u32::from_be_bytes([chunk[2], chunk[3], chunk[4], chunk[5]]);
4434
4435 if id == SETTINGS_INITIAL_WINDOW_SIZE {
4436 if value > 0x7FFF_FFFF {
4438 return Err(http2::Http2Error::Protocol(
4439 "SETTINGS_INITIAL_WINDOW_SIZE exceeds maximum",
4440 ));
4441 }
4442 let old = i64::from(flow_control.peer_initial_window_size());
4443 let new = i64::from(value);
4444 let delta = new - old;
4445 let updated = *stream_send_window + delta;
4446 if updated > MAX_FLOW_CONTROL_WINDOW {
4447 return Err(http2::Http2Error::Protocol(
4448 "SETTINGS_INITIAL_WINDOW_SIZE change causes stream window to exceed 2^31-1",
4449 ));
4450 }
4451 flow_control.set_peer_initial_window_size(value);
4452 *stream_send_window = updated;
4453 } else if id == 0x5 {
4454 if !(16_384..=16_777_215).contains(&value) {
4456 return Err(http2::Http2Error::Protocol(
4457 "invalid SETTINGS_MAX_FRAME_SIZE",
4458 ));
4459 }
4460 *peer_max_frame_size = value;
4461 }
4462 }
4463
4464 Ok(())
4465}
4466
4467fn window_update_payload(increment: u32) -> [u8; 4] {
4469 (increment & 0x7FFF_FFFF).to_be_bytes()
4470}
4471
4472async fn send_window_updates(
4475 framed: &mut http2::FramedH2,
4476 conn_increment: u32,
4477 stream_id: u32,
4478 stream_increment: u32,
4479) -> Result<(), http2::Http2Error> {
4480 if conn_increment > 0 {
4481 let payload = window_update_payload(conn_increment);
4482 framed
4483 .write_frame(http2::FrameType::WindowUpdate, 0, 0, &payload)
4484 .await?;
4485 }
4486 if stream_increment > 0 {
4487 let payload = window_update_payload(stream_increment);
4488 framed
4489 .write_frame(http2::FrameType::WindowUpdate, 0, stream_id, &payload)
4490 .await?;
4491 }
4492 Ok(())
4493}
4494
4495#[allow(dead_code)]
4497mod h2_error_code {
4498 pub const NO_ERROR: u32 = 0x0;
4499 pub const PROTOCOL_ERROR: u32 = 0x1;
4500 pub const FLOW_CONTROL_ERROR: u32 = 0x3;
4501 pub const SETTINGS_TIMEOUT: u32 = 0x4;
4502 pub const STREAM_CLOSED: u32 = 0x5;
4503 pub const FRAME_SIZE_ERROR: u32 = 0x6;
4504 pub const REFUSED_STREAM: u32 = 0x7;
4505 pub const CANCEL: u32 = 0x8;
4506 pub const ENHANCE_YOUR_CALM: u32 = 0xb;
4507}
4508
4509fn validate_goaway_payload(payload: &[u8]) -> Result<(), http2::Http2Error> {
4511 if payload.len() < 8 {
4512 return Err(http2::Http2Error::Protocol(
4513 "GOAWAY payload must be at least 8 bytes",
4514 ));
4515 }
4516 Ok(())
4517}
4518
4519fn goaway_payload(last_stream_id: u32, error_code: u32) -> [u8; 8] {
4521 let mut buf = [0u8; 8];
4522 buf[..4].copy_from_slice(&(last_stream_id & 0x7FFF_FFFF).to_be_bytes());
4523 buf[4..].copy_from_slice(&error_code.to_be_bytes());
4524 buf
4525}
4526
4527async fn send_goaway(
4529 framed: &mut http2::FramedH2,
4530 last_stream_id: u32,
4531 error_code: u32,
4532) -> Result<(), http2::Http2Error> {
4533 let payload = goaway_payload(last_stream_id, error_code);
4534 framed
4535 .write_frame(http2::FrameType::Goaway, 0, 0, &payload)
4536 .await
4537}
4538
4539fn validate_rst_stream_payload(stream_id: u32, payload: &[u8]) -> Result<(), http2::Http2Error> {
4540 if stream_id == 0 {
4541 return Err(http2::Http2Error::Protocol(
4542 "RST_STREAM must not be on stream 0",
4543 ));
4544 }
4545 if payload.len() != 4 {
4546 return Err(http2::Http2Error::Protocol(
4547 "RST_STREAM payload must be 4 bytes",
4548 ));
4549 }
4550 Ok(())
4551}
4552
4553fn validate_priority_payload(stream_id: u32, payload: &[u8]) -> Result<(), http2::Http2Error> {
4554 if stream_id == 0 {
4555 return Err(http2::Http2Error::Protocol(
4556 "PRIORITY must not be on stream 0",
4557 ));
4558 }
4559
4560 if payload.len() != 5 {
4561 return Err(http2::Http2Error::Protocol(
4562 "PRIORITY payload must be 5 bytes",
4563 ));
4564 }
4565
4566 let dependency_raw = u32::from_be_bytes([payload[0], payload[1], payload[2], payload[3]]);
4567 let dependency_stream_id = dependency_raw & 0x7FFF_FFFF;
4568 if dependency_stream_id == stream_id {
4569 return Err(http2::Http2Error::Protocol(
4570 "PRIORITY stream dependency must not reference itself",
4571 ));
4572 }
4573
4574 Ok(())
4575}
4576
4577fn extract_header_block_fragment(
4578 flags: u8,
4579 payload: &[u8],
4580) -> Result<(bool, Vec<u8>), http2::Http2Error> {
4581 const FLAG_END_STREAM: u8 = 0x1;
4582 const FLAG_PADDED: u8 = 0x8;
4583 const FLAG_PRIORITY: u8 = 0x20;
4584
4585 let end_stream = (flags & FLAG_END_STREAM) != 0;
4586 let mut idx = 0usize;
4587
4588 let pad_len = if (flags & FLAG_PADDED) != 0 {
4589 if payload.is_empty() {
4590 return Err(http2::Http2Error::Protocol(
4591 "HEADERS PADDED set with empty payload",
4592 ));
4593 }
4594 let v = payload[0] as usize;
4595 idx += 1;
4596 v
4597 } else {
4598 0
4599 };
4600
4601 if (flags & FLAG_PRIORITY) != 0 {
4602 if payload.len().saturating_sub(idx) < 5 {
4604 return Err(http2::Http2Error::Protocol(
4605 "HEADERS PRIORITY set but too short",
4606 ));
4607 }
4608 idx += 5;
4609 }
4610
4611 if payload.len() < idx {
4612 return Err(http2::Http2Error::Protocol("invalid HEADERS payload"));
4613 }
4614 let frag = &payload[idx..];
4615 if frag.len() < pad_len {
4616 return Err(http2::Http2Error::Protocol(
4617 "invalid HEADERS padding length",
4618 ));
4619 }
4620 let end = frag.len() - pad_len;
4621 Ok((end_stream, frag[..end].to_vec()))
4622}
4623
4624fn extract_data_payload(flags: u8, payload: &[u8]) -> Result<(&[u8], bool), http2::Http2Error> {
4625 const FLAG_END_STREAM: u8 = 0x1;
4626 const FLAG_PADDED: u8 = 0x8;
4627
4628 let end_stream = (flags & FLAG_END_STREAM) != 0;
4629 if (flags & FLAG_PADDED) == 0 {
4630 return Ok((payload, end_stream));
4631 }
4632 if payload.is_empty() {
4633 return Err(http2::Http2Error::Protocol(
4634 "DATA PADDED set with empty payload",
4635 ));
4636 }
4637 let pad_len = payload[0] as usize;
4638 let data = &payload[1..];
4639 if data.len() < pad_len {
4640 return Err(http2::Http2Error::Protocol("invalid DATA padding length"));
4641 }
4642 Ok((&data[..data.len() - pad_len], end_stream))
4643}
4644
4645fn request_from_h2_headers(headers: http2::HeaderList) -> Result<Request, http2::Http2Error> {
4646 let mut method: Option<fastapi_core::Method> = None;
4647 let mut path: Option<String> = None;
4648 let mut authority: Option<Vec<u8>> = None;
4649 let mut saw_regular_headers = false;
4650
4651 let mut req_headers: Vec<(String, Vec<u8>)> = Vec::new();
4652
4653 for (name, value) in headers {
4654 if name.starts_with(b":") {
4655 if saw_regular_headers {
4656 return Err(http2::Http2Error::Protocol(
4657 "pseudo-headers must appear before regular headers",
4658 ));
4659 }
4660 match name.as_slice() {
4661 b":method" => {
4662 if method.is_some() {
4663 return Err(http2::Http2Error::Protocol(
4664 "duplicate :method pseudo-header",
4665 ));
4666 }
4667 method = Some(
4668 fastapi_core::Method::from_bytes(&value)
4669 .ok_or(http2::Http2Error::Protocol("invalid :method"))?,
4670 );
4671 }
4672 b":path" => {
4673 if path.is_some() {
4674 return Err(http2::Http2Error::Protocol("duplicate :path pseudo-header"));
4675 }
4676 let s = std::str::from_utf8(&value)
4677 .map_err(|_| http2::Http2Error::Protocol("non-utf8 :path"))?;
4678 path = Some(s.to_string());
4679 }
4680 b":authority" => {
4681 if authority.is_some() {
4682 return Err(http2::Http2Error::Protocol(
4683 "duplicate :authority pseudo-header",
4684 ));
4685 }
4686 authority = Some(value);
4687 }
4688 b":scheme" => {}
4689 _ => return Err(http2::Http2Error::Protocol("unknown pseudo-header")),
4690 }
4691 continue;
4692 }
4693
4694 saw_regular_headers = true;
4695 let n = std::str::from_utf8(&name)
4696 .map_err(|_| http2::Http2Error::Protocol("non-utf8 header name"))?;
4697 req_headers.push((n.to_string(), value));
4698 }
4699
4700 let method = method.ok_or(http2::Http2Error::Protocol("missing :method"))?;
4701 let raw_path = path.ok_or(http2::Http2Error::Protocol("missing :path"))?;
4702 let (path_only, query) = match raw_path.split_once('?') {
4703 Some((p, q)) => (p.to_string(), Some(q.to_string())),
4704 None => (raw_path, None),
4705 };
4706
4707 let mut req = Request::with_version(method, path_only, fastapi_core::HttpVersion::Http2);
4708 req.set_query(query);
4709
4710 if let Some(auth) = authority {
4711 req.headers_mut().insert("host", auth);
4712 }
4713
4714 for (n, v) in req_headers {
4715 req.headers_mut().insert(n, v);
4716 }
4717
4718 Ok(req)
4719}
4720
4721fn is_h2_forbidden_header_name(name: &str) -> bool {
4722 name.eq_ignore_ascii_case("connection")
4725 || name.eq_ignore_ascii_case("keep-alive")
4726 || name.eq_ignore_ascii_case("proxy-connection")
4727 || name.eq_ignore_ascii_case("transfer-encoding")
4728 || name.eq_ignore_ascii_case("upgrade")
4729 || name.eq_ignore_ascii_case("te")
4730}
4731
4732async fn write_raw_response(stream: &mut TcpStream, bytes: &[u8]) -> io::Result<()> {
4736 use std::future::poll_fn;
4737 write_all(stream, bytes).await?;
4738 poll_fn(|cx| Pin::new(&mut *stream).poll_flush(cx)).await?;
4739 Ok(())
4740}
4741
4742pub async fn write_response(stream: &mut TcpStream, response: ResponseWrite) -> io::Result<()> {
4747 use std::future::poll_fn;
4748
4749 match response {
4750 ResponseWrite::Full(bytes) => {
4751 write_all(stream, &bytes).await?;
4752 }
4753 ResponseWrite::Stream(mut encoder) => {
4754 loop {
4756 let chunk = poll_fn(|cx| Pin::new(&mut encoder).poll_next(cx)).await;
4757 match chunk {
4758 Some(bytes) => {
4759 write_all(stream, &bytes).await?;
4760 }
4761 None => break,
4762 }
4763 }
4764 }
4765 }
4766
4767 poll_fn(|cx| Pin::new(&mut *stream).poll_flush(cx)).await?;
4769
4770 Ok(())
4771}
4772
4773pub async fn write_all(stream: &mut TcpStream, mut buf: &[u8]) -> io::Result<()> {
4775 use std::future::poll_fn;
4776
4777 while !buf.is_empty() {
4778 let n = poll_fn(|cx| Pin::new(&mut *stream).poll_write(cx, buf)).await?;
4779 if n == 0 {
4780 return Err(io::Error::new(
4781 io::ErrorKind::WriteZero,
4782 "failed to write whole buffer",
4783 ));
4784 }
4785 buf = &buf[n..];
4786 }
4787 Ok(())
4788}
4789
4790pub struct Server {
4802 parser: Parser,
4803}
4804
4805impl Server {
4806 #[must_use]
4808 pub fn new() -> Self {
4809 Self {
4810 parser: Parser::new(),
4811 }
4812 }
4813
4814 pub fn parse_request(&self, bytes: &[u8]) -> Result<Request, ParseError> {
4820 self.parser.parse(bytes)
4821 }
4822
4823 #[must_use]
4825 pub fn write_response(&self, response: Response) -> ResponseWrite {
4826 let mut writer = ResponseWriter::new();
4827 writer.write(response)
4828 }
4829}
4830
4831impl Default for Server {
4832 fn default() -> Self {
4833 Self::new()
4834 }
4835}
4836
4837#[cfg(test)]
4838mod tests {
4839 use super::*;
4840 use std::future::Future;
4841
4842 fn block_on<F: Future>(f: F) -> F::Output {
4843 let rt = asupersync::runtime::RuntimeBuilder::current_thread()
4844 .build()
4845 .expect("test runtime must build");
4846 rt.block_on(f)
4847 }
4848
4849 #[test]
4850 fn server_config_builder() {
4851 let config = ServerConfig::new("0.0.0.0:3000")
4852 .with_request_timeout_secs(60)
4853 .with_max_connections(1000)
4854 .with_tcp_nodelay(false)
4855 .with_allowed_hosts(["example.com", "api.example.com"])
4856 .with_trust_x_forwarded_host(true);
4857
4858 assert_eq!(config.bind_addr, "0.0.0.0:3000");
4859 assert_eq!(config.request_timeout, Time::from_secs(60));
4860 assert_eq!(config.max_connections, 1000);
4861 assert!(!config.tcp_nodelay);
4862 assert_eq!(config.allowed_hosts.len(), 2);
4863 assert!(config.trust_x_forwarded_host);
4864 }
4865
4866 #[test]
4867 fn server_config_defaults() {
4868 let config = ServerConfig::default();
4869 assert_eq!(config.bind_addr, "127.0.0.1:8080");
4870 assert_eq!(
4871 config.request_timeout,
4872 Time::from_secs(DEFAULT_REQUEST_TIMEOUT_SECS)
4873 );
4874 assert_eq!(config.max_connections, DEFAULT_MAX_CONNECTIONS);
4875 assert!(config.tcp_nodelay);
4876 assert!(config.allowed_hosts.is_empty());
4877 assert!(!config.trust_x_forwarded_host);
4878 }
4879
4880 #[test]
4881 fn tcp_server_creates_request_ids() {
4882 let server = TcpServer::default();
4883 let id1 = server.next_request_id();
4884 let id2 = server.next_request_id();
4885 let id3 = server.next_request_id();
4886
4887 assert_eq!(id1, 0);
4888 assert_eq!(id2, 1);
4889 assert_eq!(id3, 2);
4890 }
4891
4892 #[test]
4893 fn server_error_display() {
4894 let io_err = ServerError::Io(io::Error::new(io::ErrorKind::AddrInUse, "address in use"));
4895 assert!(io_err.to_string().contains("IO error"));
4896
4897 let shutdown_err = ServerError::Shutdown;
4898 assert_eq!(shutdown_err.to_string(), "Server shutdown");
4899
4900 let limit_err = ServerError::ConnectionLimitReached;
4901 assert_eq!(limit_err.to_string(), "Connection limit reached");
4902 }
4903
4904 #[test]
4905 fn sync_server_parses_request() {
4906 let server = Server::new();
4907 let request = b"GET /hello HTTP/1.1\r\nHost: localhost\r\n\r\n";
4908 let result = server.parse_request(request);
4909 assert!(result.is_ok());
4910 }
4911
4912 #[test]
4913 fn window_update_payload_validation_accepts_non_zero_increment() {
4914 let payload = 1u32.to_be_bytes();
4915 assert!(validate_window_update_payload(&payload).is_ok());
4916 }
4917
4918 #[test]
4919 fn window_update_payload_validation_rejects_bad_length() {
4920 let err = validate_window_update_payload(&[0, 0, 0]).unwrap_err();
4921 assert!(
4922 err.to_string()
4923 .contains("WINDOW_UPDATE payload must be 4 bytes")
4924 );
4925 }
4926
4927 #[test]
4928 fn window_update_payload_validation_rejects_zero_increment() {
4929 let payload = 0u32.to_be_bytes();
4930 let err = validate_window_update_payload(&payload).unwrap_err();
4931 assert!(
4932 err.to_string()
4933 .contains("WINDOW_UPDATE increment must be non-zero")
4934 );
4935 }
4936
4937 #[test]
4938 fn settings_frame_validation_accepts_non_ack_payload() {
4939 let payload = [0u8; 6];
4940 let is_ack = validate_settings_frame(0, 0, &payload).unwrap();
4941 assert!(!is_ack);
4942 }
4943
4944 #[test]
4945 fn settings_frame_validation_accepts_empty_ack_payload() {
4946 let is_ack = validate_settings_frame(0, 0x1, &[]).unwrap();
4947 assert!(is_ack);
4948 }
4949
4950 #[test]
4951 fn settings_frame_validation_rejects_non_zero_stream() {
4952 let err = validate_settings_frame(1, 0, &[]).unwrap_err();
4953 assert!(err.to_string().contains("SETTINGS must be on stream 0"));
4954 }
4955
4956 #[test]
4957 fn settings_frame_validation_rejects_non_empty_ack_payload() {
4958 let err = validate_settings_frame(0, 0x1, &[0, 0, 0, 0, 0, 0]).unwrap_err();
4959 assert!(
4960 err.to_string()
4961 .contains("SETTINGS ACK frame must have empty payload")
4962 );
4963 }
4964
4965 #[test]
4966 fn settings_enable_push_accepts_zero() {
4967 let payload = [0x00, 0x02, 0x00, 0x00, 0x00, 0x00];
4969 let mut hpack = http2::HpackDecoder::new();
4970 let mut max_frame_size = 16384u32;
4971 assert!(apply_http2_settings(&mut hpack, &mut max_frame_size, &payload).is_ok());
4972 }
4973
4974 #[test]
4975 fn settings_enable_push_accepts_one() {
4976 let payload = [0x00, 0x02, 0x00, 0x00, 0x00, 0x01];
4977 let mut hpack = http2::HpackDecoder::new();
4978 let mut max_frame_size = 16384u32;
4979 assert!(apply_http2_settings(&mut hpack, &mut max_frame_size, &payload).is_ok());
4980 }
4981
4982 #[test]
4983 fn settings_enable_push_rejects_invalid_value() {
4984 let payload = [0x00, 0x02, 0x00, 0x00, 0x00, 0x02];
4985 let mut hpack = http2::HpackDecoder::new();
4986 let mut max_frame_size = 16384u32;
4987 let err = apply_http2_settings(&mut hpack, &mut max_frame_size, &payload).unwrap_err();
4988 assert!(
4989 err.to_string()
4990 .contains("SETTINGS_ENABLE_PUSH must be 0 or 1")
4991 );
4992 }
4993
4994 #[test]
4995 fn settings_max_concurrent_streams_is_informational() {
4996 let payload = [0x00, 0x03, 0xFF, 0xFF, 0xFF, 0xFF];
4997 let mut hpack = http2::HpackDecoder::new();
4998 let mut max_frame_size = 16_384u32;
4999 let mut flow_control = http2::H2FlowControl::new();
5000 flow_control.set_initial_window_size(12_345);
5001 flow_control.set_peer_initial_window_size(23_456);
5002
5003 apply_http2_settings_with_fc(
5004 &mut hpack,
5005 &mut max_frame_size,
5006 Some(&mut flow_control),
5007 &payload,
5008 )
5009 .expect("SETTINGS_MAX_CONCURRENT_STREAMS is informational");
5010
5011 assert_eq!(flow_control.initial_window_size(), 12_345);
5012 assert_eq!(flow_control.peer_initial_window_size(), 23_456);
5013 assert_eq!(max_frame_size, 16_384);
5014 }
5015
5016 #[test]
5017 fn settings_initial_window_size_updates_peer_send_window_only() {
5018 let payload = [0x00, 0x04, 0x00, 0x01, 0x11, 0x70]; let mut hpack = http2::HpackDecoder::new();
5020 let mut max_frame_size = 16_384u32;
5021 let mut flow_control = http2::H2FlowControl::new();
5022 flow_control.set_initial_window_size(12_345);
5023
5024 apply_http2_settings_with_fc(
5025 &mut hpack,
5026 &mut max_frame_size,
5027 Some(&mut flow_control),
5028 &payload,
5029 )
5030 .expect("valid SETTINGS_INITIAL_WINDOW_SIZE should apply");
5031
5032 assert_eq!(
5033 flow_control.initial_window_size(),
5034 12_345,
5035 "peer settings must not alter the server receive threshold"
5036 );
5037 assert_eq!(flow_control.peer_initial_window_size(), 70_000);
5038 }
5039
5040 #[test]
5041 fn settings_initial_window_size_rejects_value_above_maximum() {
5042 let payload = [0x00, 0x04, 0x80, 0x00, 0x00, 0x00];
5043 let mut hpack = http2::HpackDecoder::new();
5044 let mut max_frame_size = 16_384u32;
5045 let mut flow_control = http2::H2FlowControl::new();
5046
5047 let err = apply_http2_settings_with_fc(
5048 &mut hpack,
5049 &mut max_frame_size,
5050 Some(&mut flow_control),
5051 &payload,
5052 )
5053 .expect_err("SETTINGS_INITIAL_WINDOW_SIZE above 2^31 - 1 must fail");
5054
5055 assert!(
5056 err.to_string()
5057 .contains("SETTINGS_INITIAL_WINDOW_SIZE exceeds maximum")
5058 );
5059 assert_eq!(
5060 flow_control.peer_initial_window_size(),
5061 http2::DEFAULT_INITIAL_WINDOW_SIZE
5062 );
5063 }
5064
5065 #[test]
5066 fn rst_stream_payload_validation_accepts_valid_payload() {
5067 let payload = 8u32.to_be_bytes();
5068 assert!(validate_rst_stream_payload(1, &payload).is_ok());
5069 }
5070
5071 #[test]
5072 fn rst_stream_payload_validation_rejects_stream_zero() {
5073 let payload = 8u32.to_be_bytes();
5074 let err = validate_rst_stream_payload(0, &payload).unwrap_err();
5075 assert!(
5076 err.to_string()
5077 .contains("RST_STREAM must not be on stream 0")
5078 );
5079 }
5080
5081 #[test]
5082 fn rst_stream_payload_validation_rejects_bad_length() {
5083 let err = validate_rst_stream_payload(1, &[0, 0, 0]).unwrap_err();
5084 assert!(
5085 err.to_string()
5086 .contains("RST_STREAM payload must be 4 bytes")
5087 );
5088 }
5089
5090 #[test]
5091 fn priority_payload_validation_accepts_valid_priority() {
5092 let payload = [0, 0, 0, 0, 16];
5093 assert!(validate_priority_payload(1, &payload).is_ok());
5094 }
5095
5096 #[test]
5097 fn priority_payload_validation_rejects_stream_zero() {
5098 let payload = [0, 0, 0, 0, 16];
5099 let err = validate_priority_payload(0, &payload).unwrap_err();
5100 assert!(err.to_string().contains("PRIORITY must not be on stream 0"));
5101 }
5102
5103 #[test]
5104 fn priority_payload_validation_rejects_bad_length() {
5105 let err = validate_priority_payload(1, &[0, 0, 0, 0]).unwrap_err();
5106 assert!(err.to_string().contains("PRIORITY payload must be 5 bytes"));
5107 }
5108
5109 #[test]
5110 fn priority_payload_validation_rejects_self_dependency() {
5111 let payload = 1u32.to_be_bytes();
5112 let mut with_weight = [0u8; 5];
5113 with_weight[..4].copy_from_slice(&payload);
5114 with_weight[4] = 16;
5115 let err = validate_priority_payload(1, &with_weight).unwrap_err();
5116 assert!(
5117 err.to_string()
5118 .contains("PRIORITY stream dependency must not reference itself")
5119 );
5120 }
5121
5122 #[test]
5123 fn goaway_payload_validation_accepts_valid_payload() {
5124 let payload = goaway_payload(0, 0);
5125 assert!(validate_goaway_payload(&payload).is_ok());
5126 }
5127
5128 #[test]
5129 fn goaway_payload_validation_accepts_payload_with_debug_data() {
5130 let mut payload = Vec::from(goaway_payload(1, 0).as_slice());
5131 payload.extend_from_slice(b"debug info");
5132 assert!(validate_goaway_payload(&payload).is_ok());
5133 }
5134
5135 #[test]
5136 fn goaway_payload_validation_rejects_short_payload() {
5137 let err = validate_goaway_payload(&[0, 0, 0]).unwrap_err();
5138 assert!(
5139 err.to_string()
5140 .contains("GOAWAY payload must be at least 8 bytes")
5141 );
5142 }
5143
5144 #[test]
5145 fn goaway_payload_validation_rejects_empty() {
5146 let err = validate_goaway_payload(&[]).unwrap_err();
5147 assert!(
5148 err.to_string()
5149 .contains("GOAWAY payload must be at least 8 bytes")
5150 );
5151 }
5152
5153 fn h2_test_frame(
5154 frame_type: http2::FrameType,
5155 stream_id: u32,
5156 payload: Vec<u8>,
5157 ) -> http2::Frame {
5158 http2::Frame {
5159 header: http2::FrameHeader {
5160 length: payload.len() as u32,
5161 frame_type: frame_type as u8,
5162 flags: 0,
5163 stream_id,
5164 },
5165 payload,
5166 }
5167 }
5168
5169 #[test]
5170 fn h2_idle_frame_rejects_data_outside_request_stream() {
5171 let frame = h2_test_frame(http2::FrameType::Data, 1, Vec::new());
5172 let err = handle_h2_idle_frame(&frame).unwrap_err();
5173 assert!(
5174 err.to_string()
5175 .contains("unexpected DATA frame outside active request stream")
5176 );
5177 }
5178
5179 #[test]
5180 fn h2_idle_frame_rejects_continuation_outside_header_block() {
5181 let frame = h2_test_frame(http2::FrameType::Continuation, 1, Vec::new());
5182 let err = handle_h2_idle_frame(&frame).unwrap_err();
5183 assert!(
5184 err.to_string()
5185 .contains("unexpected CONTINUATION frame outside header block")
5186 );
5187 }
5188
5189 #[test]
5190 fn h2_idle_frame_validates_rst_stream_payload() {
5191 let invalid = h2_test_frame(http2::FrameType::RstStream, 0, 8u32.to_be_bytes().to_vec());
5192 let err = handle_h2_idle_frame(&invalid).unwrap_err();
5193 assert!(
5194 err.to_string()
5195 .contains("RST_STREAM must not be on stream 0")
5196 );
5197
5198 let valid = h2_test_frame(http2::FrameType::RstStream, 3, 8u32.to_be_bytes().to_vec());
5199 assert!(handle_h2_idle_frame(&valid).is_ok());
5200 }
5201
5202 #[test]
5203 fn h2_idle_frame_validates_priority_payload() {
5204 let invalid = h2_test_frame(http2::FrameType::Priority, 0, vec![0, 0, 0, 0, 16]);
5205 let err = handle_h2_idle_frame(&invalid).unwrap_err();
5206 assert!(err.to_string().contains("PRIORITY must not be on stream 0"));
5207
5208 let valid = h2_test_frame(http2::FrameType::Priority, 1, vec![0, 0, 0, 0, 16]);
5209 assert!(handle_h2_idle_frame(&valid).is_ok());
5210 }
5211
5212 #[test]
5213 fn max_header_block_size_is_128k() {
5214 assert_eq!(MAX_HEADER_BLOCK_SIZE, 128 * 1024);
5215 }
5216
5217 #[test]
5218 fn server_settings_payload_advertises_max_concurrent_streams() {
5219 assert_eq!(SERVER_SETTINGS_PAYLOAD.len(), 6);
5221 assert_eq!(SERVER_SETTINGS_PAYLOAD[0..2], [0x00, 0x03]);
5222 assert_eq!(
5223 u32::from_be_bytes([
5224 SERVER_SETTINGS_PAYLOAD[2],
5225 SERVER_SETTINGS_PAYLOAD[3],
5226 SERVER_SETTINGS_PAYLOAD[4],
5227 SERVER_SETTINGS_PAYLOAD[5],
5228 ]),
5229 1
5230 );
5231 }
5232
5233 #[test]
5234 fn max_hpack_table_size_is_64k() {
5235 assert_eq!(MAX_HPACK_TABLE_SIZE, 64 * 1024);
5236 }
5237
5238 #[test]
5239 fn h2_send_window_update_ignores_other_streams() {
5240 let mut flow_control = http2::H2FlowControl::new();
5241 let mut stream_window = 123i64;
5242 let payload = 7u32.to_be_bytes();
5243
5244 apply_peer_window_update_for_send(&mut flow_control, &mut stream_window, 3, 5, &payload)
5245 .expect("window update on different stream should be ignored");
5246
5247 assert_eq!(stream_window, 123);
5248 }
5249
5250 #[test]
5251 fn h2_send_window_update_applies_connection_and_current_stream() {
5252 let mut flow_control = http2::H2FlowControl::new();
5253 let mut stream_window = 10i64;
5254
5255 let conn_before = flow_control.send_conn_window();
5256 let conn_payload = 11u32.to_be_bytes();
5257 apply_peer_window_update_for_send(
5258 &mut flow_control,
5259 &mut stream_window,
5260 9,
5261 0,
5262 &conn_payload,
5263 )
5264 .expect("connection window update should be applied");
5265 assert_eq!(flow_control.send_conn_window(), conn_before + 11);
5266 assert_eq!(stream_window, 10);
5267
5268 let stream_payload = 13u32.to_be_bytes();
5269 apply_peer_window_update_for_send(
5270 &mut flow_control,
5271 &mut stream_window,
5272 9,
5273 9,
5274 &stream_payload,
5275 )
5276 .expect("stream window update should be applied to current stream");
5277 assert_eq!(stream_window, 23);
5278 }
5279
5280 #[test]
5281 fn h2_send_settings_updates_current_stream_window_delta() {
5282 let mut flow_control = http2::H2FlowControl::new();
5283 let mut stream_window = 50i64;
5284 let mut peer_max_frame_size = 16_384u32;
5285
5286 let payload = [0x00, 0x04, 0x00, 0x01, 0x11, 0x70]; apply_peer_settings_for_send(
5288 &mut flow_control,
5289 &mut stream_window,
5290 &mut peer_max_frame_size,
5291 &payload,
5292 )
5293 .expect("valid SETTINGS_INITIAL_WINDOW_SIZE should apply");
5294
5295 assert_eq!(flow_control.peer_initial_window_size(), 70_000);
5296 assert_eq!(stream_window, 4_515); assert_eq!(peer_max_frame_size, 16_384);
5298 }
5299
5300 #[test]
5301 fn h2_send_settings_rejects_invalid_payload_len() {
5302 let mut flow_control = http2::H2FlowControl::new();
5303 let mut stream_window = 0i64;
5304 let mut peer_max_frame_size = 16_384u32;
5305 let err = apply_peer_settings_for_send(
5306 &mut flow_control,
5307 &mut stream_window,
5308 &mut peer_max_frame_size,
5309 &[0, 1, 2],
5310 )
5311 .unwrap_err();
5312 assert!(
5313 err.to_string()
5314 .contains("SETTINGS length must be a multiple of 6")
5315 );
5316 }
5317
5318 #[test]
5319 fn h2_send_settings_rejects_initial_window_too_large() {
5320 let mut flow_control = http2::H2FlowControl::new();
5321 let mut stream_window = 0i64;
5322 let mut peer_max_frame_size = 16_384u32;
5323 let payload = [0x00, 0x04, 0x80, 0x00, 0x00, 0x00]; let err = apply_peer_settings_for_send(
5325 &mut flow_control,
5326 &mut stream_window,
5327 &mut peer_max_frame_size,
5328 &payload,
5329 )
5330 .unwrap_err();
5331 assert!(
5332 err.to_string()
5333 .contains("SETTINGS_INITIAL_WINDOW_SIZE exceeds maximum")
5334 );
5335 }
5336
5337 #[test]
5338 fn h2_send_settings_window_delta_overflow_is_flow_control_error() {
5339 let mut flow_control = http2::H2FlowControl::new();
5340 let mut peer_max_frame_size = 16_384u32;
5341 let mut stream_window: i64 = 0x7FFF_FFFF - 10;
5343 let new_initial: u32 = 0x7FFF_FFFF;
5347 let payload = [
5348 0x00,
5349 0x04,
5350 new_initial.to_be_bytes()[0],
5351 new_initial.to_be_bytes()[1],
5352 new_initial.to_be_bytes()[2],
5353 new_initial.to_be_bytes()[3],
5354 ];
5355 let err = apply_peer_settings_for_send(
5356 &mut flow_control,
5357 &mut stream_window,
5358 &mut peer_max_frame_size,
5359 &payload,
5360 )
5361 .unwrap_err();
5362 assert!(err.to_string().contains("stream window to exceed 2^31-1"));
5363 }
5364
5365 #[test]
5366 fn h2_send_settings_updates_peer_max_frame_size() {
5367 let mut flow_control = http2::H2FlowControl::new();
5368 let mut stream_window = 0i64;
5369 let mut peer_max_frame_size = 65_535u32;
5370 let payload = [0x00, 0x05, 0x00, 0x00, 0x40, 0x00]; apply_peer_settings_for_send(
5373 &mut flow_control,
5374 &mut stream_window,
5375 &mut peer_max_frame_size,
5376 &payload,
5377 )
5378 .expect("valid SETTINGS_MAX_FRAME_SIZE should apply");
5379
5380 assert_eq!(peer_max_frame_size, 16_384);
5381 }
5382
5383 #[test]
5384 fn h2_send_settings_rejects_invalid_max_frame_size() {
5385 let mut flow_control = http2::H2FlowControl::new();
5386 let mut stream_window = 0i64;
5387 let mut peer_max_frame_size = 16_384u32;
5388 let payload = [0x00, 0x05, 0x00, 0x00, 0x3F, 0xFF]; let err = apply_peer_settings_for_send(
5391 &mut flow_control,
5392 &mut stream_window,
5393 &mut peer_max_frame_size,
5394 &payload,
5395 )
5396 .unwrap_err();
5397 assert!(err.to_string().contains("invalid SETTINGS_MAX_FRAME_SIZE"));
5398 }
5399
5400 #[test]
5401 fn request_from_h2_headers_rejects_unknown_pseudo_header() {
5402 let headers: http2::HeaderList = vec![
5403 (b":method".to_vec(), b"GET".to_vec()),
5404 (b":path".to_vec(), b"/".to_vec()),
5405 (b":weird".to_vec(), b"value".to_vec()),
5406 ];
5407 let err = request_from_h2_headers(headers).unwrap_err();
5408 assert!(err.to_string().contains("unknown pseudo-header"));
5409 }
5410
5411 #[test]
5412 fn request_from_h2_headers_rejects_pseudo_after_regular_header() {
5413 let headers: http2::HeaderList = vec![
5414 (b":method".to_vec(), b"GET".to_vec()),
5415 (b":path".to_vec(), b"/".to_vec()),
5416 (b"x-test".to_vec(), b"ok".to_vec()),
5417 (b":authority".to_vec(), b"example.com".to_vec()),
5418 ];
5419 let err = request_from_h2_headers(headers).unwrap_err();
5420 assert!(
5421 err.to_string()
5422 .contains("pseudo-headers must appear before regular headers")
5423 );
5424 }
5425
5426 #[test]
5431 fn host_validation_missing_host_rejected() {
5432 let config = ServerConfig::default();
5433 let request = Request::new(fastapi_core::Method::Get, "/");
5434 let err = validate_host_header(&request, &config).unwrap_err();
5435 assert_eq!(err.kind, HostValidationErrorKind::Missing);
5436 assert_eq!(err.response().status().as_u16(), 400);
5437 }
5438
5439 #[test]
5440 fn host_validation_allows_configured_host() {
5441 let config = ServerConfig::default().with_allowed_hosts(["example.com"]);
5442 let mut request = Request::new(fastapi_core::Method::Get, "/");
5443 request
5444 .headers_mut()
5445 .insert("Host".to_string(), b"example.com".to_vec());
5446 assert!(validate_host_header(&request, &config).is_ok());
5447 }
5448
5449 #[test]
5450 fn host_validation_rejects_disallowed_host() {
5451 let config = ServerConfig::default().with_allowed_hosts(["example.com"]);
5452 let mut request = Request::new(fastapi_core::Method::Get, "/");
5453 request
5454 .headers_mut()
5455 .insert("Host".to_string(), b"evil.com".to_vec());
5456 let err = validate_host_header(&request, &config).unwrap_err();
5457 assert_eq!(err.kind, HostValidationErrorKind::NotAllowed);
5458 }
5459
5460 #[test]
5461 fn host_validation_wildcard_allows_subdomains_only() {
5462 let config = ServerConfig::default().with_allowed_hosts(["*.example.com"]);
5463 let mut request = Request::new(fastapi_core::Method::Get, "/");
5464 request
5465 .headers_mut()
5466 .insert("Host".to_string(), b"api.example.com".to_vec());
5467 assert!(validate_host_header(&request, &config).is_ok());
5468
5469 let mut request = Request::new(fastapi_core::Method::Get, "/");
5470 request
5471 .headers_mut()
5472 .insert("Host".to_string(), b"example.com".to_vec());
5473 let err = validate_host_header(&request, &config).unwrap_err();
5474 assert_eq!(err.kind, HostValidationErrorKind::NotAllowed);
5475 }
5476
5477 #[test]
5478 fn host_validation_uses_x_forwarded_host_when_trusted() {
5479 let config = ServerConfig::default()
5480 .with_allowed_hosts(["example.com"])
5481 .with_trust_x_forwarded_host(true);
5482 let mut request = Request::new(fastapi_core::Method::Get, "/");
5483 request
5484 .headers_mut()
5485 .insert("Host".to_string(), b"internal.local".to_vec());
5486 request
5487 .headers_mut()
5488 .insert("X-Forwarded-Host".to_string(), b"example.com".to_vec());
5489 assert!(validate_host_header(&request, &config).is_ok());
5490 }
5491
5492 #[test]
5493 fn host_validation_rejects_invalid_host_value() {
5494 let config = ServerConfig::default();
5495 let mut request = Request::new(fastapi_core::Method::Get, "/");
5496 request
5497 .headers_mut()
5498 .insert("Host".to_string(), b"bad host".to_vec());
5499 let err = validate_host_header(&request, &config).unwrap_err();
5500 assert_eq!(err.kind, HostValidationErrorKind::Invalid);
5501 }
5502
5503 #[test]
5508 fn websocket_upgrade_detection_accepts_token_lists_case_insensitive() {
5509 let mut request = Request::new(fastapi_core::Method::Get, "/ws");
5510 request
5511 .headers_mut()
5512 .insert("Upgrade".to_string(), b"h2c, WebSocket".to_vec());
5513 request
5514 .headers_mut()
5515 .insert("Connection".to_string(), b"keep-alive, UPGRADE".to_vec());
5516
5517 assert!(is_websocket_upgrade_request(&request));
5518 }
5519
5520 #[test]
5521 fn websocket_upgrade_detection_rejects_missing_connection_upgrade_token() {
5522 let mut request = Request::new(fastapi_core::Method::Get, "/ws");
5523 request
5524 .headers_mut()
5525 .insert("Upgrade".to_string(), b"websocket".to_vec());
5526 request
5527 .headers_mut()
5528 .insert("Connection".to_string(), b"keep-alive".to_vec());
5529
5530 assert!(!is_websocket_upgrade_request(&request));
5531 }
5532
5533 #[test]
5534 fn websocket_upgrade_detection_rejects_non_get_method() {
5535 let mut request = Request::new(fastapi_core::Method::Post, "/ws");
5536 request
5537 .headers_mut()
5538 .insert("Upgrade".to_string(), b"websocket".to_vec());
5539 request
5540 .headers_mut()
5541 .insert("Connection".to_string(), b"upgrade".to_vec());
5542
5543 assert!(!is_websocket_upgrade_request(&request));
5544 }
5545
5546 #[test]
5551 fn keep_alive_default_http11() {
5552 let mut request = Request::new(fastapi_core::Method::Get, "/path".to_string());
5554 request
5555 .headers_mut()
5556 .insert("Host".to_string(), b"example.com".to_vec());
5557 assert!(should_keep_alive(&request));
5558 }
5559
5560 #[test]
5561 fn keep_alive_explicit_keep_alive() {
5562 let mut request = Request::new(fastapi_core::Method::Get, "/path".to_string());
5563 request
5564 .headers_mut()
5565 .insert("Connection".to_string(), b"keep-alive".to_vec());
5566 assert!(should_keep_alive(&request));
5567 }
5568
5569 #[test]
5570 fn keep_alive_connection_close() {
5571 let mut request = Request::new(fastapi_core::Method::Get, "/path".to_string());
5572 request
5573 .headers_mut()
5574 .insert("Connection".to_string(), b"close".to_vec());
5575 assert!(!should_keep_alive(&request));
5576 }
5577
5578 #[test]
5579 fn keep_alive_connection_close_case_insensitive() {
5580 let mut request = Request::new(fastapi_core::Method::Get, "/path".to_string());
5581 request
5582 .headers_mut()
5583 .insert("Connection".to_string(), b"CLOSE".to_vec());
5584 assert!(!should_keep_alive(&request));
5585 }
5586
5587 #[test]
5588 fn keep_alive_multiple_values() {
5589 let mut request = Request::new(fastapi_core::Method::Get, "/path".to_string());
5590 request
5591 .headers_mut()
5592 .insert("Connection".to_string(), b"keep-alive, upgrade".to_vec());
5593 assert!(should_keep_alive(&request));
5594 }
5595
5596 #[test]
5601 fn timeout_budget_created_relative_to_current_time() {
5602 let config = ServerConfig::new("127.0.0.1:8080").with_request_timeout_secs(45);
5603 let budget = Budget::new().with_deadline(request_deadline_at(
5604 Time::from_secs(90),
5605 config.request_timeout,
5606 ));
5607 assert_eq!(budget.deadline, Some(Time::from_secs(135)));
5608 }
5609
5610 #[test]
5611 fn timeout_duration_conversion_from_time() {
5612 let timeout = Time::from_secs(30);
5613 let duration = Duration::from_nanos(timeout.as_nanos());
5614 assert_eq!(duration, Duration::from_secs(30));
5615 }
5616
5617 #[test]
5618 fn timeout_duration_conversion_from_time_millis() {
5619 let timeout = Time::from_millis(1500);
5620 let duration = Duration::from_nanos(timeout.as_nanos());
5621 assert_eq!(duration, Duration::from_millis(1500));
5622 }
5623
5624 #[test]
5625 fn gateway_timeout_response_has_correct_status() {
5626 let response = Response::with_status(StatusCode::GATEWAY_TIMEOUT);
5627 assert_eq!(response.status().as_u16(), 504);
5628 }
5629
5630 #[test]
5631 fn gateway_timeout_response_with_body() {
5632 let response = Response::with_status(StatusCode::GATEWAY_TIMEOUT).body(
5633 fastapi_core::ResponseBody::Bytes(b"Request timed out".to_vec()),
5634 );
5635 assert_eq!(response.status().as_u16(), 504);
5636 assert!(response.body_ref().len() > 0);
5638 }
5639
5640 #[test]
5641 fn elapsed_time_check_logic() {
5642 let start = Instant::now();
5644 let timeout_duration = Duration::from_millis(10);
5645
5646 assert!(start.elapsed() <= timeout_duration);
5648
5649 std::thread::sleep(Duration::from_millis(20));
5651
5652 assert!(start.elapsed() > timeout_duration);
5654 }
5655
5656 #[test]
5661 fn connection_counter_starts_at_zero() {
5662 let server = TcpServer::default();
5663 assert_eq!(server.current_connections(), 0);
5664 }
5665
5666 #[test]
5667 fn try_acquire_connection_unlimited() {
5668 let server = TcpServer::default();
5670 assert_eq!(server.config().max_connections, 0);
5671
5672 for _ in 0..100 {
5674 assert!(server.try_acquire_connection());
5675 }
5676 assert_eq!(server.current_connections(), 100);
5677
5678 for _ in 0..100 {
5680 server.release_connection();
5681 }
5682 assert_eq!(server.current_connections(), 0);
5683 }
5684
5685 #[test]
5686 fn try_acquire_connection_with_limit() {
5687 let config = ServerConfig::new("127.0.0.1:8080").with_max_connections(5);
5688 let server = TcpServer::new(config);
5689
5690 for i in 0..5 {
5692 assert!(
5693 server.try_acquire_connection(),
5694 "Should acquire connection {i}"
5695 );
5696 }
5697 assert_eq!(server.current_connections(), 5);
5698
5699 assert!(!server.try_acquire_connection());
5701 assert_eq!(server.current_connections(), 5);
5702
5703 server.release_connection();
5705 assert_eq!(server.current_connections(), 4);
5706
5707 assert!(server.try_acquire_connection());
5709 assert_eq!(server.current_connections(), 5);
5710 }
5711
5712 #[test]
5713 fn try_acquire_connection_single_connection_limit() {
5714 let config = ServerConfig::new("127.0.0.1:8080").with_max_connections(1);
5715 let server = TcpServer::new(config);
5716
5717 assert!(server.try_acquire_connection());
5719 assert_eq!(server.current_connections(), 1);
5720
5721 assert!(!server.try_acquire_connection());
5723 assert_eq!(server.current_connections(), 1);
5724
5725 server.release_connection();
5727 assert!(server.try_acquire_connection());
5728 }
5729
5730 #[test]
5731 fn app_connection_task_clone_shares_counters_but_not_handle_registry() {
5732 let server = TcpServer::new(ServerConfig::new("127.0.0.1:0").with_max_connections(4));
5733
5734 assert!(server.try_acquire_connection());
5735 let task_server = server.clone_for_connection_task();
5736
5737 assert_eq!(task_server.current_connections(), 1);
5738 assert_eq!(server.current_connections(), 1);
5739 assert_eq!(task_server.metrics().total_accepted, 1);
5740 assert_eq!(
5741 task_server
5742 .connection_handles
5743 .lock()
5744 .expect("task handle registry should not be poisoned")
5745 .len(),
5746 0
5747 );
5748
5749 task_server.release_connection();
5750 assert_eq!(server.current_connections(), 0);
5751 }
5752
5753 #[test]
5754 fn service_unavailable_response_has_correct_status() {
5755 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE);
5756 assert_eq!(response.status().as_u16(), 503);
5757 }
5758
5759 #[test]
5760 fn service_unavailable_response_with_body() {
5761 let response = Response::with_status(StatusCode::SERVICE_UNAVAILABLE)
5762 .header("connection", b"close".to_vec())
5763 .body(fastapi_core::ResponseBody::Bytes(
5764 b"503 Service Unavailable: connection limit reached".to_vec(),
5765 ));
5766 assert_eq!(response.status().as_u16(), 503);
5767 assert!(response.body_ref().len() > 0);
5768 }
5769
5770 #[test]
5771 fn config_max_connections_default_is_zero() {
5772 let config = ServerConfig::default();
5773 assert_eq!(config.max_connections, 0);
5774 }
5775
5776 #[test]
5777 fn config_max_connections_can_be_set() {
5778 let config = ServerConfig::new("127.0.0.1:8080").with_max_connections(100);
5779 assert_eq!(config.max_connections, 100);
5780 }
5781
5782 #[test]
5787 fn config_keep_alive_timeout_default() {
5788 let config = ServerConfig::default();
5789 assert_eq!(
5790 config.keep_alive_timeout,
5791 Duration::from_secs(DEFAULT_KEEP_ALIVE_TIMEOUT_SECS)
5792 );
5793 }
5794
5795 #[test]
5796 fn config_keep_alive_timeout_can_be_set() {
5797 let config =
5798 ServerConfig::new("127.0.0.1:8080").with_keep_alive_timeout(Duration::from_secs(120));
5799 assert_eq!(config.keep_alive_timeout, Duration::from_secs(120));
5800 }
5801
5802 #[test]
5803 fn config_keep_alive_timeout_can_be_set_secs() {
5804 let config = ServerConfig::new("127.0.0.1:8080").with_keep_alive_timeout_secs(90);
5805 assert_eq!(config.keep_alive_timeout, Duration::from_secs(90));
5806 }
5807
5808 #[test]
5809 fn config_max_requests_per_connection_default() {
5810 let config = ServerConfig::default();
5811 assert_eq!(
5812 config.max_requests_per_connection,
5813 DEFAULT_MAX_REQUESTS_PER_CONNECTION
5814 );
5815 }
5816
5817 #[test]
5818 fn config_max_requests_per_connection_can_be_set() {
5819 let config = ServerConfig::new("127.0.0.1:8080").with_max_requests_per_connection(50);
5820 assert_eq!(config.max_requests_per_connection, 50);
5821 }
5822
5823 #[test]
5824 fn config_max_requests_per_connection_unlimited() {
5825 let config = ServerConfig::new("127.0.0.1:8080").with_max_requests_per_connection(0);
5826 assert_eq!(config.max_requests_per_connection, 0);
5827 }
5828
5829 #[test]
5830 fn response_with_keep_alive_header() {
5831 let response = Response::ok().header("connection", b"keep-alive".to_vec());
5832 let headers = response.headers();
5833 let connection_header = headers
5834 .iter()
5835 .find(|(name, _)| name.eq_ignore_ascii_case("connection"));
5836 assert!(connection_header.is_some());
5837 assert_eq!(connection_header.unwrap().1, b"keep-alive");
5838 }
5839
5840 #[test]
5841 fn response_with_close_header() {
5842 let response = Response::ok().header("connection", b"close".to_vec());
5843 let headers = response.headers();
5844 let connection_header = headers
5845 .iter()
5846 .find(|(name, _)| name.eq_ignore_ascii_case("connection"));
5847 assert!(connection_header.is_some());
5848 assert_eq!(connection_header.unwrap().1, b"close");
5849 }
5850
5851 #[test]
5856 fn config_drain_timeout_default() {
5857 let config = ServerConfig::default();
5858 assert_eq!(
5859 config.drain_timeout,
5860 Duration::from_secs(DEFAULT_DRAIN_TIMEOUT_SECS)
5861 );
5862 }
5863
5864 #[test]
5865 fn config_drain_timeout_can_be_set() {
5866 let config =
5867 ServerConfig::new("127.0.0.1:8080").with_drain_timeout(Duration::from_secs(60));
5868 assert_eq!(config.drain_timeout, Duration::from_secs(60));
5869 }
5870
5871 #[test]
5872 fn config_drain_timeout_can_be_set_secs() {
5873 let config = ServerConfig::new("127.0.0.1:8080").with_drain_timeout_secs(45);
5874 assert_eq!(config.drain_timeout, Duration::from_secs(45));
5875 }
5876
5877 #[test]
5878 fn server_not_draining_initially() {
5879 let server = TcpServer::default();
5880 assert!(!server.is_draining());
5881 }
5882
5883 #[test]
5884 fn server_start_drain_sets_flag() {
5885 let server = TcpServer::default();
5886 assert!(!server.is_draining());
5887 server.start_drain();
5888 assert!(server.is_draining());
5889 }
5890
5891 #[test]
5892 fn server_start_drain_idempotent() {
5893 let server = TcpServer::default();
5894 server.start_drain();
5895 assert!(server.is_draining());
5896 server.start_drain();
5897 assert!(server.is_draining());
5898 }
5899
5900 #[test]
5901 fn wait_for_drain_returns_true_when_no_connections() {
5902 block_on(async {
5903 let server = TcpServer::default();
5904 assert_eq!(server.current_connections(), 0);
5905 let result = server
5906 .wait_for_drain(Duration::from_millis(100), Some(Duration::from_millis(1)))
5907 .await;
5908 assert!(result);
5909 });
5910 }
5911
5912 #[test]
5913 fn wait_for_drain_timeout_with_connections() {
5914 block_on(async {
5915 let server = TcpServer::default();
5916 server.try_acquire_connection();
5918 server.try_acquire_connection();
5919 assert_eq!(server.current_connections(), 2);
5920
5921 let result = server
5923 .wait_for_drain(Duration::from_millis(50), Some(Duration::from_millis(5)))
5924 .await;
5925 assert!(!result);
5926 assert_eq!(server.current_connections(), 2);
5927 });
5928 }
5929
5930 #[test]
5931 fn drain_returns_zero_when_no_connections() {
5932 block_on(async {
5933 let server = TcpServer::new(
5934 ServerConfig::new("127.0.0.1:8080").with_drain_timeout(Duration::from_millis(100)),
5935 );
5936 assert_eq!(server.current_connections(), 0);
5937 let remaining = server.drain().await;
5938 assert_eq!(remaining, 0);
5939 assert!(server.is_draining());
5940 });
5941 }
5942
5943 #[test]
5944 fn drain_returns_count_when_connections_remain() {
5945 block_on(async {
5946 let server = TcpServer::new(
5947 ServerConfig::new("127.0.0.1:8080").with_drain_timeout(Duration::from_millis(50)),
5948 );
5949 server.try_acquire_connection();
5951 server.try_acquire_connection();
5952 server.try_acquire_connection();
5953
5954 let remaining = server.drain().await;
5955 assert_eq!(remaining, 3);
5956 assert!(server.is_draining());
5957 });
5958 }
5959
5960 #[test]
5961 fn cleanup_completed_handles_prunes_finished_runtime_tasks() {
5962 use std::sync::mpsc;
5963 use std::time::{Duration, Instant as StdInstant};
5964
5965 let runtime = asupersync::runtime::RuntimeBuilder::new()
5966 .worker_threads(2)
5967 .build()
5968 .expect("runtime build");
5969 let handle = runtime.handle();
5970 let server = TcpServer::default();
5971 let (tx, rx) = mpsc::sync_channel(1);
5972
5973 let join = handle.spawn(async move {
5974 tx.send(()).expect("completion signal should send");
5975 });
5976
5977 server
5978 .connection_handles
5979 .lock()
5980 .expect("connection handle mutex should not be poisoned")
5981 .push(join);
5982
5983 rx.recv_timeout(Duration::from_secs(5))
5984 .expect("spawned runtime task should complete");
5985
5986 let deadline = StdInstant::now() + Duration::from_secs(5);
5991 loop {
5992 if server
5993 .connection_handles
5994 .lock()
5995 .expect("connection handle mutex should not be poisoned")[0]
5996 .is_finished()
5997 {
5998 break;
5999 }
6000 assert!(
6001 StdInstant::now() < deadline,
6002 "JoinHandle should report completion after task exit"
6003 );
6004 std::thread::sleep(Duration::from_millis(10));
6005 }
6006
6007 block_on(async {
6008 server.cleanup_completed_handles(&Cx::for_testing()).await;
6009 });
6010
6011 let remaining = server
6012 .connection_handles
6013 .lock()
6014 .expect("connection handle mutex should not be poisoned")
6015 .len();
6016 assert_eq!(remaining, 0);
6017 }
6018
6019 #[test]
6020 fn cleanup_completed_handles_reaps_panicked_runtime_tasks_without_panicking() {
6021 use std::time::{Duration, Instant as StdInstant};
6022
6023 let runtime = asupersync::runtime::RuntimeBuilder::new()
6024 .worker_threads(2)
6025 .build()
6026 .expect("runtime build");
6027 let handle = runtime.handle();
6028 let server = TcpServer::default();
6029
6030 let join = handle.spawn(async move {
6031 panic!("intentional panic to verify cleanup panics are observed");
6032 });
6033
6034 server
6035 .connection_handles
6036 .lock()
6037 .expect("connection handle mutex should not be poisoned")
6038 .push(join);
6039
6040 let deadline = StdInstant::now() + Duration::from_secs(1);
6041 loop {
6042 let finished = server
6043 .connection_handles
6044 .lock()
6045 .expect("connection handle mutex should not be poisoned")[0]
6046 .is_finished();
6047 if finished {
6048 break;
6049 }
6050 assert!(
6051 StdInstant::now() < deadline,
6052 "panicking task should finish promptly"
6053 );
6054 std::thread::sleep(Duration::from_millis(10));
6055 }
6056
6057 block_on(async {
6058 server.cleanup_completed_handles(&Cx::for_testing()).await;
6059 });
6060
6061 let remaining = server
6062 .connection_handles
6063 .lock()
6064 .expect("connection handle mutex should not be poisoned")
6065 .len();
6066 assert_eq!(remaining, 0);
6067 }
6068
6069 #[test]
6070 fn connection_slot_guard_releases_counter_when_task_panics() {
6071 use std::time::{Duration, Instant as StdInstant};
6072
6073 let runtime = asupersync::runtime::RuntimeBuilder::new()
6074 .worker_threads(2)
6075 .build()
6076 .expect("runtime build");
6077 let handle = runtime.handle();
6078 let counter = Arc::new(AtomicU64::new(1));
6079
6080 let panic_task = handle.spawn({
6081 let counter = Arc::clone(&counter);
6082 async move {
6083 let _connection_slot = ConnectionSlotGuard::new(counter);
6084 panic!("intentional panic to verify connection slot cleanup");
6085 }
6086 });
6087
6088 let deadline = StdInstant::now() + Duration::from_secs(1);
6089 while !panic_task.is_finished() {
6090 assert!(
6091 StdInstant::now() < deadline,
6092 "panicing task should finish promptly"
6093 );
6094 std::thread::sleep(Duration::from_millis(10));
6095 }
6096
6097 assert_eq!(
6098 counter.load(Ordering::Relaxed),
6099 0,
6100 "connection slot must be released even when the task unwinds"
6101 );
6102 }
6103
6104 #[test]
6105 fn connection_slot_guard_releases_counter_when_future_drops_before_poll() {
6106 let counter = Arc::new(AtomicU64::new(1));
6107 let connection_slot = ConnectionSlotGuard::new(Arc::clone(&counter));
6108
6109 let future = async move {
6110 let _connection_slot = connection_slot;
6111 };
6112
6113 drop(future);
6114
6115 assert_eq!(
6116 counter.load(Ordering::Relaxed),
6117 0,
6118 "connection slot must be released even if the spawned future is dropped before polling"
6119 );
6120 }
6121
6122 #[test]
6123 fn serve_concurrent_shutdown_wakes_idle_accept_loop() {
6124 use std::time::{Duration, Instant as StdInstant};
6125
6126 let server = Arc::new(TcpServer::new(ServerConfig::new("127.0.0.1:0")));
6127 let server_for_thread = Arc::clone(&server);
6128
6129 let serve_thread = std::thread::spawn(move || {
6130 block_on(async {
6131 let cx = Cx::for_testing();
6132 server_for_thread
6133 .serve_concurrent(&cx, |_ctx, _req| async {
6134 Response::ok().body(fastapi_core::ResponseBody::Bytes(b"ok".to_vec()))
6135 })
6136 .await
6137 })
6138 });
6139
6140 std::thread::sleep(Duration::from_millis(100));
6141 server.shutdown();
6142
6143 let deadline = StdInstant::now() + Duration::from_secs(2);
6144 while !serve_thread.is_finished() {
6145 assert!(
6146 StdInstant::now() < deadline,
6147 "serve_concurrent should exit promptly after shutdown without a new connection"
6148 );
6149 std::thread::sleep(Duration::from_millis(20));
6150 }
6151
6152 let result = serve_thread
6153 .join()
6154 .expect("serve_concurrent regression thread should not panic");
6155 assert!(
6156 result.is_ok(),
6157 "serve_concurrent should stop cleanly on shutdown"
6158 );
6159 }
6160
6161 #[test]
6162 fn server_shutdown_error_display() {
6163 let err = ServerError::Shutdown;
6164 assert_eq!(err.to_string(), "Server shutdown");
6165 }
6166
6167 #[test]
6172 fn server_has_shutdown_controller() {
6173 let server = TcpServer::default();
6174 let controller = server.shutdown_controller();
6175 assert!(!controller.is_shutting_down());
6176 }
6177
6178 #[test]
6179 fn server_subscribe_shutdown_returns_receiver() {
6180 let server = TcpServer::default();
6181 let receiver = server.subscribe_shutdown();
6182 assert!(!receiver.is_shutting_down());
6183 }
6184
6185 #[test]
6186 fn server_shutdown_sets_draining_and_controller() {
6187 let server = TcpServer::default();
6188 assert!(!server.is_shutting_down());
6189 assert!(!server.is_draining());
6190 assert!(!server.shutdown_controller().is_shutting_down());
6191
6192 server.shutdown();
6193
6194 assert!(server.is_shutting_down());
6195 assert!(server.is_draining());
6196 assert!(server.shutdown_controller().is_shutting_down());
6197 }
6198
6199 #[test]
6200 fn server_shutdown_notifies_receivers() {
6201 let server = TcpServer::default();
6202 let receiver1 = server.subscribe_shutdown();
6203 let receiver2 = server.subscribe_shutdown();
6204
6205 assert!(!receiver1.is_shutting_down());
6206 assert!(!receiver2.is_shutting_down());
6207
6208 server.shutdown();
6209
6210 assert!(receiver1.is_shutting_down());
6211 assert!(receiver2.is_shutting_down());
6212 }
6213
6214 #[test]
6215 fn server_shutdown_is_idempotent() {
6216 let server = TcpServer::default();
6217 let receiver = server.subscribe_shutdown();
6218
6219 server.shutdown();
6220 server.shutdown();
6221 server.shutdown();
6222
6223 assert!(server.is_shutting_down());
6224 assert!(receiver.is_shutting_down());
6225 }
6226
6227 #[test]
6232 fn keep_alive_timeout_error_display() {
6233 let err = ServerError::KeepAliveTimeout;
6234 assert_eq!(err.to_string(), "Keep-alive timeout");
6235 }
6236
6237 #[test]
6238 fn keep_alive_timeout_zero_disables_timeout() {
6239 let config = ServerConfig::new("127.0.0.1:8080").with_keep_alive_timeout(Duration::ZERO);
6240 assert!(config.keep_alive_timeout.is_zero());
6241 }
6242
6243 #[test]
6244 fn keep_alive_timeout_default_is_non_zero() {
6245 let config = ServerConfig::default();
6246 assert!(!config.keep_alive_timeout.is_zero());
6247 assert_eq!(
6248 config.keep_alive_timeout,
6249 Duration::from_secs(DEFAULT_KEEP_ALIVE_TIMEOUT_SECS)
6250 );
6251 }
6252
6253 #[test]
6254 fn timed_out_io_error_kind() {
6255 let err = io::Error::new(io::ErrorKind::TimedOut, "test timeout");
6256 assert_eq!(err.kind(), io::ErrorKind::TimedOut);
6257 }
6258
6259 #[test]
6260 fn instant_deadline_calculation() {
6261 let timeout = Duration::from_millis(100);
6262 let deadline = Instant::now() + timeout;
6263
6264 assert!(deadline > Instant::now());
6266
6267 std::thread::sleep(Duration::from_millis(150));
6269 assert!(Instant::now() >= deadline);
6270 }
6271
6272 #[test]
6273 fn server_metrics_initial_state() {
6274 let server = TcpServer::default();
6275 let m = server.metrics();
6276 assert_eq!(m.active_connections, 0);
6277 assert_eq!(m.total_accepted, 0);
6278 assert_eq!(m.total_rejected, 0);
6279 assert_eq!(m.total_timed_out, 0);
6280 assert_eq!(m.total_requests, 0);
6281 assert_eq!(m.bytes_in, 0);
6282 assert_eq!(m.bytes_out, 0);
6283 }
6284
6285 #[test]
6286 fn server_metrics_after_acquire_release() {
6287 let server = TcpServer::new(ServerConfig::new("127.0.0.1:0").with_max_connections(10));
6288 assert!(server.try_acquire_connection());
6289 assert!(server.try_acquire_connection());
6290
6291 let m = server.metrics();
6292 assert_eq!(m.active_connections, 2);
6293 assert_eq!(m.total_accepted, 2);
6294 assert_eq!(m.total_rejected, 0);
6295
6296 server.release_connection();
6297 let m = server.metrics();
6298 assert_eq!(m.active_connections, 1);
6299 assert_eq!(m.total_accepted, 2); }
6301
6302 #[test]
6303 fn server_metrics_rejection_counted() {
6304 let server = TcpServer::new(ServerConfig::new("127.0.0.1:0").with_max_connections(1));
6305 assert!(server.try_acquire_connection());
6306 assert!(!server.try_acquire_connection()); let m = server.metrics();
6309 assert_eq!(m.total_accepted, 1);
6310 assert_eq!(m.total_rejected, 1);
6311 assert_eq!(m.active_connections, 1);
6312 }
6313
6314 #[test]
6315 fn server_metrics_bytes_tracking() {
6316 let server = TcpServer::default();
6317 server.record_bytes_in(1024);
6318 server.record_bytes_in(512);
6319 server.record_bytes_out(2048);
6320
6321 let m = server.metrics();
6322 assert_eq!(m.bytes_in, 1536);
6323 assert_eq!(m.bytes_out, 2048);
6324 }
6325
6326 #[test]
6327 fn server_metrics_unlimited_connections_accepted() {
6328 let server = TcpServer::new(ServerConfig::new("127.0.0.1:0").with_max_connections(0));
6329 for _ in 0..100 {
6330 assert!(server.try_acquire_connection());
6331 }
6332 let m = server.metrics();
6333 assert_eq!(m.total_accepted, 100);
6334 assert_eq!(m.total_rejected, 0);
6335 assert_eq!(m.active_connections, 100);
6336 }
6337
6338 #[test]
6339 fn server_metrics_clone_eq() {
6340 let server = TcpServer::default();
6341 server.record_bytes_in(42);
6342 let m1 = server.metrics();
6343 let m2 = m1.clone();
6344 assert_eq!(m1, m2);
6345 }
6346}
6347
6348pub trait AppServeExt {
6371 fn serve(self, addr: impl Into<String>) -> impl Future<Output = Result<(), ServeError>> + Send;
6411
6412 fn serve_with_config(
6435 self,
6436 config: ServerConfig,
6437 ) -> impl Future<Output = Result<(), ServeError>> + Send;
6438}
6439
6440#[derive(Debug)]
6442pub enum ServeError {
6443 Startup(fastapi_core::StartupHookError),
6445 Server(ServerError),
6447}
6448
6449impl std::fmt::Display for ServeError {
6450 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
6451 match self {
6452 Self::Startup(e) => write!(f, "startup hook failed: {}", e.message),
6453 Self::Server(e) => write!(f, "server error: {e}"),
6454 }
6455 }
6456}
6457
6458impl std::error::Error for ServeError {
6459 fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
6460 match self {
6461 Self::Startup(_) => None,
6462 Self::Server(e) => Some(e),
6463 }
6464 }
6465}
6466
6467impl From<ServerError> for ServeError {
6468 fn from(e: ServerError) -> Self {
6469 Self::Server(e)
6470 }
6471}
6472
6473impl AppServeExt for App {
6474 fn serve(self, addr: impl Into<String>) -> impl Future<Output = Result<(), ServeError>> + Send {
6475 let config = ServerConfig::new(addr);
6476 self.serve_with_config(config)
6477 }
6478
6479 #[allow(clippy::manual_async_fn)] fn serve_with_config(
6481 self,
6482 config: ServerConfig,
6483 ) -> impl Future<Output = Result<(), ServeError>> + Send {
6484 async move {
6485 match self.run_startup_hooks().await {
6487 fastapi_core::StartupOutcome::Success => {}
6488 fastapi_core::StartupOutcome::PartialSuccess { warnings } => {
6489 eprintln!("Warning: {warnings} startup hook(s) had non-fatal errors");
6491 }
6492 fastapi_core::StartupOutcome::Aborted(e) => {
6493 return Err(ServeError::Startup(e));
6494 }
6495 }
6496
6497 let server = TcpServer::new(config);
6499
6500 let app = Arc::new(self);
6502
6503 let cx = Cx::current().ok_or_else(|| {
6504 ServeError::Server(ServerError::Io(io::Error::new(
6505 io::ErrorKind::Other,
6506 "fastapi App::serve must run inside an asupersync runtime",
6507 )))
6508 })?;
6509
6510 let bind_addr = &server.config().bind_addr;
6512 println!("🚀 Server starting on http://{bind_addr}");
6513
6514 let result = server.serve_app(&cx, Arc::clone(&app)).await;
6516
6517 app.run_shutdown_hooks().await;
6519
6520 result.map_err(ServeError::from)
6521 }
6522 }
6523}
6524
6525pub async fn serve(app: App, addr: impl Into<String>) -> Result<(), ServeError> {
6543 app.serve(addr).await
6544}
6545
6546pub async fn serve_with_config(app: App, config: ServerConfig) -> Result<(), ServeError> {
6564 app.serve_with_config(config).await
6565}