@@ -11,7 +11,9 @@ use http::{Method, Request, Response, Uri, Version};
1111
1212use super :: conn;
1313use super :: connect:: { self , sealed:: Connect , Alpn , Connected , Connection } ;
14- use super :: pool:: { self , Key as PoolKey , Pool , Poolable , Pooled , Reservation } ;
14+ use super :: pool:: {
15+ self , CheckoutIsClosedError , Key as PoolKey , Pool , Poolable , Pooled , Reservation ,
16+ } ;
1517#[ cfg( feature = "tcp" ) ]
1618use super :: HttpConnector ;
1719use crate :: body:: { Body , HttpBody } ;
@@ -223,7 +225,17 @@ where
223225 mut req : Request < B > ,
224226 pool_key : PoolKey ,
225227 ) -> Result < Response < Body > , ClientError < B > > {
226- let mut pooled = self . connection_for ( pool_key) . await ?;
228+ let mut pooled = match self . connection_for ( pool_key) . await {
229+ Ok ( pooled) => pooled,
230+ Err ( ClientConnectError :: Normal ( err) ) => return Err ( ClientError :: Normal ( err) ) ,
231+ Err ( ClientConnectError :: H2CheckoutIsClosed ( reason) ) => {
232+ return Err ( ClientError :: Canceled {
233+ connection_reused : true ,
234+ req,
235+ reason,
236+ } )
237+ }
238+ } ;
227239
228240 if pooled. is_http1 ( ) {
229241 if req. version ( ) == Version :: HTTP_2 {
@@ -321,7 +333,7 @@ where
321333 async fn connection_for (
322334 & self ,
323335 pool_key : PoolKey ,
324- ) -> Result < Pooled < PoolClient < B > > , ClientError < B > > {
336+ ) -> Result < Pooled < PoolClient < B > > , ClientConnectError > {
325337 // This actually races 2 different futures to try to get a ready
326338 // connection the fastest, and to reduce connection churn.
327339 //
@@ -337,6 +349,7 @@ where
337349 // and then be inserted into the pool as an idle connection.
338350 let checkout = self . pool . checkout ( pool_key. clone ( ) ) ;
339351 let connect = self . connect_to ( pool_key) ;
352+ let is_ver_h2 = self . config . ver == Ver :: Http2 ;
340353
341354 // The order of the `select` is depended on below...
342355
@@ -380,16 +393,25 @@ where
380393 // In both cases, we should just wait for the other future.
381394 Either :: Left ( ( Err ( err) , connecting) ) => {
382395 if err. is_canceled ( ) {
383- connecting. await . map_err ( ClientError :: Normal )
396+ connecting. await . map_err ( ClientConnectError :: Normal )
384397 } else {
385- Err ( ClientError :: Normal ( err) )
398+ Err ( ClientConnectError :: Normal ( err) )
386399 }
387400 }
388401 Either :: Right ( ( Err ( err) , checkout) ) => {
389402 if err. is_canceled ( ) {
390- checkout. await . map_err ( ClientError :: Normal )
403+ checkout. await . map_err ( move |err| {
404+ if is_ver_h2
405+ && err. is_canceled ( )
406+ && err. find_source :: < CheckoutIsClosedError > ( ) . is_some ( )
407+ {
408+ ClientConnectError :: H2CheckoutIsClosed ( err)
409+ } else {
410+ ClientConnectError :: Normal ( err)
411+ }
412+ } )
391413 } else {
392- Err ( ClientError :: Normal ( err) )
414+ Err ( ClientConnectError :: Normal ( err) )
393415 }
394416 }
395417 }
@@ -722,6 +744,11 @@ impl<B> ClientError<B> {
722744 }
723745}
724746
747+ enum ClientConnectError {
748+ Normal ( crate :: Error ) ,
749+ H2CheckoutIsClosed ( crate :: Error ) ,
750+ }
751+
725752/// A marker to identify what version a pooled connection is.
726753#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
727754pub ( super ) enum Ver {
0 commit comments