@@ -824,7 +824,14 @@ pub(crate) async fn apply_middleware_chain_for_scheme<C: AsyncRead + AsyncWrite
824824 // body. Apply each entry's `on_error` policy without buffering (an
825825 // unresolved binding is handled before the body is read) and forward
826826 // the original request unchanged if the chain allows.
827- let input = middleware_request_input ( scheme, & req, ctx, BTreeMap :: new ( ) , String :: new ( ) , Vec :: new ( ) ) ;
827+ let input = middleware_request_input (
828+ scheme,
829+ & req,
830+ ctx,
831+ BTreeMap :: new ( ) ,
832+ String :: new ( ) ,
833+ Vec :: new ( ) ,
834+ ) ;
828835 let outcome = runner. evaluate_described ( & chain, input) . await ?;
829836 emit_middleware_events ( ctx, & req, & outcome) ;
830837 return Ok ( if outcome. allowed {
@@ -2823,6 +2830,72 @@ network_policies:
28232830 . unwrap ( ) ;
28242831 }
28252832
2833+ #[ tokio:: test]
2834+ async fn l7_rest_middleware_acknowledges_expect_continue_before_reading_body ( ) {
2835+ let ( config, tunnel_engine, ctx) =
2836+ middleware_relay_context ( "openshell/secrets" , "fail_closed" ) ;
2837+ let ( mut app, mut relay_client) = tokio:: io:: duplex ( 8192 ) ;
2838+ let ( mut relay_upstream, mut upstream) = tokio:: io:: duplex ( 8192 ) ;
2839+ let relay = tokio:: spawn ( async move {
2840+ relay_with_inspection (
2841+ & config,
2842+ tunnel_engine,
2843+ & mut relay_client,
2844+ & mut relay_upstream,
2845+ & ctx,
2846+ )
2847+ . await
2848+ } ) ;
2849+
2850+ let body = br#"{"api_key":"sk-1234567890abcdef"}"# ;
2851+ let headers = format ! (
2852+ "POST /v1/messages HTTP/1.1\r \n Host: api.example.test\r \n Content-Length: {}\r \n Expect: 100-continue\r \n Connection: close\r \n \r \n " ,
2853+ body. len( )
2854+ ) ;
2855+ app. write_all ( headers. as_bytes ( ) ) . await . unwrap ( ) ;
2856+
2857+ let mut interim = [ 0u8 ; 64 ] ;
2858+ let n = tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( 1 ) , app. read ( & mut interim) )
2859+ . await
2860+ . expect ( "middleware buffering should acknowledge Expect before reading the body" )
2861+ . unwrap ( ) ;
2862+ assert_eq ! ( & interim[ ..n] , b"HTTP/1.1 100 Continue\r \n \r \n " ) ;
2863+
2864+ app. write_all ( body) . await . unwrap ( ) ;
2865+
2866+ let mut upstream_request = [ 0u8 ; 1024 ] ;
2867+ let n = tokio:: time:: timeout (
2868+ std:: time:: Duration :: from_secs ( 1 ) ,
2869+ upstream. read ( & mut upstream_request) ,
2870+ )
2871+ . await
2872+ . expect ( "request should reach upstream after the body is released" )
2873+ . unwrap ( ) ;
2874+ let upstream_request = String :: from_utf8_lossy ( & upstream_request[ ..n] ) ;
2875+ assert ! ( upstream_request. contains( r#""api_key":"[REDACTED]""# ) ) ;
2876+ assert ! ( !upstream_request. contains( "Expect: 100-continue" ) ) ;
2877+
2878+ upstream
2879+ . write_all ( b"HTTP/1.1 204 No Content\r \n Content-Length: 0\r \n Connection: close\r \n \r \n " )
2880+ . await
2881+ . unwrap ( ) ;
2882+ let mut client_response = [ 0u8 ; 512 ] ;
2883+ let n = tokio:: time:: timeout (
2884+ std:: time:: Duration :: from_secs ( 1 ) ,
2885+ app. read ( & mut client_response) ,
2886+ )
2887+ . await
2888+ . expect ( "response should reach client" )
2889+ . unwrap ( ) ;
2890+ assert ! ( String :: from_utf8_lossy( & client_response[ ..n] ) . contains( "204 No Content" ) ) ;
2891+ drop ( app) ;
2892+ tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( 1 ) , relay)
2893+ . await
2894+ . expect ( "relay should finish" )
2895+ . unwrap ( )
2896+ . unwrap ( ) ;
2897+ }
2898+
28262899 #[ tokio:: test]
28272900 async fn l7_rest_middleware_fail_closed_does_not_reach_upstream ( ) {
28282901 let ( config, tunnel_engine, ctx) =
@@ -3484,7 +3557,8 @@ network_policies:
34843557 let mut response = Vec :: new ( ) ;
34853558 let mut buf = [ 0u8 ; 512 ] ;
34863559 while !String :: from_utf8_lossy ( & response) . contains ( "middleware_failed" ) {
3487- match tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( 1 ) , app. read ( & mut buf) ) . await {
3560+ match tokio:: time:: timeout ( std:: time:: Duration :: from_secs ( 1 ) , app. read ( & mut buf) ) . await
3561+ {
34883562 Ok ( Ok ( 0 ) ) | Err ( _) => break , // clean EOF, or no more data before the deadline
34893563 Ok ( Ok ( n) ) => response. extend_from_slice ( & buf[ ..n] ) ,
34903564 Ok ( Err ( e) ) => panic ! ( "read from relay failed: {e}" ) ,
0 commit comments