1
1
use async_trait:: async_trait;
2
- use reqwest:: { self , Client , RequestBuilder , StatusCode } ;
2
+ use reqwest:: { self , Client , RequestBuilder , Response , StatusCode } ;
3
3
use slog_scope:: debug;
4
4
use std:: io;
5
5
use thiserror:: Error ;
@@ -35,6 +35,21 @@ pub enum CertificateHandlerError {
35
35
/// Mostly network errors.
36
36
#[ error( "io error: {0}" ) ]
37
37
IOError ( #[ from] io:: Error ) ,
38
+
39
+ /// Incompatible API version error
40
+ #[ error( "HTTP API version mismatch: {0}" ) ]
41
+ ApiVersionMismatch ( String ) ,
42
+ }
43
+
44
+ #[ cfg( test) ]
45
+ /// convenient methods to error enum
46
+ impl CertificateHandlerError {
47
+ pub fn is_api_version_mismatch ( & self ) -> bool {
48
+ match self {
49
+ Self :: ApiVersionMismatch ( _) => true ,
50
+ _ => false ,
51
+ }
52
+ }
38
53
}
39
54
40
55
/// Trait for mocking and testing a `CertificateHandler`
@@ -79,6 +94,22 @@ impl CertificateHandlerHTTPClient {
79
94
pub fn prepare_request_builder ( & self , request_builder : RequestBuilder ) -> RequestBuilder {
80
95
request_builder. header ( "API_VERSION" , MITHRIL_API_VERSION )
81
96
}
97
+
98
+ /// API version error handling
99
+ fn handle_api_error ( & self , response : & Response ) -> CertificateHandlerError {
100
+ if let Some ( version) = response. headers ( ) . get ( "mithril-api-version" ) {
101
+ CertificateHandlerError :: ApiVersionMismatch ( format ! (
102
+ "server version: '{}', signer version: '{}'" ,
103
+ version. to_str( ) . unwrap( ) ,
104
+ MITHRIL_API_VERSION
105
+ ) )
106
+ } else {
107
+ CertificateHandlerError :: ApiVersionMismatch ( format ! (
108
+ "version precondition failed, sent version '{}'." ,
109
+ MITHRIL_API_VERSION
110
+ ) )
111
+ }
112
+ }
82
113
}
83
114
84
115
#[ async_trait]
@@ -99,6 +130,7 @@ impl CertificateHandler for CertificateHandlerHTTPClient {
99
130
Ok ( epoch_settings) => Ok ( Some ( epoch_settings) ) ,
100
131
Err ( err) => Err ( CertificateHandlerError :: JsonParseFailed ( err. to_string ( ) ) ) ,
101
132
} ,
133
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
102
134
_ => Err ( CertificateHandlerError :: RemoteServerTechnical (
103
135
response. text ( ) . await . unwrap_or_default ( ) ,
104
136
) ) ,
@@ -125,6 +157,7 @@ impl CertificateHandler for CertificateHandlerHTTPClient {
125
157
Ok ( pending_certificate) => Ok ( Some ( pending_certificate) ) ,
126
158
Err ( err) => Err ( CertificateHandlerError :: JsonParseFailed ( err. to_string ( ) ) ) ,
127
159
} ,
160
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
128
161
StatusCode :: NO_CONTENT => Ok ( None ) ,
129
162
_ => Err ( CertificateHandlerError :: RemoteServerTechnical (
130
163
response. text ( ) . await . unwrap_or_default ( ) ,
@@ -148,6 +181,7 @@ impl CertificateHandler for CertificateHandlerHTTPClient {
148
181
match response {
149
182
Ok ( response) => match response. status ( ) {
150
183
StatusCode :: CREATED => Ok ( ( ) ) ,
184
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
151
185
StatusCode :: BAD_REQUEST => Err ( CertificateHandlerError :: RemoteServerLogical (
152
186
format ! ( "bad request: {}" , response. text( ) . await . unwrap_or_default( ) ) ,
153
187
) ) ,
@@ -176,6 +210,7 @@ impl CertificateHandler for CertificateHandlerHTTPClient {
176
210
match response {
177
211
Ok ( response) => match response. status ( ) {
178
212
StatusCode :: CREATED => Ok ( ( ) ) ,
213
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
179
214
StatusCode :: BAD_REQUEST => Err ( CertificateHandlerError :: RemoteServerLogical (
180
215
format ! ( "bad request: {}" , response. text( ) . await . unwrap_or_default( ) ) ,
181
216
) ) ,
@@ -325,6 +360,22 @@ mod tests {
325
360
assert_eq ! ( epoch_settings_expected, epoch_settings. unwrap( ) . unwrap( ) ) ;
326
361
}
327
362
363
+ #[ tokio:: test]
364
+ async fn test_epoch_settings_ko_412 ( ) {
365
+ let ( server, config) = setup_test ( ) ;
366
+ let _snapshots_mock = server. mock ( |when, then| {
367
+ when. path ( "/epoch-settings" ) ;
368
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
369
+ } ) ;
370
+ let certificate_handler = CertificateHandlerHTTPClient :: new ( config. aggregator_endpoint ) ;
371
+ let epoch_settings = certificate_handler
372
+ . retrieve_epoch_settings ( )
373
+ . await
374
+ . unwrap_err ( ) ;
375
+
376
+ assert ! ( epoch_settings. is_api_version_mismatch( ) ) ;
377
+ }
378
+
328
379
#[ tokio:: test]
329
380
async fn test_epoch_settings_ko_500 ( ) {
330
381
let ( server, config) = setup_test ( ) ;
@@ -359,6 +410,22 @@ mod tests {
359
410
) ;
360
411
}
361
412
413
+ #[ tokio:: test]
414
+ async fn test_certificate_pending_ko_412 ( ) {
415
+ let ( server, config) = setup_test ( ) ;
416
+ let _snapshots_mock = server. mock ( |when, then| {
417
+ when. path ( "/certificate-pending" ) ;
418
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
419
+ } ) ;
420
+ let certificate_handler = CertificateHandlerHTTPClient :: new ( config. aggregator_endpoint ) ;
421
+ let error = certificate_handler
422
+ . retrieve_pending_certificate ( )
423
+ . await
424
+ . unwrap_err ( ) ;
425
+
426
+ assert ! ( error. is_api_version_mismatch( ) ) ;
427
+ }
428
+
362
429
#[ tokio:: test]
363
430
async fn test_certificate_pending_ok_204 ( ) {
364
431
let ( server, config) = setup_test ( ) ;
@@ -402,7 +469,25 @@ mod tests {
402
469
}
403
470
404
471
#[ tokio:: test]
405
- async fn test_register_signer_ok_400 ( ) {
472
+ async fn test_register_signer_ko_412 ( ) {
473
+ let ( server, config) = setup_test ( ) ;
474
+ let _snapshots_mock = server. mock ( |when, then| {
475
+ when. method ( POST ) . path ( "/register-signer" ) ;
476
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
477
+ } ) ;
478
+ let single_signers = fake_data:: signers ( 1 ) ;
479
+ let single_signer = single_signers. first ( ) . unwrap ( ) ;
480
+ let certificate_handler = CertificateHandlerHTTPClient :: new ( config. aggregator_endpoint ) ;
481
+ let error = certificate_handler
482
+ . register_signer ( single_signer)
483
+ . await
484
+ . unwrap_err ( ) ;
485
+
486
+ assert ! ( error. is_api_version_mismatch( ) ) ;
487
+ }
488
+
489
+ #[ tokio:: test]
490
+ async fn test_register_signer_ko_400 ( ) {
406
491
let single_signers = fake_data:: signers ( 1 ) ;
407
492
let single_signer = single_signers. first ( ) . unwrap ( ) ;
408
493
let ( server, config) = setup_test ( ) ;
@@ -428,7 +513,7 @@ mod tests {
428
513
}
429
514
430
515
#[ tokio:: test]
431
- async fn test_register_signer_ok_500 ( ) {
516
+ async fn test_register_signer_ko_500 ( ) {
432
517
let single_signers = fake_data:: signers ( 1 ) ;
433
518
let single_signer = single_signers. first ( ) . unwrap ( ) ;
434
519
let ( server, config) = setup_test ( ) ;
@@ -460,6 +545,23 @@ mod tests {
460
545
register_signatures. expect ( "unexpected error" ) ;
461
546
}
462
547
548
+ #[ tokio:: test]
549
+ async fn test_register_signatures_ko_412 ( ) {
550
+ let ( server, config) = setup_test ( ) ;
551
+ let _snapshots_mock = server. mock ( |when, then| {
552
+ when. method ( POST ) . path ( "/register-signatures" ) ;
553
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
554
+ } ) ;
555
+ let single_signatures = fake_data:: single_signatures ( ( 1 ..5 ) . collect ( ) ) ;
556
+ let certificate_handler = CertificateHandlerHTTPClient :: new ( config. aggregator_endpoint ) ;
557
+ let error = certificate_handler
558
+ . register_signatures ( & single_signatures)
559
+ . await
560
+ . unwrap_err ( ) ;
561
+
562
+ assert ! ( error. is_api_version_mismatch( ) ) ;
563
+ }
564
+
463
565
#[ tokio:: test]
464
566
async fn test_register_signatures_ko_400 ( ) {
465
567
let single_signatures = fake_data:: single_signatures ( ( 1 ..5 ) . collect ( ) ) ;
0 commit comments