1 use std::io::prelude::*;
2 
3 use libc::off_t;
4 use nix::sys::sendfile::*;
5 use tempfile::tempfile;
6 
7 cfg_if! {
8     if #[cfg(linux_android)] {
9         use nix::unistd::{pipe, read};
10         use std::os::unix::io::AsRawFd;
11     } else if #[cfg(any(freebsdlike, apple_targets, solarish))] {
12         use std::net::Shutdown;
13         use std::os::unix::net::UnixStream;
14     }
15 }
16 
17 #[cfg(linux_android)]
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, Some(&mut offset), 2).unwrap();
27 
28     assert_eq!(2, res);
29 
30     let mut buf = [0u8; 1024];
31     assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
32     assert_eq!(b"f1", &buf[0..2]);
33     assert_eq!(7, offset);
34 }
35 
36 #[cfg(target_os = "linux")]
37 #[test]
test_sendfile64_linux()38 fn test_sendfile64_linux() {
39     const CONTENTS: &[u8] = b"abcdef123456";
40     let mut tmp = tempfile().unwrap();
41     tmp.write_all(CONTENTS).unwrap();
42 
43     let (rd, wr) = pipe().unwrap();
44     let mut offset: libc::off64_t = 5;
45     let res = sendfile64(&wr, &tmp, Some(&mut offset), 2).unwrap();
46 
47     assert_eq!(2, res);
48 
49     let mut buf = [0u8; 1024];
50     assert_eq!(2, read(rd.as_raw_fd(), &mut buf).unwrap());
51     assert_eq!(b"f1", &buf[0..2]);
52     assert_eq!(7, offset);
53 }
54 
55 #[cfg(target_os = "freebsd")]
56 #[test]
test_sendfile_freebsd()57 fn test_sendfile_freebsd() {
58     // Declare the content
59     let header_strings =
60         ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
61     let body = "Xabcdef123456";
62     let body_offset = 1;
63     let trailer_strings = ["\n", "Served by Make Believe\n"];
64 
65     // Write the body to a file
66     let mut tmp = tempfile().unwrap();
67     tmp.write_all(body.as_bytes()).unwrap();
68 
69     // Prepare headers and trailers for sendfile
70     let headers: Vec<&[u8]> =
71         header_strings.iter().map(|s| s.as_bytes()).collect();
72     let trailers: Vec<&[u8]> =
73         trailer_strings.iter().map(|s| s.as_bytes()).collect();
74 
75     // Prepare socket pair
76     let (mut rd, wr) = UnixStream::pair().unwrap();
77 
78     // Call the test method
79     let (res, bytes_written) = sendfile(
80         &tmp,
81         &wr,
82         body_offset as off_t,
83         None,
84         Some(headers.as_slice()),
85         Some(trailers.as_slice()),
86         SfFlags::empty(),
87         0,
88     );
89     assert!(res.is_ok());
90     wr.shutdown(Shutdown::Both).unwrap();
91 
92     // Prepare the expected result
93     let expected_string = header_strings.concat()
94         + &body[body_offset..]
95         + &trailer_strings.concat();
96 
97     // Verify the message that was sent
98     assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
99 
100     let mut read_string = String::new();
101     let bytes_read = rd.read_to_string(&mut read_string).unwrap();
102     assert_eq!(bytes_written as usize, bytes_read);
103     assert_eq!(expected_string, read_string);
104 }
105 
106 #[cfg(target_os = "dragonfly")]
107 #[test]
test_sendfile_dragonfly()108 fn test_sendfile_dragonfly() {
109     // Declare the content
110     let header_strings =
111         ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
112     let body = "Xabcdef123456";
113     let body_offset = 1;
114     let trailer_strings = ["\n", "Served by Make Believe\n"];
115 
116     // Write the body to a file
117     let mut tmp = tempfile().unwrap();
118     tmp.write_all(body.as_bytes()).unwrap();
119 
120     // Prepare headers and trailers for sendfile
121     let headers: Vec<&[u8]> =
122         header_strings.iter().map(|s| s.as_bytes()).collect();
123     let trailers: Vec<&[u8]> =
124         trailer_strings.iter().map(|s| s.as_bytes()).collect();
125 
126     // Prepare socket pair
127     let (mut rd, wr) = UnixStream::pair().unwrap();
128 
129     // Call the test method
130     let (res, bytes_written) = sendfile(
131         &tmp,
132         &wr,
133         body_offset as off_t,
134         None,
135         Some(headers.as_slice()),
136         Some(trailers.as_slice()),
137     );
138     assert!(res.is_ok());
139     wr.shutdown(Shutdown::Both).unwrap();
140 
141     // Prepare the expected result
142     let expected_string = header_strings.concat()
143         + &body[body_offset..]
144         + &trailer_strings.concat();
145 
146     // Verify the message that was sent
147     assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
148 
149     let mut read_string = String::new();
150     let bytes_read = rd.read_to_string(&mut read_string).unwrap();
151     assert_eq!(bytes_written as usize, bytes_read);
152     assert_eq!(expected_string, read_string);
153 }
154 
155 #[cfg(apple_targets)]
156 #[test]
test_sendfile_darwin()157 fn test_sendfile_darwin() {
158     // Declare the content
159     let header_strings =
160         vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
161     let body = "Xabcdef123456";
162     let body_offset = 1;
163     let trailer_strings = vec!["\n", "Served by Make Believe\n"];
164 
165     // Write the body to a file
166     let mut tmp = tempfile().unwrap();
167     tmp.write_all(body.as_bytes()).unwrap();
168 
169     // Prepare headers and trailers for sendfile
170     let headers: Vec<&[u8]> =
171         header_strings.iter().map(|s| s.as_bytes()).collect();
172     let trailers: Vec<&[u8]> =
173         trailer_strings.iter().map(|s| s.as_bytes()).collect();
174 
175     // Prepare socket pair
176     let (mut rd, wr) = UnixStream::pair().unwrap();
177 
178     // Call the test method
179     let (res, bytes_written) = sendfile(
180         &tmp,
181         &wr,
182         body_offset as off_t,
183         None,
184         Some(headers.as_slice()),
185         Some(trailers.as_slice()),
186     );
187     assert!(res.is_ok());
188     wr.shutdown(Shutdown::Both).unwrap();
189 
190     // Prepare the expected result
191     let expected_string = header_strings.concat()
192         + &body[body_offset..]
193         + &trailer_strings.concat();
194 
195     // Verify the message that was sent
196     assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
197 
198     let mut read_string = String::new();
199     let bytes_read = rd.read_to_string(&mut read_string).unwrap();
200     assert_eq!(bytes_written as usize, bytes_read);
201     assert_eq!(expected_string, read_string);
202 }
203 
204 #[cfg(solarish)]
205 #[test]
test_sendfilev()206 fn test_sendfilev() {
207     use std::os::fd::AsFd;
208     // Declare the content
209     let header_strings =
210         ["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
211     let body = "Xabcdef123456";
212     let body_offset = 1usize;
213     let trailer_strings = ["\n", "Served by Make Believe\n"];
214 
215     // Write data to files
216     let mut header_data = tempfile().unwrap();
217     header_data
218         .write_all(header_strings.concat().as_bytes())
219         .unwrap();
220     let mut body_data = tempfile().unwrap();
221     body_data.write_all(body.as_bytes()).unwrap();
222     let mut trailer_data = tempfile().unwrap();
223     trailer_data
224         .write_all(trailer_strings.concat().as_bytes())
225         .unwrap();
226     let (mut rd, wr) = UnixStream::pair().unwrap();
227     let vec: &[SendfileVec] = &[
228         SendfileVec::new(
229             header_data.as_fd(),
230             0,
231             header_strings.iter().map(|s| s.len()).sum(),
232         ),
233         SendfileVec::new(
234             body_data.as_fd(),
235             body_offset as off_t,
236             body.len() - body_offset,
237         ),
238         SendfileVec::new(
239             trailer_data.as_fd(),
240             0,
241             trailer_strings.iter().map(|s| s.len()).sum(),
242         ),
243     ];
244 
245     let (res, bytes_written) = sendfilev(&wr, vec);
246     assert!(res.is_ok());
247     wr.shutdown(Shutdown::Both).unwrap();
248 
249     // Prepare the expected result
250     let expected_string = header_strings.concat()
251         + &body[body_offset..]
252         + &trailer_strings.concat();
253 
254     // Verify the message that was sent
255     assert_eq!(bytes_written, expected_string.as_bytes().len());
256 
257     let mut read_string = String::new();
258     let bytes_read = rd.read_to_string(&mut read_string).unwrap();
259     assert_eq!(bytes_written, bytes_read);
260     assert_eq!(expected_string, read_string);
261 }
262