toolkit: no thread panic in http_fetch, no casts, exact egress-proxy form

Implemented-By: OpenCode session (model recorded in docs/implementer-log.md)
This commit is contained in:
2026-09-23 16:13:43 -07:00
parent e69ba632e6
commit 9662966b45
6 changed files with 62 additions and 4 deletions
+10 -1
View File
@@ -80,7 +80,16 @@ pub fn fetch_with(curl: &Path, args: &HttpFetchArgs) -> Outcome {
Some(r) => r,
None => return Outcome::tool_error("http_fetch: curl has no standard error".to_string()),
};
let stderr_handle = std::thread::spawn(move || read_capped(stderr_reader));
// `Builder`, not `spawn`, which panics when the system refuses a thread.
let stderr_handle = match std::thread::Builder::new().spawn(move || read_capped(stderr_reader))
{
Ok(handle) => handle,
Err(e) => {
let _ = child.kill();
let _ = child.wait();
return Outcome::tool_error(format!("http_fetch: cannot start a thread: {e}"));
}
};
let mut body = Vec::new();
let mut stdout = match child.stdout.take() {
+4 -1
View File
@@ -35,7 +35,10 @@ pub fn read_file(args: &ReadFileArgs) -> Outcome {
};
let mut buf = Vec::new();
let n = match file.take(MAX_READ as u64 + 1).read_to_end(&mut buf) {
let n = match file
.take(u64::try_from(MAX_READ).map_or(u64::MAX, |n| n.saturating_add(1)))
.read_to_end(&mut buf)
{
Err(e) => return tool_err("read_file", path, &e.to_string()),
Ok(n) => n,
};
+3 -1
View File
@@ -33,7 +33,9 @@ impl From<std::io::Error> for InputError {
/// (`Read::take`); more than MAX_INPUT is TooLarge.
pub fn read_input(stdin: &mut dyn std::io::Read) -> Result<String, InputError> {
let mut buf = Vec::new();
let n = stdin.take(MAX_INPUT as u64 + 1).read_to_end(&mut buf)?;
let n = stdin
.take(u64::try_from(MAX_INPUT).map_or(u64::MAX, |n| n.saturating_add(1)))
.read_to_end(&mut buf)?;
if n > MAX_INPUT {
return Err(InputError::TooLarge);
}
+2 -1
View File
@@ -18,7 +18,8 @@ fn main() -> ExitCode {
/// The `egress-proxy --socket <path> --allow <list>` form. Anything else, including a program name
/// that is not `egress-proxy`, returns `None` so the tool form handles it.
fn parse_egress_proxy(args: &[OsString]) -> Option<ExitCode> {
if args.first()?.as_bytes() != b"egress-proxy" {
// Exactly five words: a longer list is not this form, and goes to the tool form (exit 2).
if args.len() != 5 || args.first()?.as_bytes() != b"egress-proxy" {
return None;
}
// The form is `egress-proxy --socket <path> --allow <list>`, in that order.