14
14
#include <assert.h>
15
15
#include <fcntl.h>
16
16
#include <ggl/alloc.h>
17
+ #include <ggl/backoff.h>
17
18
#include <ggl/base64.h>
18
19
#include <ggl/buffer.h>
19
20
#include <ggl/bump_alloc.h>
@@ -409,6 +410,81 @@ static GglError get_tes_credentials(TesCredentials *tes_creds) {
409
410
return GGL_ERR_OK ;
410
411
}
411
412
413
+ typedef struct CurlRequestRetryCtx {
414
+ const char * url_for_sigv4_download ;
415
+ GglBuffer host ;
416
+ GglBuffer file_path ;
417
+ SigV4Details sigv4_details ;
418
+
419
+ // reset response_data for next attempt
420
+ GglError (* retry_cleanup_fn )(void * );
421
+ void * response_data ;
422
+
423
+ // Needed to propagate errors when retrying is impossible.
424
+ GglError err ;
425
+ } DownloadRequestRetryCtx ;
426
+
427
+ static GglError retry_download_wrapper (void * ctx ) {
428
+ DownloadRequestRetryCtx * retry_ctx = (DownloadRequestRetryCtx * ) ctx ;
429
+ long http_response_code ;
430
+
431
+ GglError ret = sigv4_download (
432
+ retry_ctx -> url_for_sigv4_download ,
433
+ retry_ctx -> host ,
434
+ retry_ctx -> file_path ,
435
+ * (int * ) retry_ctx -> response_data ,
436
+ retry_ctx -> sigv4_details ,
437
+ & http_response_code
438
+ );
439
+ if (http_response_code == (long ) 403 ) {
440
+ GglError err = retry_ctx -> retry_cleanup_fn (retry_ctx -> response_data );
441
+ if (err != GGL_ERR_OK ) {
442
+ retry_ctx -> err = err ;
443
+ return GGL_ERR_OK ;
444
+ }
445
+ return GGL_ERR_FAILURE ;
446
+ }
447
+ if (ret != GGL_ERR_OK ) {
448
+ GGL_LOGE (
449
+ "Artifact download attempt failed due to error: %d" , ret
450
+
451
+ );
452
+ retry_ctx -> err = ret ;
453
+ return GGL_ERR_OK ;
454
+ }
455
+
456
+ retry_ctx -> err = ret ;
457
+ return GGL_ERR_OK ;
458
+ }
459
+
460
+ static GglError retriable_download_request (
461
+ const char * url_for_sigv4_download ,
462
+ GglBuffer host ,
463
+ GglBuffer file_path ,
464
+ int artifact_fd ,
465
+ SigV4Details sigv4_details
466
+ ) {
467
+ DownloadRequestRetryCtx ctx
468
+ = { .url_for_sigv4_download = url_for_sigv4_download ,
469
+ .host = host ,
470
+ .file_path = file_path ,
471
+ .sigv4_details = sigv4_details ,
472
+ .response_data = (void * ) & artifact_fd ,
473
+ .retry_cleanup_fn = truncate_file ,
474
+ .err = GGL_ERR_OK };
475
+
476
+ GglError ret
477
+ = ggl_backoff (1000 , 64000 , 3 , retry_download_wrapper , (void * ) & ctx );
478
+ if (ret != GGL_ERR_OK ) {
479
+ GGL_LOGE ("Artifact download attempt failed; retries exhausted." );
480
+ return ret ;
481
+ }
482
+ if (ctx .err != GGL_ERR_OK ) {
483
+ return ctx .err ;
484
+ }
485
+ return GGL_ERR_OK ;
486
+ }
487
+
412
488
static GglError download_s3_artifact (
413
489
GglBuffer scratch_buffer ,
414
490
GglUriInfo uri_info ,
@@ -434,7 +510,7 @@ static GglError download_s3_artifact(
434
510
return error ;
435
511
}
436
512
437
- return sigv4_download (
513
+ return retriable_download_request (
438
514
(const char * ) url_vec .buf .data ,
439
515
(GglBuffer ) { .data = & scratch_buffer .data [start_loc ],
440
516
.len = end_loc - start_loc },
0 commit comments