• 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 = "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