diff --git a/Cargo.lock b/Cargo.lock index 19c4895..496334c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -946,9 +946,9 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.4.0" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "972d7902c8735f2695410b8aed7df6ed12a47394aa1c8d7af49f0497b731a94d" +checksum = "9a7ac20be9b7726e0bbdbf974c059676d9acb1cd414961f570a4e8231cacd7fc" dependencies = [ "base64", "cookie_store", diff --git a/src/online.rs b/src/online.rs index 64dc9b2..c3e5ea5 100644 --- a/src/online.rs +++ b/src/online.rs @@ -287,6 +287,10 @@ fn hardened_agent(pinned: Vec) -> ureq::Agent { .max_redirects(0) .timeout_connect(Some(Duration::from_secs(10))) .timeout_recv_response(Some(Duration::from_secs(TIMEOUT_SECS))) + // Since ureq 3.4.1 (#1194) recv_response bounds only the HEADERS; without + // a body deadline a stalled reply hangs the POST forever. The JSON key + // answer arrives in one read, so a TOTAL cap is the right shape here. + .timeout_recv_body(Some(Duration::from_secs(TIMEOUT_SECS))) .build(); // `with_parts`, never `new_with_config` — see [`PinnedResolver`]. ureq::Agent::with_parts(config, DefaultConnector::new(), PinnedResolver(pinned)) @@ -917,6 +921,22 @@ mod tests { ); } + // The POST reply body has its own deadline, not just the headers: ureq + // 3.4.1+ recv_response covers headers only, so without recv_body a stalled + // reply would hang the key request forever. + #[test] + fn the_reply_body_read_is_bounded_not_only_the_headers() { + let agent = hardened_agent(Vec::new()); + let t = agent.config().timeouts(); + assert_eq!( + t.recv_body, + Some(Duration::from_secs(TIMEOUT_SECS)), + "ureq 3.4.1+ recv_response covers headers only; without recv_body the \ + reply read has no deadline at all" + ); + assert_eq!(t.recv_response, Some(Duration::from_secs(TIMEOUT_SECS))); + } + #[test] fn resolve_and_guard_accepts_public_literal() { // Public numeric hosts resolve without DNS — must be accepted.