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 = "dragonfly", 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 =
66 vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
67 let body = "Xabcdef123456";
68 let body_offset = 1;
69 let trailer_strings = vec!["\n", "Served by Make Believe\n"];
70
71 // Write the body to a file
72 let mut tmp = tempfile().unwrap();
73 tmp.write_all(body.as_bytes()).unwrap();
74
75 // Prepare headers and trailers for sendfile
76 let headers: Vec<&[u8]> =
77 header_strings.iter().map(|s| s.as_bytes()).collect();
78 let trailers: Vec<&[u8]> =
79 trailer_strings.iter().map(|s| s.as_bytes()).collect();
80
81 // Prepare socket pair
82 let (mut rd, wr) = UnixStream::pair().unwrap();
83
84 // Call the test method
85 let (res, bytes_written) = sendfile(
86 tmp.as_raw_fd(),
87 wr.as_raw_fd(),
88 body_offset as off_t,
89 None,
90 Some(headers.as_slice()),
91 Some(trailers.as_slice()),
92 SfFlags::empty(),
93 0,
94 );
95 assert!(res.is_ok());
96 wr.shutdown(Shutdown::Both).unwrap();
97
98 // Prepare the expected result
99 let expected_string = header_strings.concat()
100 + &body[body_offset..]
101 + &trailer_strings.concat();
102
103 // Verify the message that was sent
104 assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
105
106 let mut read_string = String::new();
107 let bytes_read = rd.read_to_string(&mut read_string).unwrap();
108 assert_eq!(bytes_written as usize, bytes_read);
109 assert_eq!(expected_string, read_string);
110 }
111
112 #[cfg(target_os = "dragonfly")]
113 #[test]
test_sendfile_dragonfly()114 fn test_sendfile_dragonfly() {
115 // Declare the content
116 let header_strings =
117 vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
118 let body = "Xabcdef123456";
119 let body_offset = 1;
120 let trailer_strings = vec!["\n", "Served by Make Believe\n"];
121
122 // Write the body to a file
123 let mut tmp = tempfile().unwrap();
124 tmp.write_all(body.as_bytes()).unwrap();
125
126 // Prepare headers and trailers for sendfile
127 let headers: Vec<&[u8]> =
128 header_strings.iter().map(|s| s.as_bytes()).collect();
129 let trailers: Vec<&[u8]> =
130 trailer_strings.iter().map(|s| s.as_bytes()).collect();
131
132 // Prepare socket pair
133 let (mut rd, wr) = UnixStream::pair().unwrap();
134
135 // Call the test method
136 let (res, bytes_written) = sendfile(
137 tmp.as_raw_fd(),
138 wr.as_raw_fd(),
139 body_offset as off_t,
140 None,
141 Some(headers.as_slice()),
142 Some(trailers.as_slice()),
143 );
144 assert!(res.is_ok());
145 wr.shutdown(Shutdown::Both).unwrap();
146
147 // Prepare the expected result
148 let expected_string = header_strings.concat()
149 + &body[body_offset..]
150 + &trailer_strings.concat();
151
152 // Verify the message that was sent
153 assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
154
155 let mut read_string = String::new();
156 let bytes_read = rd.read_to_string(&mut read_string).unwrap();
157 assert_eq!(bytes_written as usize, bytes_read);
158 assert_eq!(expected_string, read_string);
159 }
160
161 #[cfg(any(target_os = "ios", target_os = "macos"))]
162 #[test]
test_sendfile_darwin()163 fn test_sendfile_darwin() {
164 // Declare the content
165 let header_strings =
166 vec!["HTTP/1.1 200 OK\n", "Content-Type: text/plain\n", "\n"];
167 let body = "Xabcdef123456";
168 let body_offset = 1;
169 let trailer_strings = vec!["\n", "Served by Make Believe\n"];
170
171 // Write the body to a file
172 let mut tmp = tempfile().unwrap();
173 tmp.write_all(body.as_bytes()).unwrap();
174
175 // Prepare headers and trailers for sendfile
176 let headers: Vec<&[u8]> =
177 header_strings.iter().map(|s| s.as_bytes()).collect();
178 let trailers: Vec<&[u8]> =
179 trailer_strings.iter().map(|s| s.as_bytes()).collect();
180
181 // Prepare socket pair
182 let (mut rd, wr) = UnixStream::pair().unwrap();
183
184 // Call the test method
185 let (res, bytes_written) = sendfile(
186 tmp.as_raw_fd(),
187 wr.as_raw_fd(),
188 body_offset as off_t,
189 None,
190 Some(headers.as_slice()),
191 Some(trailers.as_slice()),
192 );
193 assert!(res.is_ok());
194 wr.shutdown(Shutdown::Both).unwrap();
195
196 // Prepare the expected result
197 let expected_string = header_strings.concat()
198 + &body[body_offset..]
199 + &trailer_strings.concat();
200
201 // Verify the message that was sent
202 assert_eq!(bytes_written as usize, expected_string.as_bytes().len());
203
204 let mut read_string = String::new();
205 let bytes_read = rd.read_to_string(&mut read_string).unwrap();
206 assert_eq!(bytes_written as usize, bytes_read);
207 assert_eq!(expected_string, read_string);
208 }
209