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