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