@@ -20,7 +20,7 @@ use tokio::io::{AsyncReadExt, AsyncWriteExt};
2020use hyper:: body:: Bytes ;
2121use hyper:: body:: Frame ;
2222use hyper:: Request ;
23- use hyper_util:: client:: legacy:: connect:: { capture_connection, HttpConnector } ;
23+ use hyper_util:: client:: legacy:: connect:: { capture_connection, HttpConnector , HttpInfo } ;
2424use hyper_util:: client:: legacy:: Client ;
2525use hyper_util:: rt:: { TokioExecutor , TokioIo } ;
2626
@@ -978,3 +978,91 @@ fn connection_poisoning() {
978978 assert_eq ! ( num_conns. load( Ordering :: SeqCst ) , 2 ) ;
979979 assert_eq ! ( num_requests. load( Ordering :: SeqCst ) , 5 ) ;
980980}
981+
982+ #[ cfg( not( miri) ) ]
983+ #[ tokio:: test]
984+ async fn connect_info_on_error ( ) {
985+ let client = Client :: builder ( TokioExecutor :: new ( ) ) . build ( HttpConnector :: new ( ) ) ;
986+
987+ // srv1 accepts one connection, and cancel it after reading the second request.
988+ let tcp1 = tokio:: net:: TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
989+ let addr1 = tcp1. local_addr ( ) . unwrap ( ) ;
990+ let srv1 = tokio:: spawn ( async move {
991+ let ( mut sock, _addr) = tcp1. accept ( ) . await . unwrap ( ) ;
992+ let mut buf = [ 0 ; 4096 ] ;
993+ sock. read ( & mut buf) . await . expect ( "read 1" ) ;
994+ let body = Bytes :: from ( "Hello, world!" ) ;
995+ sock. write_all (
996+ format ! ( "HTTP/1.1 200 OK\r \n Content-Length: {}\r \n \r \n " , body. len( ) ) . as_bytes ( ) ,
997+ )
998+ . await
999+ . expect ( "write header" ) ;
1000+ sock. write_all ( & body) . await . expect ( "write body" ) ;
1001+
1002+ sock. read ( & mut buf) . await . expect ( "read 2" ) ;
1003+ drop ( sock) ;
1004+ } ) ;
1005+
1006+ // Makes a first request to srv1, which should succeed.
1007+ {
1008+ let req = Request :: builder ( )
1009+ . uri ( format ! ( "http://{addr1}" ) )
1010+ . body ( Empty :: < Bytes > :: new ( ) )
1011+ . unwrap ( ) ;
1012+ let res = client. request ( req) . await . unwrap ( ) ;
1013+ let http_info = res. extensions ( ) . get :: < HttpInfo > ( ) . unwrap ( ) ;
1014+ assert_eq ! ( http_info. remote_addr( ) , addr1) ;
1015+ let res_body = String :: from_utf8 ( res. collect ( ) . await . unwrap ( ) . to_bytes ( ) . into ( ) ) . unwrap ( ) ;
1016+ assert_eq ! ( res_body, "Hello, world!" ) ;
1017+ }
1018+
1019+ // Makes a second request to srv1, which should use the same connection and fail.
1020+ {
1021+ let req = Request :: builder ( )
1022+ . uri ( format ! ( "http://{addr1}" ) )
1023+ . body ( Empty :: < Bytes > :: new ( ) )
1024+ . unwrap ( ) ;
1025+ let err = client. request ( req) . await . unwrap_err ( ) ;
1026+ let conn_info = err. connect_info ( ) . unwrap ( ) ;
1027+ assert ! ( !conn_info. is_proxied( ) ) ;
1028+ assert ! ( !conn_info. is_negotiated_h2( ) ) ;
1029+ assert ! ( conn_info. is_reused( ) ) ;
1030+
1031+ let mut exts = http:: Extensions :: new ( ) ;
1032+ conn_info. get_extras ( & mut exts) ;
1033+ let http_info = exts. get :: < HttpInfo > ( ) . unwrap ( ) ;
1034+ assert_eq ! ( http_info. remote_addr( ) , addr1) ;
1035+ }
1036+
1037+ srv1. await . unwrap ( ) ;
1038+
1039+ // srv2 accepts one connection, reads a request, and immediately closes it.
1040+ let tcp2 = tokio:: net:: TcpListener :: bind ( "127.0.0.1:0" ) . await . unwrap ( ) ;
1041+ let addr2 = tcp2. local_addr ( ) . unwrap ( ) ;
1042+ let srv2 = tokio:: spawn ( async move {
1043+ let ( mut sock, _addr) = tcp2. accept ( ) . await . unwrap ( ) ;
1044+ let mut buf = [ 0 ; 4096 ] ;
1045+ sock. read ( & mut buf) . await . expect ( "read" ) ;
1046+ drop ( sock) ;
1047+ } ) ;
1048+
1049+ // Makes a first request to srv2, which should use a fresh connection and fail.
1050+ {
1051+ let req = Request :: builder ( )
1052+ . uri ( format ! ( "http://{addr2}" ) )
1053+ . body ( Empty :: < Bytes > :: new ( ) )
1054+ . unwrap ( ) ;
1055+ let err = client. request ( req) . await . unwrap_err ( ) ;
1056+ let conn_info = err. connect_info ( ) . unwrap ( ) ;
1057+ assert ! ( !conn_info. is_proxied( ) ) ;
1058+ assert ! ( !conn_info. is_negotiated_h2( ) ) ;
1059+ assert ! ( !conn_info. is_reused( ) ) ;
1060+
1061+ let mut exts = http:: Extensions :: new ( ) ;
1062+ conn_info. get_extras ( & mut exts) ;
1063+ let http_info = exts. get :: < HttpInfo > ( ) . unwrap ( ) ;
1064+ assert_eq ! ( http_info. remote_addr( ) , addr2) ;
1065+ }
1066+
1067+ srv2. await . unwrap ( ) ;
1068+ }
0 commit comments