1
1
use async_trait:: async_trait;
2
2
use flate2:: read:: GzDecoder ;
3
3
use futures:: StreamExt ;
4
- use reqwest:: { self , StatusCode } ;
4
+ use reqwest:: { self , Response , StatusCode } ;
5
5
use reqwest:: { Client , RequestBuilder } ;
6
6
use slog_scope:: debug;
7
7
use std:: env;
@@ -48,6 +48,17 @@ pub enum AggregatorHandlerError {
48
48
/// [AggregatorHandler::download_snapshot] beforehand.
49
49
#[ error( "archive not found, did you download it beforehand ? Expected path: '{0}'" ) ]
50
50
ArchiveNotFound ( PathBuf ) ,
51
+
52
+ /// Error raised when the server API version mismatch the client API version.
53
+ #[ error( "API version mismatch: {0}" ) ]
54
+ ApiVersionMismatch ( String ) ,
55
+ }
56
+
57
+ #[ cfg( test) ]
58
+ impl AggregatorHandlerError {
59
+ pub fn is_api_version_mismatch ( & self ) -> bool {
60
+ matches ! ( self , Self :: ApiVersionMismatch ( _) )
61
+ }
51
62
}
52
63
53
64
/// AggregatorHandler represents a read interactor with an aggregator
@@ -128,6 +139,22 @@ impl AggregatorHTTPClient {
128
139
) ) ,
129
140
}
130
141
}
142
+
143
+ /// API version error handling
144
+ fn handle_api_error ( & self , response : & Response ) -> AggregatorHandlerError {
145
+ if let Some ( version) = response. headers ( ) . get ( "mithril-api-version" ) {
146
+ AggregatorHandlerError :: ApiVersionMismatch ( format ! (
147
+ "server version: '{}', signer version: '{}'" ,
148
+ version. to_str( ) . unwrap( ) ,
149
+ MITHRIL_API_VERSION
150
+ ) )
151
+ } else {
152
+ AggregatorHandlerError :: ApiVersionMismatch ( format ! (
153
+ "version precondition failed, sent version '{}'." ,
154
+ MITHRIL_API_VERSION
155
+ ) )
156
+ }
157
+ }
131
158
}
132
159
133
160
#[ async_trait]
@@ -147,6 +174,7 @@ impl AggregatorHandler for AggregatorHTTPClient {
147
174
Ok ( snapshots) => Ok ( snapshots) ,
148
175
Err ( err) => Err ( AggregatorHandlerError :: JsonParseFailed ( err. to_string ( ) ) ) ,
149
176
} ,
177
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
150
178
status_error => Err ( AggregatorHandlerError :: RemoteServerTechnical (
151
179
status_error. to_string ( ) ,
152
180
) ) ,
@@ -172,6 +200,7 @@ impl AggregatorHandler for AggregatorHTTPClient {
172
200
Ok ( snapshot) => Ok ( snapshot) ,
173
201
Err ( err) => Err ( AggregatorHandlerError :: JsonParseFailed ( err. to_string ( ) ) ) ,
174
202
} ,
203
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
175
204
StatusCode :: NOT_FOUND => Err ( AggregatorHandlerError :: RemoteServerLogical (
176
205
"snapshot not found" . to_string ( ) ,
177
206
) ) ,
@@ -226,6 +255,7 @@ impl AggregatorHandler for AggregatorHTTPClient {
226
255
}
227
256
Ok ( local_path. into_os_string ( ) . into_string ( ) . unwrap ( ) )
228
257
}
258
+ StatusCode :: PRECONDITION_FAILED => Err ( self . handle_api_error ( & response) ) ,
229
259
StatusCode :: NOT_FOUND => Err ( AggregatorHandlerError :: RemoteServerLogical (
230
260
"snapshot archive not found" . to_string ( ) ,
231
261
) ) ,
@@ -352,6 +382,20 @@ mod tests {
352
382
assert_eq ! ( snapshots. unwrap( ) , snapshots_expected) ;
353
383
}
354
384
385
+ #[ tokio:: test]
386
+ async fn test_list_snapshots_ko_412 ( ) {
387
+ let ( server, config) = setup_test ( ) ;
388
+ let _snapshots_mock = server. mock ( |when, then| {
389
+ when. path ( "/snapshots" ) ;
390
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
391
+ } ) ;
392
+ let aggregator_client =
393
+ AggregatorHTTPClient :: new ( config. network , config. aggregator_endpoint ) ;
394
+ let error = aggregator_client. list_snapshots ( ) . await . unwrap_err ( ) ;
395
+
396
+ assert ! ( error. is_api_version_mismatch( ) ) ;
397
+ }
398
+
355
399
#[ tokio:: test]
356
400
async fn test_list_snapshots_ko_500 ( ) {
357
401
let ( server, config) = setup_test ( ) ;
@@ -403,6 +447,24 @@ mod tests {
403
447
assert ! ( snapshot. is_err( ) ) ;
404
448
}
405
449
450
+ #[ tokio:: test]
451
+ async fn test_snapshot_details_ko_412 ( ) {
452
+ let ( server, config) = setup_test ( ) ;
453
+ let digest = "digest123" ;
454
+ let _snapshots_mock = server. mock ( |when, then| {
455
+ when. path ( format ! ( "/snapshot/{}" , digest) ) ;
456
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
457
+ } ) ;
458
+ let aggregator_client =
459
+ AggregatorHTTPClient :: new ( config. network , config. aggregator_endpoint ) ;
460
+ let error = aggregator_client
461
+ . get_snapshot_details ( digest)
462
+ . await
463
+ . unwrap_err ( ) ;
464
+
465
+ assert ! ( error. is_api_version_mismatch( ) ) ;
466
+ }
467
+
406
468
#[ tokio:: test]
407
469
async fn get_snapshot_details_ko_500 ( ) {
408
470
let digest = "digest123" ;
@@ -448,6 +510,26 @@ mod tests {
448
510
assert_eq ! ( data_downloaded, data_expected) ;
449
511
}
450
512
513
+ #[ tokio:: test]
514
+ async fn test_download_snapshot_ko_412 ( ) {
515
+ let ( server, config) = setup_test ( ) ;
516
+ let digest = "digest123" ;
517
+ let url_path = "/download" ;
518
+ let _snapshots_mock = server. mock ( |when, then| {
519
+ when. path ( url_path. to_string ( ) ) ;
520
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
521
+ } ) ;
522
+ let aggregator_client =
523
+ AggregatorHTTPClient :: new ( config. network , config. aggregator_endpoint ) ;
524
+ let location = server. url ( url_path) ;
525
+ let error = aggregator_client
526
+ . download_snapshot ( digest, & location)
527
+ . await
528
+ . unwrap_err ( ) ;
529
+
530
+ assert ! ( error. is_api_version_mismatch( ) ) ;
531
+ }
532
+
451
533
#[ tokio:: test]
452
534
async fn get_download_snapshot_ko_unreachable ( ) {
453
535
let digest = "digest123" ;
@@ -502,6 +584,22 @@ mod tests {
502
584
assert ! ( local_dir_path. is_err( ) ) ;
503
585
}
504
586
587
+ #[ tokio:: test]
588
+ async fn test_certificate_details_412 ( ) {
589
+ let ( server, config) = setup_test ( ) ;
590
+ let certificate_hash = "certificate-hash-123" ;
591
+ let _snapshots_mock = server. mock ( |when, then| {
592
+ when. path ( format ! ( "/certificate/{}" , certificate_hash) ) ;
593
+ then. status ( 412 ) . header ( "mithril-api-version" , "0.0.999" ) ;
594
+ } ) ;
595
+ let aggregator_client =
596
+ AggregatorHTTPClient :: new ( config. network , config. aggregator_endpoint ) ;
597
+ let _error = aggregator_client
598
+ . get_certificate_details ( certificate_hash)
599
+ . await
600
+ . unwrap_err ( ) ;
601
+ }
602
+
505
603
#[ tokio:: test]
506
604
async fn get_certificate_details_ok ( ) {
507
605
let certificate_hash = "certificate-hash-123" ;
0 commit comments