mirror of
https://github.com/openai/codex.git
synced 2026-11-01 19:33:35 +00:00
Make exec-server file reads cancellable between chunks (#49696)
## What changed Run direct `read_file` operations in a blocking task with bounded read chunks and cancellation checks. Dropping the async caller cancels further reads between chunks. Preserve the 512 MiB size limit, symlink-following options, and regular-file validation. ## Testing Add regression coverage for 4 MiB reads and oversized-file rejection with both symlink-following options, cancellation after the first chunk, and FIFO rejection without waiting for a writer. GitOrigin-RevId: 19f2816de15a03bd89b463de6b002367e6a692a9
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
mod common;
|
||||
|
||||
#[cfg(unix)]
|
||||
use anyhow::Context;
|
||||
use anyhow::Result;
|
||||
use codex_exec_server::Environment;
|
||||
use codex_exec_server::ExecServerClient;
|
||||
@@ -77,12 +79,14 @@ async fn completed_streams_release_handle_capacity() -> Result<()> {
|
||||
}
|
||||
|
||||
#[cfg(unix)]
|
||||
#[test_case::test_case(true ; "follow")]
|
||||
#[test_case::test_case(false ; "no_follow")]
|
||||
#[tokio::test]
|
||||
async fn file_reads_reject_fifo_without_waiting_for_a_writer() -> Result<()> {
|
||||
async fn file_reads_reject_fifo_without_waiting_for_a_writer(follow_symlinks: bool) -> Result<()> {
|
||||
let server = exec_server().await?;
|
||||
let file_system = connect_file_system(server.websocket_url())?;
|
||||
let tmp = TempDir::new()?;
|
||||
let path = tmp.path().join("named-pipe");
|
||||
let path = tmp.path().canonicalize()?.join("named-pipe");
|
||||
let output = std::process::Command::new("mkfifo").arg(&path).output()?;
|
||||
if !output.status.success() {
|
||||
anyhow::bail!(
|
||||
@@ -93,26 +97,37 @@ async fn file_reads_reject_fifo_without_waiting_for_a_writer() -> Result<()> {
|
||||
}
|
||||
|
||||
let path_uri = PathUri::from_host_native_path(&path)?;
|
||||
let read_error = timeout(
|
||||
let read_result = timeout(
|
||||
Duration::from_secs(1),
|
||||
file_system.read_file(&path_uri, ReadFileOptions::default(), /*sandbox*/ None),
|
||||
file_system.read_file(
|
||||
&path_uri,
|
||||
ReadFileOptions { follow_symlinks },
|
||||
/*sandbox*/ None,
|
||||
),
|
||||
)
|
||||
.await
|
||||
.expect("reading a FIFO should not wait for a writer")
|
||||
.expect_err("reading a FIFO should be rejected");
|
||||
.context("reading a FIFO should not wait for a writer")?;
|
||||
let Err(read_error) = read_result else {
|
||||
panic!("reading a FIFO should be rejected");
|
||||
};
|
||||
let stream_result = timeout(
|
||||
Duration::from_secs(1),
|
||||
file_system.read_file_stream(&path_uri, /*sandbox*/ None),
|
||||
)
|
||||
.await
|
||||
.expect("streaming a FIFO should not wait for a writer");
|
||||
.context("streaming a FIFO should not wait for a writer")?;
|
||||
let Err(stream_error) = stream_result else {
|
||||
panic!("streaming a FIFO should be rejected");
|
||||
};
|
||||
let expected = format!("path `{}` is not a file", path.display());
|
||||
let expected_read = if follow_symlinks {
|
||||
expected.clone()
|
||||
} else {
|
||||
"path is not a regular file".to_string()
|
||||
};
|
||||
assert_eq!(
|
||||
(read_error.to_string(), stream_error.to_string()),
|
||||
(expected.clone(), expected)
|
||||
(expected_read, expected)
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user