Skip to main content

idt/downloaders/
http.rs

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