Skip to content

Commit 20c74d0

Browse files
linesightclaude
andcommitted
download_cef: add HTTP Range resume support and increase retries
Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
1 parent b33250e commit 20c74d0

1 file changed

Lines changed: 49 additions & 12 deletions

File tree

tools/download_cef.py

Lines changed: 49 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
import hashlib
3838
import json
3939
import os
40+
import time
4041
import sys
4142
import tarfile
4243
import zipfile
@@ -195,33 +196,70 @@ def find_in_index(cef_version, cef_postfix2):
195196
sys.exit(1)
196197

197198

198-
def download(url, dest_path, expected_size=0, max_retries=3):
199-
"""Download url to dest_path with a progress bar, retrying on failure."""
199+
def download(url, dest_path, expected_size=0, max_retries=50):
200+
"""Download url to dest_path with a progress bar and resume support."""
200201
try:
201-
from urllib.request import urlopen
202+
from urllib.request import Request, urlopen
202203
except ImportError:
203-
from urllib2 import urlopen
204+
from urllib2 import Request, urlopen
204205

205206
log("Downloading: {}".format(url))
207+
208+
total = expected_size
209+
downloaded = 0
210+
chunk_size = 1024 * 1024 # 1 MB
211+
212+
# Resume from an existing partial file if present
213+
if os.path.isfile(dest_path):
214+
downloaded = os.path.getsize(dest_path)
215+
if total and downloaded >= total:
216+
log("Already fully downloaded: {}".format(os.path.basename(dest_path)))
217+
return
218+
if downloaded > 0:
219+
log("Resuming from {:.1f} MB...".format(downloaded / (1024 * 1024)))
220+
206221
for attempt in range(1, max_retries + 1):
207222
if attempt > 1:
208-
log("Retry {}/{}: {}".format(attempt, max_retries, url))
223+
# Re-check how much we have on disk after a failed attempt
224+
if os.path.isfile(dest_path):
225+
downloaded = os.path.getsize(dest_path)
226+
log("Retry {}/{} (resuming from {:.1f} MB): {}".format(
227+
attempt, max_retries, downloaded / (1024 * 1024), url))
228+
229+
req = Request(url)
230+
if downloaded > 0:
231+
req.add_header("Range", "bytes={}-".format(downloaded))
232+
209233
try:
210-
response = urlopen(url, timeout=120)
234+
response = urlopen(req, timeout=120)
211235
except Exception as exc:
212236
if attempt == max_retries:
213237
log("ERROR: Download failed: {}".format(exc))
214238
sys.exit(1)
215239
log("WARNING: Connection error (attempt {}): {}".format(attempt, exc))
240+
time.sleep(2)
216241
continue
217242

218-
total = int(response.headers.get("Content-Length") or expected_size or 0)
219-
downloaded = 0
220-
chunk_size = 1024 * 1024 # 1 MB
243+
# Determine total size from response
244+
content_range = response.headers.get("Content-Range")
245+
if content_range:
246+
# e.g. "bytes 100-200/614600000"
247+
try:
248+
total = int(content_range.rsplit("/", 1)[-1])
249+
except (ValueError, IndexError):
250+
pass
251+
else:
252+
total = int(response.headers.get("Content-Length") or total or 0)
253+
if downloaded > 0:
254+
# Server didn't honour Range; start over
255+
log("WARNING: Server ignored Range header, restarting download.")
256+
downloaded = 0
257+
221258
error = None
222259

223260
try:
224-
with open(dest_path, "wb") as fp:
261+
mode = "ab" if downloaded > 0 else "wb"
262+
with open(dest_path, mode) as fp:
225263
while True:
226264
chunk = response.read(chunk_size)
227265
if not chunk:
@@ -239,12 +277,11 @@ def download(url, dest_path, expected_size=0, max_retries=3):
239277
downloaded / (1024 * 1024), total / (1024 * 1024))
240278

241279
if error is not None:
242-
if os.path.isfile(dest_path):
243-
os.remove(dest_path)
244280
if attempt == max_retries:
245281
log("ERROR: Download failed: {}".format(error))
246282
sys.exit(1)
247283
log("WARNING: Download incomplete (attempt {}): {}".format(attempt, error))
284+
time.sleep(2)
248285
continue
249286

250287
log("Saved: {}".format(os.path.basename(dest_path)))

0 commit comments

Comments
 (0)