@@ -11,7 +11,9 @@ use http::{Method, Request, Response, Uri, Version};
11
11
12
12
use super :: conn;
13
13
use 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
+ } ;
15
17
#[ cfg( feature = "tcp" ) ]
16
18
use super :: HttpConnector ;
17
19
use crate :: body:: { Body , HttpBody } ;
@@ -223,7 +225,17 @@ where
223
225
mut req : Request < B > ,
224
226
pool_key : PoolKey ,
225
227
) -> 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
+ } ;
227
239
228
240
if pooled. is_http1 ( ) {
229
241
if req. version ( ) == Version :: HTTP_2 {
@@ -321,7 +333,7 @@ where
321
333
async fn connection_for (
322
334
& self ,
323
335
pool_key : PoolKey ,
324
- ) -> Result < Pooled < PoolClient < B > > , ClientError < B > > {
336
+ ) -> Result < Pooled < PoolClient < B > > , ClientConnectError > {
325
337
// This actually races 2 different futures to try to get a ready
326
338
// connection the fastest, and to reduce connection churn.
327
339
//
@@ -337,6 +349,7 @@ where
337
349
// and then be inserted into the pool as an idle connection.
338
350
let checkout = self . pool . checkout ( pool_key. clone ( ) ) ;
339
351
let connect = self . connect_to ( pool_key) ;
352
+ let is_ver_h2 = self . config . ver == Ver :: Http2 ;
340
353
341
354
// The order of the `select` is depended on below...
342
355
@@ -380,16 +393,25 @@ where
380
393
// In both cases, we should just wait for the other future.
381
394
Either :: Left ( ( Err ( err) , connecting) ) => {
382
395
if err. is_canceled ( ) {
383
- connecting. await . map_err ( ClientError :: Normal )
396
+ connecting. await . map_err ( ClientConnectError :: Normal )
384
397
} else {
385
- Err ( ClientError :: Normal ( err) )
398
+ Err ( ClientConnectError :: Normal ( err) )
386
399
}
387
400
}
388
401
Either :: Right ( ( Err ( err) , checkout) ) => {
389
402
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
+ } )
391
413
} else {
392
- Err ( ClientError :: Normal ( err) )
414
+ Err ( ClientConnectError :: Normal ( err) )
393
415
}
394
416
}
395
417
}
@@ -722,6 +744,11 @@ impl<B> ClientError<B> {
722
744
}
723
745
}
724
746
747
+ enum ClientConnectError {
748
+ Normal ( crate :: Error ) ,
749
+ H2CheckoutIsClosed ( crate :: Error ) ,
750
+ }
751
+
725
752
/// A marker to identify what version a pooled connection is.
726
753
#[ derive( Clone , Copy , Debug , PartialEq , Eq , Hash ) ]
727
754
pub ( super ) enum Ver {
0 commit comments