1use std::time::Duration;
5
6use crate::error::{err, ErrorCode, Result};
7use crate::keys::{keys_from_response, KeyDoc};
8use crate::lexical;
9
10const MAX_BODY: u64 = 256 * 1024;
12
13pub fn fetch_keys(host: &str) -> Result<KeyDoc> {
21 if lexical::check_dns_name(host, "host").is_err() {
22 return err(ErrorCode::KeyUnavailable, "$", format!("{host:?} is not a DNS name: no keys are resolved for it"));
23 }
24 let agent: ureq::Agent = ureq::Agent::config_builder()
25 .max_redirects(0)
26 .http_status_as_error(false)
27 .https_only(true)
28 .timeout_global(Some(Duration::from_secs(10)))
29 .build()
30 .into();
31 let url = format!("https://{host}/.well-known/datumesh.json");
32 let mut resp = match agent.get(&url).call() {
33 Ok(r) => r,
34 Err(e) => return err(ErrorCode::KeyUnavailable, "$", format!("{url}: {e}")),
35 };
36 let status = resp.status().as_u16();
37 if status != 200 {
38 return keys_from_response(host, status, None);
39 }
40 match resp.body_mut().with_config().limit(MAX_BODY).read_to_vec() {
41 Ok(body) => keys_from_response(host, status, Some(&body)),
42 Err(e) => err(ErrorCode::KeyUnavailable, "$", format!("{url}: {e}")),
43 }
44}