@@ -215,6 +215,16 @@ func calculateHashForPartialFile(file *os.File) (hash.Hash, error) {
215
215
return hash , nil
216
216
}
217
217
218
+ func (uri URI ) checkSeverSupportsRangeHeader () (bool , error ) {
219
+ url := uri .ResolveURL ()
220
+ resp , err := http .Head (url )
221
+ if err != nil {
222
+ return false , err
223
+ }
224
+ defer resp .Body .Close ()
225
+ return resp .Header .Get ("Accept-Ranges" ) == "bytes" , nil
226
+ }
227
+
218
228
func (uri URI ) DownloadFile (filePath , sha string , fileN , total int , downloadStatus func (string , string , string , float64 )) error {
219
229
url := uri .ResolveURL ()
220
230
if uri .LooksLikeOCI () {
@@ -282,21 +292,23 @@ func (uri URI) DownloadFile(filePath, sha string, fileN, total int, downloadStat
282
292
return fmt .Errorf ("failed to create request for %q: %v" , filePath , err )
283
293
}
284
294
285
- /* TODO
286
- * 1. ~~Mock downloads~~
287
- * 2. Check if server supports partial downloads
288
- * 3. ~~Resume partial downloads~~
289
- * 4. Ensure progressWriter accurately reflects progress if a partial file is present
290
- * 5. MAYBE:
291
- * a. Delete file if calculatedSHA != sha
292
- */
293
-
294
295
// save partial download to dedicated file
295
296
tmpFilePath := filePath + ".partial"
296
297
tmpFileInfo , err := os .Stat (tmpFilePath )
297
298
if err == nil {
298
- startPos := tmpFileInfo .Size ()
299
- req .Header .Set ("Range" , fmt .Sprintf ("bytes=%d-" , startPos ))
299
+ support , err := uri .checkSeverSupportsRangeHeader ()
300
+ if err != nil {
301
+ return fmt .Errorf ("failed to check if uri server supports range header: %v" , err )
302
+ }
303
+ if support {
304
+ startPos := tmpFileInfo .Size ()
305
+ req .Header .Set ("Range" , fmt .Sprintf ("bytes=%d-" , startPos ))
306
+ } else {
307
+ err := removePartialFile (tmpFilePath )
308
+ if err != nil {
309
+ return err
310
+ }
311
+ }
300
312
} else if ! errors .Is (err , os .ErrNotExist ) {
301
313
return fmt .Errorf ("failed to check file %q existence: %v" , filePath , err )
302
314
}
@@ -341,6 +353,11 @@ func (uri URI) DownloadFile(filePath, sha string, fileN, total int, downloadStat
341
353
return fmt .Errorf ("failed to write file %q: %v" , filePath , err )
342
354
}
343
355
356
+ err = os .Rename (tmpFilePath , filePath )
357
+ if err != nil {
358
+ return fmt .Errorf ("failed to rename temporary file %s -> %s: %v" , tmpFilePath , filePath , err )
359
+ }
360
+
344
361
if sha != "" {
345
362
// Verify SHA
346
363
calculatedSHA := fmt .Sprintf ("%x" , progress .hash .Sum (nil ))
@@ -352,11 +369,6 @@ func (uri URI) DownloadFile(filePath, sha string, fileN, total int, downloadStat
352
369
log .Debug ().Msgf ("SHA missing for %q. Skipping validation" , filePath )
353
370
}
354
371
355
- err = os .Rename (tmpFilePath , filePath )
356
- if err != nil {
357
- return fmt .Errorf ("failed to rename temporary file %s -> %s: %v" , tmpFilePath , filePath , err )
358
- }
359
-
360
372
log .Info ().Msgf ("File %q downloaded and verified" , filePath )
361
373
if utils .IsArchive (filePath ) {
362
374
basePath := filepath .Dir (filePath )
0 commit comments