@@ -734,3 +734,107 @@ async fn zombie_connection_is_evicted() {
734734 connection is still open"
735735 ) ;
736736}
737+
738+ /// Server rejects a request whose body exceeds `max_request_body_bytes` with 413 and
739+ /// `ServerError::RequestBodyTooLarge`.
740+ #[ tokio:: test]
741+ async fn request_body_too_large ( ) {
742+ let mut available_ports = available_ports_factory ( unique_u16 ! ( ) ) ;
743+ let a_socket = available_ports. get_next_local_host_socket ( ) ;
744+ let dummy_b_socket = available_ports. get_next_local_host_socket ( ) ;
745+
746+ // B client points at a non-existent server; it will never be called because the oversized
747+ // request is rejected at the HTTP layer before any component logic runs.
748+ let b_remote_client = ComponentBClient :: new (
749+ RemoteClientConfig :: default ( ) ,
750+ & dummy_b_socket. ip ( ) . to_string ( ) ,
751+ dummy_b_socket. port ( ) ,
752+ & TEST_REMOTE_CLIENT_METRICS ,
753+ ) ;
754+ let component_a = ComponentA :: new ( Box :: new ( b_remote_client) ) ;
755+
756+ let ( tx_a, rx_a) = channel :: < RequestWrapper < ComponentARequest , ComponentAResponse > > ( 32 ) ;
757+ let a_local_client = LocalComponentClient :: new ( tx_a, & TEST_LOCAL_CLIENT_METRICS ) ;
758+
759+ let mut local_server = LocalComponentServer :: new (
760+ component_a,
761+ & LocalServerConfig :: default ( ) ,
762+ rx_a,
763+ & TEST_LOCAL_SERVER_METRICS ,
764+ ) ;
765+ task:: spawn ( async move {
766+ let _ = local_server. start ( ) . await ;
767+ } ) ;
768+
769+ let server_config = RemoteServerConfig { max_request_body_bytes : 1 , ..Default :: default ( ) } ;
770+ let mut remote_server = RemoteComponentServer :: new (
771+ a_local_client,
772+ server_config,
773+ a_socket. port ( ) ,
774+ & TEST_REMOTE_SERVER_METRICS ,
775+ ) ;
776+ task:: spawn ( async move {
777+ let _ = remote_server. start ( ) . await ;
778+ } ) ;
779+ task:: yield_now ( ) . await ;
780+
781+ let uri: Uri = format ! ( "http://[{}]:{}/" , a_socket. ip( ) , a_socket. port( ) ) . parse ( ) . unwrap ( ) ;
782+ let http_request = Request :: post ( uri)
783+ . header ( CONTENT_TYPE , APPLICATION_OCTET_STREAM )
784+ . header ( REQUEST_ID_HEADER , RequestId :: generate ( ) . to_string ( ) )
785+ . body ( Full :: new ( Bytes :: from ( "x" . repeat ( 1024 ) ) ) )
786+ . unwrap ( ) ;
787+ let http_response =
788+ Client :: builder ( TokioExecutor :: new ( ) ) . build_http ( ) . request ( http_request) . await . unwrap ( ) ;
789+
790+ assert_eq ! ( http_response. status( ) , StatusCode :: PAYLOAD_TOO_LARGE ) ;
791+ let body_bytes = http_response. into_body ( ) . collect ( ) . await . unwrap ( ) . to_bytes ( ) ;
792+ let server_error = SerdeWrapper :: < ServerError > :: wrapper_deserialize ( & body_bytes) . unwrap ( ) ;
793+ assert ! ( matches!( server_error, ServerError :: RequestBodyTooLarge ( _) ) ) ;
794+ }
795+
796+ /// Client returns `ResponseParsingFailure` when the server's response body exceeds
797+ /// `max_response_body_bytes`.
798+ #[ tokio:: test]
799+ async fn response_body_too_large ( ) {
800+ let socket = available_ports_factory ( unique_u16 ! ( ) ) . get_next_local_host_socket ( ) ;
801+ task:: spawn ( async move {
802+ async fn handler (
803+ _http_request : Request < Incoming > ,
804+ ) -> Result < Response < Full < Bytes > > , Infallible > {
805+ Ok ( Response :: builder ( )
806+ . status ( StatusCode :: OK )
807+ . header ( CONTENT_TYPE , APPLICATION_OCTET_STREAM )
808+ . body ( Full :: new ( Bytes :: from ( vec ! [ 0u8 ; 1024 ] ) ) )
809+ . unwrap ( ) )
810+ }
811+
812+ let listener = TcpListener :: bind ( & socket) . await . unwrap ( ) ;
813+ loop {
814+ let Ok ( ( stream, _) ) = listener. accept ( ) . await else { continue } ;
815+ let io = TokioIo :: new ( stream) ;
816+ let service = service_fn ( |req| async move { handler ( req) . await } ) ;
817+ tokio:: spawn ( async move {
818+ let _ = Http2ServerBuilder :: new ( TokioExecutor :: new ( ) )
819+ . http2 ( )
820+ . serve_connection ( io, service)
821+ . await ;
822+ } ) ;
823+ }
824+ } ) ;
825+ task:: yield_now ( ) . await ;
826+
827+ let client_config =
828+ RemoteClientConfig { max_response_body_bytes : 1 , retries : 0 , ..FAST_FAILING_CLIENT_CONFIG } ;
829+ let client = ComponentAClient :: new (
830+ client_config,
831+ & socket. ip ( ) . to_string ( ) ,
832+ socket. port ( ) ,
833+ & TEST_REMOTE_CLIENT_METRICS ,
834+ ) ;
835+
836+ let Err ( error) = client. a_get_value ( ) . await else {
837+ panic ! ( "Expected an error" ) ;
838+ } ;
839+ assert ! ( matches!( error, ClientError :: ResponseParsingFailure ( _) ) , "unexpected error: {error}" ) ;
840+ }
0 commit comments