diff options
Diffstat (limited to 'src/platform/linux.rs')
| -rw-r--r-- | src/platform/linux.rs | 77 |
1 files changed, 69 insertions, 8 deletions
diff --git a/src/platform/linux.rs b/src/platform/linux.rs index 4d2ed049..8e5ad7a6 100644 --- a/src/platform/linux.rs +++ b/src/platform/linux.rs @@ -4,7 +4,10 @@ use std::{ process::{Command, Stdio}, }; -use super::{ClipboardCommand, ClipboardImage, ForegroundJob, ForegroundProcess, Signal}; +use super::{ + read_limited_reader, ClipboardCommand, ClipboardImage, ForegroundJob, ForegroundProcess, + LimitedRead, Signal, +}; /// Collect the foreground terminal job for a given child PID. pub fn foreground_job(child_pid: u32) -> Option<ForegroundJob> { @@ -221,17 +224,53 @@ fn run_notification_command(mut command: Command) -> std::io::Result<bool> { } fn read_clipboard_image_with_command(program: &str, args: &[&str]) -> Option<Vec<u8>> { - let output = Command::new(program) - .args(args) + let mut command = Command::new(program); + command.args(args); + read_clipboard_image_with_spawned_command(command) +} + +fn read_clipboard_image_with_spawned_command(command: Command) -> Option<Vec<u8>> { + read_clipboard_image_with_spawned_command_max( + command, + crate::server::protocol::MAX_CLIPBOARD_IMAGE_PAYLOAD, + ) +} + +fn read_clipboard_image_with_spawned_command_max( + mut command: Command, + max_bytes: usize, +) -> Option<Vec<u8>> { + let mut child = command .stdin(Stdio::null()) + .stdout(Stdio::piped()) .stderr(Stdio::null()) - .output() + .spawn() .ok()?; + let stdout = child.stdout.take()?; + + let read = match read_limited_reader(stdout, max_bytes) { + Ok(read) => read, + Err(_) => { + let _ = child.kill(); + let _ = child.wait(); + return None; + } + }; - if output.status.success() && !output.stdout.is_empty() { - Some(output.stdout) - } else { - None + if read == LimitedRead::Oversized { + let _ = child.kill(); + let _ = child.wait(); + return None; + } + + let status = child.wait().ok()?; + if !status.success() { + return None; + } + + match read { + LimitedRead::Complete(bytes) => Some(bytes), + LimitedRead::Empty | LimitedRead::Oversized => None, } } @@ -330,6 +369,28 @@ mod tests { } #[test] + fn read_clipboard_image_with_spawned_command_reads_under_limit() { + let mut command = Command::new("sh"); + command.arg("-c").arg("printf image"); + + assert_eq!( + read_clipboard_image_with_spawned_command_max(command, 16), + Some(b"image".to_vec()) + ); + } + + #[test] + fn read_clipboard_image_with_spawned_command_rejects_over_limit() { + let mut command = Command::new("sh"); + command.arg("-c").arg("printf oversized"); + + assert_eq!( + read_clipboard_image_with_spawned_command_max(command, 4), + None + ); + } + + #[test] fn desktop_notification_separates_option_like_titles() { let _guard = env_lock().lock().unwrap(); unsafe { |
