261 lines
7.6 KiB
Rust
261 lines
7.6 KiB
Rust
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);
|
|
}
|