use std::io::prelude::*; use libc::off_t; use nix::sys::sendfile::*; use tempfile::tempfile; cfg_if! { if #[cfg(linux_android)] { use nix::unistd::{pipe, read}; use std::os::unix::io::AsRawFd; } else if #[cfg(any(freebsdlike, apple_targets, solarish))] { use std::net::Shutdown; use std::os::unix::net::UnixStream; } } #[cfg(linux_android)] #[test] fn test_sendfile_linux() { const CONTENTS: &[u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); let (rd, wr) = pipe().unwrap(); let mut offset: off_t = 5; let res = sendfile(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); } #[cfg(target_os = "linux")] #[test] fn test_sendfile64_linux() { const CONTENTS: &[u8] = b"abcdef123456"; let mut tmp = tempfile().unwrap(); tmp.write_all(CONTENTS).unwrap(); let (rd, wr) = pipe().unwrap(); let mut offset: libc::off64_t = 5; let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap(); assert_eq!(2, res); let mut buf = [0u8; 1024]; assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap()); assert_eq!(b"f1", &buf[0..2]); assert_eq!(7, offset); } #[cfg(target_os = "freebsd")] #[test] fn test_sendfile_freebsd() { // Declare the content let header_strings = ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; let trailer_strings = ["\n", "Served by Make Believe\n"]; // Write the body to a file let mut tmp = tempfile().unwrap(); tmp.write_all(body.as_bytes()).unwrap(); // Prepare headers and trailers for sendfile let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); // Prepare socket pair let (mut rd, wr) = UnixStream::pair().unwrap(); // Call the test method let (res, bytes_written) = sendfile( &tmp, &wr, body_offset as off_t, None, Some(headers.as_slice()), Some(trailers.as_slice()), SfFlags::empty(), 0, ); assert!(res.is_ok()); wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result let expected_string = header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); let mut read_string = String::new(); let bytes_read = rd.read_to_string(&mut read_string).unwrap(); assert_eq!(bytes_written as usize, bytes_read); assert_eq!(expected_string, read_string); } #[cfg(target_os = "dragonfly")] #[test] fn test_sendfile_dragonfly() { // Declare the content let header_strings = ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; let trailer_strings = ["\n", "Served by Make Believe\n"]; // Write the body to a file let mut tmp = tempfile().unwrap(); tmp.write_all(body.as_bytes()).unwrap(); // Prepare headers and trailers for sendfile let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); // Prepare socket pair let (mut rd, wr) = UnixStream::pair().unwrap(); // Call the test method let (res, bytes_written) = sendfile( &tmp, &wr, body_offset as off_t, None, Some(headers.as_slice()), Some(trailers.as_slice()), ); assert!(res.is_ok()); wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result let expected_string = header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); let mut read_string = String::new(); let bytes_read = rd.read_to_string(&mut read_string).unwrap(); assert_eq!(bytes_written as usize, bytes_read); assert_eq!(expected_string, read_string); } #[cfg(apple_targets)] #[test] fn test_sendfile_darwin() { // Declare the content let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1; let trailer_strings = vec!["\n", "Served by Make Believe\n"]; // Write the body to a file let mut tmp = tempfile().unwrap(); tmp.write_all(body.as_bytes()).unwrap(); // Prepare headers and trailers for sendfile let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect(); let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect(); // Prepare socket pair let (mut rd, wr) = UnixStream::pair().unwrap(); // Call the test method let (res, bytes_written) = sendfile( &tmp, &wr, body_offset as off_t, None, Some(headers.as_slice()), Some(trailers.as_slice()), ); assert!(res.is_ok()); wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result let expected_string = header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written as usize, expected_string.as_bytes().len()); let mut read_string = String::new(); let bytes_read = rd.read_to_string(&mut read_string).unwrap(); assert_eq!(bytes_written as usize, bytes_read); assert_eq!(expected_string, read_string); } #[cfg(solarish)] #[test] fn test_sendfilev() { use std::os::fd::AsFd; // Declare the content let header_strings = ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"]; let body = "Xabcdef123456"; let body_offset = 1usize; let trailer_strings = ["\n", "Served by Make Believe\n"]; // Write data to files let mut header_data = tempfile().unwrap(); header_data .write_all(header_strings.concat().as_bytes()) .unwrap(); let mut body_data = tempfile().unwrap(); body_data.write_all(body.as_bytes()).unwrap(); let mut trailer_data = tempfile().unwrap(); trailer_data .write_all(trailer_strings.concat().as_bytes()) .unwrap(); let (mut rd, wr) = UnixStream::pair().unwrap(); let vec: &[SendfileVec] = &[ SendfileVec::new( header_data.as_fd(), 0, header_strings.iter().map(|s| s.len()).sum(), ), SendfileVec::new( body_data.as_fd(), body_offset as off_t, body.len() - body_offset, ), SendfileVec::new( trailer_data.as_fd(), 0, trailer_strings.iter().map(|s| s.len()).sum(), ), ]; let (res, bytes_written) = sendfilev(&wr, vec); assert!(res.is_ok()); wr.shutdown(Shutdown::Both).unwrap(); // Prepare the expected result let expected_string = header_strings.concat() + &body[body_offset..] + &trailer_strings.concat(); // Verify the message that was sent assert_eq!(bytes_written, expected_string.as_bytes().len()); let mut read_string = String::new(); let bytes_read = rd.read_to_string(&mut read_string).unwrap(); assert_eq!(bytes_written, bytes_read); assert_eq!(expected_string, read_string); }