11use core:: mem:: MaybeUninit ;
22
3+ use http:: uri:: { Authority , Scheme } ;
34use httparse:: Status ;
45
56use crate :: {
@@ -71,7 +72,7 @@ impl<D, const MAX_HEADERS: usize> Context<'_, D, MAX_HEADERS> {
7172 // split the headers from buffer.
7273 let slice = buf. split_to ( len) . freeze ( ) ;
7374
74- let uri = Uri :: from_maybe_shared ( slice. slice ( path_head..path_head + path_len) ) ?;
75+ let mut uri = Uri :: from_maybe_shared ( slice. slice ( path_head..path_head + path_len) ) ?. into_parts ( ) ;
7576
7677 // pop a cached headermap or construct a new one.
7778 let mut headers = self . take_headers ( ) ;
@@ -87,6 +88,25 @@ impl<D, const MAX_HEADERS: usize> Context<'_, D, MAX_HEADERS> {
8788
8889 let extensions = self . take_extensions ( ) ;
8990
91+ // Try to set authority from host header if not present in request path
92+ if uri. authority . is_none ( ) {
93+ // @TODO if it's a tls connection we could set the sni server name as authority instead
94+ if let Some ( host) = headers. get ( http:: header:: HOST ) {
95+ uri. authority = Some ( Authority :: try_from ( host. as_bytes ( ) ) ?) ;
96+ }
97+ }
98+
99+ // If authority is set, this will set the correct scheme depending on the tls acceptor used in the service.
100+ if uri. authority . is_some ( ) && uri. scheme . is_none ( ) {
101+ uri. scheme = if self . is_tls {
102+ Some ( Scheme :: HTTPS )
103+ } else {
104+ Some ( Scheme :: HTTP )
105+ } ;
106+ }
107+
108+ let uri = Uri :: from_parts ( uri) ?;
109+
90110 * req. method_mut ( ) = method;
91111 * req. version_mut ( ) = version;
92112 * req. uri_mut ( ) = uri;
@@ -173,7 +193,7 @@ mod test {
173193
174194 #[ test]
175195 fn connection_multiple_value ( ) {
176- let mut ctx = Context :: < _ , 4 > :: new ( & ( ) ) ;
196+ let mut ctx = Context :: < _ , 4 > :: new ( & ( ) , false ) ;
177197
178198 let head = b"\
179199 GET / HTTP/1.1\r \n \
@@ -211,7 +231,7 @@ mod test {
211231
212232 #[ test]
213233 fn transfer_encoding ( ) {
214- let mut ctx = Context :: < _ , 4 > :: new ( & ( ) ) ;
234+ let mut ctx = Context :: < _ , 4 > :: new ( & ( ) , false ) ;
215235
216236 let head = b"\
217237 GET / HTTP/1.1\r \n \
@@ -311,4 +331,33 @@ mod test {
311331 "transfer coding is not decoded to chunked"
312332 ) ;
313333 }
334+
335+ #[ test]
336+ fn test_host_with_scheme ( ) {
337+ let mut ctx = Context :: < _ , 4 > :: new ( & ( ) , true ) ;
338+
339+ let head = b"\
340+ GET / HTTP/1.1\r \n \
341+ Host: example.com\r \n \
342+ \r \n \
343+ ";
344+ let mut buf = BytesMut :: from ( & head[ ..] ) ;
345+
346+ let ( req, _) = ctx. decode_head :: < 128 > ( & mut buf) . unwrap ( ) . unwrap ( ) ;
347+
348+ assert_eq ! ( req. uri( ) . scheme( ) , Some ( & Scheme :: HTTPS ) ) ;
349+ assert_eq ! ( req. uri( ) . authority( ) , Some ( & Authority :: from_static( "example.com" ) ) ) ;
350+ assert_eq ! ( req. headers( ) . get( http:: header:: HOST ) . unwrap( ) , "example.com" ) ;
351+
352+ let head = b"\
353+ GET / HTTP/1.1\r \n \
354+ \r \n \
355+ ";
356+ let mut buf = BytesMut :: from ( & head[ ..] ) ;
357+
358+ let ( req, _) = ctx. decode_head :: < 128 > ( & mut buf) . unwrap ( ) . unwrap ( ) ;
359+
360+ assert_eq ! ( req. uri( ) . scheme( ) , None ) ;
361+ assert_eq ! ( req. uri( ) . authority( ) , None ) ;
362+ }
314363}
0 commit comments