@@ -21,8 +21,56 @@ use std::error::Error;
21
21
22
22
use serde:: de:: StdError ;
23
23
24
- /// Punches through all the layers of `tonic::Status` sources to check if this is a `hyper::Error` that is canceled.
25
- pub ( super ) fn is_hyper_canceled ( status : & tonic:: Status ) -> bool {
24
+ fn has_transient_io_error < E : StdError > ( error : E ) -> bool {
25
+ let Some ( source) = error. source ( ) else {
26
+ return false ;
27
+ } ;
28
+
29
+ if let Some ( io_error) = source. downcast_ref :: < std:: io:: Error > ( ) {
30
+ is_io_error_transient ( io_error)
31
+ } else {
32
+ false
33
+ }
34
+ }
35
+
36
+ // tonic 0.11 (current dependency)
37
+ fn is_hyper_0_error_transient ( error : & hyper_0:: Error ) -> bool {
38
+ if error. is_canceled ( ) || has_transient_io_error ( error) {
39
+ true
40
+ } else if let Some ( source) = error. source ( ) {
41
+ if let Some ( h2_error) = source. downcast_ref :: < h2_03:: Error > ( ) {
42
+ h2_error. is_go_away ( )
43
+ } else {
44
+ false
45
+ }
46
+ } else {
47
+ false
48
+ }
49
+ }
50
+
51
+ // tonic 0.12
52
+ fn is_hyper_error_transient ( error : & hyper:: Error ) -> bool {
53
+ if error. is_canceled ( ) || has_transient_io_error ( error) {
54
+ true
55
+ } else if let Some ( source) = error. source ( ) {
56
+ if let Some ( h2_error) = source. downcast_ref :: < h2:: Error > ( ) {
57
+ h2_error. is_go_away ( )
58
+ } else {
59
+ false
60
+ }
61
+ } else {
62
+ false
63
+ }
64
+ }
65
+
66
+ fn is_io_error_transient ( error : & std:: io:: Error ) -> bool {
67
+ match error. kind ( ) {
68
+ std:: io:: ErrorKind :: BrokenPipe => true ,
69
+ _ => false ,
70
+ }
71
+ }
72
+
73
+ pub ( super ) fn is_tonic_status_transient ( status : & tonic:: Status ) -> bool {
26
74
let source = status
27
75
. source ( )
28
76
. and_then ( |it| it. downcast_ref :: < tonic:: transport:: Error > ( ) )
@@ -33,11 +81,9 @@ pub(super) fn is_hyper_canceled(status: &tonic::Status) -> bool {
33
81
} ;
34
82
35
83
if let Some ( hyper_0) = source. downcast_ref :: < hyper_0:: Error > ( ) {
36
- // tonic 0.11 (current dependency)
37
- hyper_0. is_canceled ( )
38
- } else if let Some ( hyper_1) = source. downcast_ref :: < hyper:: Error > ( ) {
39
- // tonic 0.12
40
- hyper_1. is_canceled ( )
84
+ is_hyper_0_error_transient ( hyper_0)
85
+ } else if let Some ( hyper) = source. downcast_ref :: < hyper:: Error > ( ) {
86
+ is_hyper_error_transient ( hyper)
41
87
} else {
42
88
false
43
89
}
@@ -48,47 +94,22 @@ pub(super) fn is_hyper_canceled(status: &tonic::Status) -> bool {
48
94
/// Because hyper does not expose constructors for its error variants, there is no
49
95
/// reasonable way to construct a test for positive detection of a hyper cancellation.
50
96
#[ cfg( test) ]
51
- mod test_is_hyper_canceled {
97
+ mod test_is_tonic_status_transient {
52
98
use tonic:: Code ;
53
99
54
- use super :: is_hyper_canceled ;
100
+ use super :: is_tonic_status_transient ;
55
101
56
102
#[ test]
57
103
fn ignores_tonic_abort ( ) {
58
104
let input = tonic:: Status :: new ( Code :: Aborted , "foo" ) ;
59
105
60
- assert ! ( !is_hyper_canceled ( & input) ) ;
106
+ assert ! ( !is_tonic_status_transient ( & input) ) ;
61
107
}
62
108
63
109
#[ test]
64
110
fn ignores_tonic_cancel ( ) {
65
111
let input = tonic:: Status :: new ( Code :: Cancelled , "foo" ) ;
66
112
67
- assert ! ( !is_hyper_canceled( & input) ) ;
68
- }
69
- }
70
-
71
- pub ( super ) fn is_tonic_status_transient ( status : & tonic:: Status ) -> bool {
72
- let source = status
73
- . source ( )
74
- . and_then ( |it| it. downcast_ref :: < tonic:: transport:: Error > ( ) )
75
- . and_then ( StdError :: source) ;
76
-
77
- let Some ( source) = source else {
78
- return false ;
79
- } ;
80
-
81
- if let Some ( hyper_0) = source. downcast_ref :: < hyper_0:: Error > ( ) {
82
- // tonic 0.11 (current dependency)
83
- let source: Option < & h2_03:: Error > = hyper_0. source ( ) . and_then ( |s| s. downcast_ref ( ) ) ;
84
-
85
- source. map ( |s| s. is_go_away ( ) ) . unwrap_or_default ( )
86
- } else if let Some ( hyper_1) = source. downcast_ref :: < hyper:: Error > ( ) {
87
- // tonic 0.12
88
- let source: Option < & h2:: Error > = hyper_1. source ( ) . and_then ( |s| s. downcast_ref ( ) ) ;
89
-
90
- source. map ( |s| s. is_go_away ( ) ) . unwrap_or_default ( )
91
- } else {
92
- false
113
+ assert ! ( !is_tonic_status_transient( & input) ) ;
93
114
}
94
115
}
0 commit comments