• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 use std::io::prelude::*;
2 use std::os::unix::prelude::*;
3 
4 use libc::off_t;
5 use nix::sys::sendfile::*;
6 use tempfile::tempfile;
7 
8 cfg_if! {
9     if #[cfg(any(target_os = "android", target_os = "linux"))] {
10         use nix::unistd::{close, pipe, read};
11     } else if #[cfg(any(target_os = "freebsd", target_os = "ios", target_os = "macos"))] {
12         use std::net::Shutdown;
13         use std::os::unix::net::UnixStream;
14     }
15 }
16 
17 #[cfg(any(target_os = "android", target_os = "linux"))]
18 #[test]
test_sendfile_linux()19 fn test_sendfile_linux() {
20     const CONTENTS: &[u8] = b"abcdef123456";
21     let mut tmp = tempfile().unwrap();
22     tmp.write_all(CONTENTS).unwrap();
23 
24     let (rd, wr) = pipe().unwrap();
25     let mut offset: off_t = 5;
26     let res = sendfile(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
27 
28     assert_eq!(2, res);
29 
30     let mut buf = [0u8; 1024];
31     assert_eq!(2, read(rd, &mut buf).unwrap());
32     assert_eq!(b"f1", &buf[0..2]);
33     assert_eq!(7, offset);
34 
35     close(rd).unwrap();
36     close(wr).unwrap();
37 }
38 
39 #[cfg(target_os = "linux")]
40 #[test]
test_sendfile64_linux()41 fn test_sendfile64_linux() {
42     const CONTENTS: &[u8] = b"abcdef123456";
43     let mut tmp = tempfile().unwrap();
44     tmp.write_all(CONTENTS).unwrap();
45 
46     let (rd, wr) = pipe().unwrap();
47     let mut offset: libc::off64_t = 5;
48     let res = sendfile64(wr, tmp.as_raw_fd(), Some(&mut offset), 2).unwrap();
49 
50     assert_eq!(2, res);
51 
52     let mut buf = [0u8; 1024];
53     assert_eq!(2, read(rd, &mut buf).unwrap());
54     assert_eq!(b"f1", &buf[0..2]);
55     assert_eq!(7, offset);
56 
57     close(rd).unwrap();
58     close(wr).unwrap();
59 }
60 
61 #[cfg(target_os = "freebsd")]
62 #[test]
test_sendfile_freebsd()63 fn test_sendfile_freebsd() {
64     // Declare the content
65     let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
66     let body = "Xabcdef123456";
67     let body_offset = 1;
68     let trailer_strings = vec!["\n", "Served by Make Believe\n"];
69 
70     // Write the body to a file
71     let mut tmp = tempfile().unwrap();
72     tmp.write_all(body.as_bytes()).unwrap();
73 
74     // Prepare headers and trailers for sendfile
75     let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
76     let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
77 
78     // Prepare socket pair
79     let (mut rd, wr) = UnixStream::pair().unwrap();
80 
81     // Call the test method
82     let (res, bytes_written) = sendfile(
83         tmp.as_raw_fd(),
84         wr.as_raw_fd(),
85         body_offset as off_t,
86         None,
87         Some(headers.as_slice()),
88         Some(trailers.as_slice()),
89         SfFlags::empty(),
90         0,
91     );
92     assert!(res.is_ok());
93     wr.shutdown(Shutdown::Both).unwrap();
94 
95     // Prepare the expected result
96     let expected_string =
97         header_strings.concat() + &body[body_offset..] + &trailer_strings.concat();
98 
99     // Verify the message that was sent
100     assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
101 
102     let mut read_string = String::new();
103     let bytes_read = rd.read_to_string(&mut read_string).unwrap();
104     assert_eq!(bytes_written as usize, bytes_read);
105     assert_eq!(expected_string, read_string);
106 }
107 
108 #[cfg(any(target_os = "ios", target_os = "macos"))]
109 #[test]
test_sendfile_darwin()110 fn test_sendfile_darwin() {
111     // Declare the content
112     let header_strings = vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
113     let body = "Xabcdef123456";
114     let body_offset = 1;
115     let trailer_strings = vec!["\n", "Served by Make Believe\n"];
116 
117     // Write the body to a file
118     let mut tmp = tempfile().unwrap();
119     tmp.write_all(body.as_bytes()).unwrap();
120 
121     // Prepare headers and trailers for sendfile
122     let headers: Vec<&[u8]> = header_strings.iter().map(|s| s.as_bytes()).collect();
123     let trailers: Vec<&[u8]> = trailer_strings.iter().map(|s| s.as_bytes()).collect();
124 
125     // Prepare socket pair
126     let (mut rd, wr) = UnixStream::pair().unwrap();
127 
128     // Call the test method
129     let (res, bytes_written) = sendfile(
130         tmp.as_raw_fd(),
131         wr.as_raw_fd(),
132         body_offset as off_t,
133         None,
134         Some(headers.as_slice()),
135         Some(trailers.as_slice()),
136     );
137     assert!(res.is_ok());
138     wr.shutdown(Shutdown::Both).unwrap();
139 
140     // Prepare the expected result
141     let expected_string =
142         header_strings.concat() + &body[body_offset..] + &trailer_strings.concat();
143 
144     // Verify the message that was sent
145     assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
146 
147     let mut read_string = String::new();
148     let bytes_read = rd.read_to_string(&mut read_string).unwrap();
149     assert_eq!(bytes_written as usize, bytes_read);
150     assert_eq!(expected_string, read_string);
151 }
152