Skip to main content

idt/downloaders/
http.rs

1use std::fs::File;
2use std::path::PathBuf;
3
4use deflate::ChecksumSource;
5use deflate::HttpDeflateOption;
6use rootcause::prelude::ResultExt;
7
8pub mod deflate;
9pub mod github;
10
11/// Downloads a file from the given URL with the specified [`HttpDeflateOption`].
12///
13/// The file is always downloaded to a temporary location first. If a [`ChecksumSource`] is provided,
14/// the SHA256 checksum is verified before processing. If `checksum` is `None`, processing proceeds
15/// without verification.
16///
17/// # Errors
18/// - The HTTP request fails or returns a non-success status.
19/// - Decompression or archive extraction fails.
20/// - A filesystem operation (create/read/write/remove) fails.
21/// - Checksum verification fails (mismatch).
22/// - Creating a temporary directory fails.
23pub fn run(
24    url: &str,
25    deflate_opt: &HttpDeflateOption,
26    checksum: Option<&ChecksumSource>,
27) -> rootcause::Result<PathBuf> {
28    // Phase 1: Download to a temporary file.
29    let tmp_dir = tempfile::tempdir().context("error creating tmp dir for download")?;
30    let tmp_file = tmp_dir.path().join("download");
31
32    let resp = ureq::get(url)
33        .call()
34        .context("error downloading")
35        .attach_with(|| format!("url={url}"))?;
36
37    let mut file = File::create(&tmp_file).context("error creating tmp file")?;
38    std::io::copy(&mut resp.into_body().as_reader(), &mut file)
39        .context("error writing download to tmp file")
40        .attach_with(|| format!("url={url}"))?;
41
42    // Phase 2: Checksum verification (only when a source is provided).
43    if let Some(source) = checksum {
44        let expected = crate::downloaders::checksum::download_and_find_checksum(source.checksums_url, source.filename)?;
45        crate::downloaders::checksum::verify(&tmp_file, &expected)?;
46    }
47
48    // Phase 3: Process the downloaded file according to the option.
49    deflate_opt.process(&tmp_file)
50}