@@ -2059,6 +2059,255 @@ async fn reset_before_headers_reaches_peer_without_headers() {
20592059 join ( srv, client) . await ;
20602060}
20612061
2062+ #[ tokio:: test]
2063+ async fn host_authority_mismatch_promotes_host_to_authority ( ) {
2064+ // When Host differs from URI authority, Host should win for :authority
2065+ // and Host header should be stripped from regular headers.
2066+ h2_support:: trace_init!( ) ;
2067+ let ( io, mut srv) = mock:: new ( ) ;
2068+
2069+ let srv = async move {
2070+ let settings = srv. assert_client_handshake ( ) . await ;
2071+ assert_default_settings ! ( settings) ;
2072+ srv. recv_frame (
2073+ frames:: headers ( 1 )
2074+ . pseudo ( frame:: Pseudo {
2075+ method : Method :: GET . into ( ) ,
2076+ scheme : util:: byte_str ( "https" ) . into ( ) ,
2077+ authority : util:: byte_str ( "example.com" ) . into ( ) ,
2078+ path : util:: byte_str ( "/" ) . into ( ) ,
2079+ ..Default :: default ( )
2080+ } )
2081+ . eos ( ) ,
2082+ )
2083+ . await ;
2084+ srv. send_frame ( frames:: headers ( 1 ) . response ( 200 ) . eos ( ) ) . await ;
2085+ } ;
2086+
2087+ let h2 = async move {
2088+ let ( mut client, mut h2) = client:: handshake ( io) . await . expect ( "handshake" ) ;
2089+
2090+ let request = Request :: builder ( )
2091+ . version ( Version :: HTTP_2 )
2092+ . method ( Method :: GET )
2093+ . uri ( "https://example.net/" )
2094+ . header ( "host" , "example.com" )
2095+ . body ( ( ) )
2096+ . unwrap ( ) ;
2097+
2098+ let ( response, _) = client. send_request ( request, true ) . unwrap ( ) ;
2099+ h2. drive ( response) . await . unwrap ( ) ;
2100+ } ;
2101+
2102+ join ( srv, h2) . await ;
2103+ }
2104+
2105+ #[ tokio:: test]
2106+ async fn host_authority_http11_version_still_promotes_host_to_authority ( ) {
2107+ // Real integration path: higher layers (for example hyper/hyper-util)
2108+ // commonly pass Request values with the default HTTP/1.1 version even when
2109+ // the selected transport is HTTP/2. We still need HTTP/2-compliant
2110+ // canonicalization on the wire, so Host must promote to :authority here.
2111+ h2_support:: trace_init!( ) ;
2112+ let ( io, mut srv) = mock:: new ( ) ;
2113+
2114+ let srv = async move {
2115+ let settings = srv. assert_client_handshake ( ) . await ;
2116+ assert_default_settings ! ( settings) ;
2117+ srv. recv_frame (
2118+ frames:: headers ( 1 )
2119+ . pseudo ( frame:: Pseudo {
2120+ method : Method :: GET . into ( ) ,
2121+ scheme : util:: byte_str ( "https" ) . into ( ) ,
2122+ authority : util:: byte_str ( "example.com" ) . into ( ) ,
2123+ path : util:: byte_str ( "/" ) . into ( ) ,
2124+ ..Default :: default ( )
2125+ } )
2126+ . eos ( ) ,
2127+ )
2128+ . await ;
2129+ srv. send_frame ( frames:: headers ( 1 ) . response ( 200 ) . eos ( ) ) . await ;
2130+ } ;
2131+
2132+ let h2 = async move {
2133+ let ( mut client, mut h2) = client:: handshake ( io) . await . expect ( "handshake" ) ;
2134+
2135+ let request = Request :: builder ( )
2136+ // Keep the default request version to model the common caller behavior.
2137+ . method ( Method :: GET )
2138+ . uri ( "https://example.net/" )
2139+ . header ( "host" , "example.com" )
2140+ . body ( ( ) )
2141+ . unwrap ( ) ;
2142+
2143+ let ( response, _) = client. send_request ( request, true ) . unwrap ( ) ;
2144+ h2. drive ( response) . await . unwrap ( ) ;
2145+ } ;
2146+
2147+ join ( srv, h2) . await ;
2148+ }
2149+
2150+ #[ tokio:: test]
2151+ async fn host_authority_matching_strips_host ( ) {
2152+ // When Host matches URI authority, Host header should still be stripped.
2153+ h2_support:: trace_init!( ) ;
2154+ let ( io, mut srv) = mock:: new ( ) ;
2155+
2156+ let srv = async move {
2157+ let settings = srv. assert_client_handshake ( ) . await ;
2158+ assert_default_settings ! ( settings) ;
2159+ srv. recv_frame (
2160+ frames:: headers ( 1 )
2161+ . pseudo ( frame:: Pseudo {
2162+ method : Method :: GET . into ( ) ,
2163+ scheme : util:: byte_str ( "https" ) . into ( ) ,
2164+ authority : util:: byte_str ( "example.com" ) . into ( ) ,
2165+ path : util:: byte_str ( "/" ) . into ( ) ,
2166+ ..Default :: default ( )
2167+ } )
2168+ . eos ( ) ,
2169+ )
2170+ . await ;
2171+ srv. send_frame ( frames:: headers ( 1 ) . response ( 200 ) . eos ( ) ) . await ;
2172+ } ;
2173+
2174+ let h2 = async move {
2175+ let ( mut client, mut h2) = client:: handshake ( io) . await . expect ( "handshake" ) ;
2176+
2177+ let request = Request :: builder ( )
2178+ . version ( Version :: HTTP_2 )
2179+ . method ( Method :: GET )
2180+ . uri ( "https://example.com/" )
2181+ . header ( "host" , "example.com" )
2182+ . body ( ( ) )
2183+ . unwrap ( ) ;
2184+
2185+ let ( response, _) = client. send_request ( request, true ) . unwrap ( ) ;
2186+ h2. drive ( response) . await . unwrap ( ) ;
2187+ } ;
2188+
2189+ join ( srv, h2) . await ;
2190+ }
2191+
2192+ #[ tokio:: test]
2193+ async fn host_authority_duplicate_host_first_wins ( ) {
2194+ // When multiple Host headers are present, first value is used for :authority.
2195+ h2_support:: trace_init!( ) ;
2196+ let ( io, mut srv) = mock:: new ( ) ;
2197+
2198+ let srv = async move {
2199+ let settings = srv. assert_client_handshake ( ) . await ;
2200+ assert_default_settings ! ( settings) ;
2201+ srv. recv_frame (
2202+ frames:: headers ( 1 )
2203+ . pseudo ( frame:: Pseudo {
2204+ method : Method :: GET . into ( ) ,
2205+ scheme : util:: byte_str ( "https" ) . into ( ) ,
2206+ authority : util:: byte_str ( "first.example" ) . into ( ) ,
2207+ path : util:: byte_str ( "/" ) . into ( ) ,
2208+ ..Default :: default ( )
2209+ } )
2210+ . eos ( ) ,
2211+ )
2212+ . await ;
2213+ srv. send_frame ( frames:: headers ( 1 ) . response ( 200 ) . eos ( ) ) . await ;
2214+ } ;
2215+
2216+ let h2 = async move {
2217+ let ( mut client, mut h2) = client:: handshake ( io) . await . expect ( "handshake" ) ;
2218+
2219+ let request = Request :: builder ( )
2220+ . version ( Version :: HTTP_2 )
2221+ . method ( Method :: GET )
2222+ . uri ( "https://example.net/" )
2223+ . header ( "host" , "first.example" )
2224+ . header ( "host" , "second.example" )
2225+ . body ( ( ) )
2226+ . unwrap ( ) ;
2227+
2228+ let ( response, _) = client. send_request ( request, true ) . unwrap ( ) ;
2229+ h2. drive ( response) . await . unwrap ( ) ;
2230+ } ;
2231+
2232+ join ( srv, h2) . await ;
2233+ }
2234+
2235+ #[ tokio:: test]
2236+ async fn host_authority_invalid_host_keeps_uri_authority ( ) {
2237+ // When Host is invalid (unparseable as authority), keep URI authority and strip Host.
2238+ h2_support:: trace_init!( ) ;
2239+ let ( io, mut srv) = mock:: new ( ) ;
2240+
2241+ let srv = async move {
2242+ let settings = srv. assert_client_handshake ( ) . await ;
2243+ assert_default_settings ! ( settings) ;
2244+ srv. recv_frame (
2245+ frames:: headers ( 1 )
2246+ . pseudo ( frame:: Pseudo {
2247+ method : Method :: GET . into ( ) ,
2248+ scheme : util:: byte_str ( "https" ) . into ( ) ,
2249+ authority : util:: byte_str ( "example.net" ) . into ( ) ,
2250+ path : util:: byte_str ( "/" ) . into ( ) ,
2251+ ..Default :: default ( )
2252+ } )
2253+ . eos ( ) ,
2254+ )
2255+ . await ;
2256+ srv. send_frame ( frames:: headers ( 1 ) . response ( 200 ) . eos ( ) ) . await ;
2257+ } ;
2258+
2259+ let h2 = async move {
2260+ let ( mut client, mut h2) = client:: handshake ( io) . await . expect ( "handshake" ) ;
2261+
2262+ let request = Request :: builder ( )
2263+ . version ( Version :: HTTP_2 )
2264+ . method ( Method :: GET )
2265+ . uri ( "https://example.net/" )
2266+ . header ( "host" , "not:a/good authority" )
2267+ . body ( ( ) )
2268+ . unwrap ( ) ;
2269+
2270+ let ( response, _) = client. send_request ( request, true ) . unwrap ( ) ;
2271+ h2. drive ( response) . await . unwrap ( ) ;
2272+ } ;
2273+
2274+ join ( srv, h2) . await ;
2275+ }
2276+
2277+ #[ tokio:: test]
2278+ async fn host_authority_relative_uri_http2_still_errors ( ) {
2279+ // Relative URI with HTTP/2 version should still produce MissingUriSchemeAndAuthority error,
2280+ // even when a Host header is provided. The Host canonicalization does not synthesize
2281+ // authority for relative URIs.
2282+ h2_support:: trace_init!( ) ;
2283+ let ( io, mut srv) = mock:: new ( ) ;
2284+
2285+ let srv = async move {
2286+ let settings = srv. assert_client_handshake ( ) . await ;
2287+ assert_default_settings ! ( settings) ;
2288+ } ;
2289+
2290+ let h2 = async move {
2291+ let ( mut client, h2) = client:: handshake ( io) . await . expect ( "handshake" ) ;
2292+
2293+ let request = Request :: builder ( )
2294+ . version ( Version :: HTTP_2 )
2295+ . method ( Method :: GET )
2296+ . uri ( "/" )
2297+ . header ( "host" , "example.com" )
2298+ . body ( ( ) )
2299+ . unwrap ( ) ;
2300+
2301+ client
2302+ . send_request ( request, true )
2303+ . expect_err ( "should be UserError" ) ;
2304+ let _: ( ) = h2. await . expect ( "h2" ) ;
2305+ drop ( client) ;
2306+ } ;
2307+
2308+ join ( srv, h2) . await ;
2309+ }
2310+
20622311const SETTINGS : & [ u8 ] = & [ 0 , 0 , 0 , 4 , 0 , 0 , 0 , 0 , 0 ] ;
20632312const SETTINGS_ACK : & [ u8 ] = & [ 0 , 0 , 0 , 4 , 1 , 0 , 0 , 0 , 0 ] ;
20642313
0 commit comments