Revision control
Copy as Markdown
Other Tools
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);
}