1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
use std::{
fs,
io::{self, Error, ErrorKind, Read},
path::Path,
};
/// Download a file from the given URL and return the data.
pub fn download(url: impl AsRef<str>) -> io::Result<Vec<u8>> {
let url = url.as_ref();
// `file` URL, empty hostname, absolute path
if let Some(file_path) = url.strip_prefix("file://") {
return fs::read(Path::new(file_path));
}
// `file` URLs with non-empty hostname or relative paths are unsupported.
if url.starts_with("file:") {
eprintln!("Unsupported file: URL {}", url);
return Err(Error::from(ErrorKind::Unsupported));
}
let resp = std::process::Command::new("curl")
// follow redirects
.arg("-L")
// fail fast with no "error pages" output. more of a hint though, so we might still get error on stdout.
// so make sure to check the actual status returned.
.arg("-f")
// silent. no progress or error messages. only pure "response data"
.arg("-s")
.arg(url)
.output();
match resp {
Ok(out) => {
// ideally, we would redirect response to a file directly, but lets take it one step at a time.
let result = out.stdout;
if out.status.success() {
Ok(result)
} else {
Err(io::Error::new(
io::ErrorKind::Other,
format!(
"curl error code: {:?}\ncurl stderr: {:?}",
out.status.code(),
std::str::from_utf8(&out.stderr)
),
))
}
}
Err(e) => Err(io::Error::new(
io::ErrorKind::Other,
format!("curl command error : {e:#?}"),
)),
}
}