1 mod support;
2 use std::io::Read;
3 use support::*;
4
5 #[tokio::test]
brotli_response()6 async fn brotli_response() {
7 brotli_case(10_000, 4096).await;
8 }
9
10 #[tokio::test]
brotli_single_byte_chunks()11 async fn brotli_single_byte_chunks() {
12 brotli_case(10, 1).await;
13 }
14
15 #[tokio::test]
test_brotli_empty_body()16 async fn test_brotli_empty_body() {
17 let server = server::http(move |req| async move {
18 assert_eq!(req.method(), "HEAD");
19
20 http::Response::builder()
21 .header("content-encoding", "br")
22 .header("content-length", 100)
23 .body(Default::default())
24 .unwrap()
25 });
26
27 let client = reqwest::Client::new();
28 let res = client
29 .head(&format!("http://{}/brotli", server.addr()))
30 .send()
31 .await
32 .unwrap();
33
34 let body = res.text().await.unwrap();
35
36 assert_eq!(body, "");
37 }
38
39 #[tokio::test]
test_accept_header_is_not_changed_if_set()40 async fn test_accept_header_is_not_changed_if_set() {
41 let server = server::http(move |req| async move {
42 assert_eq!(req.headers()["accept"], "application/json");
43 assert!(req.headers()["accept-encoding"]
44 .to_str()
45 .unwrap()
46 .contains("br"));
47 http::Response::default()
48 });
49
50 let client = reqwest::Client::new();
51
52 let res = client
53 .get(&format!("http://{}/accept", server.addr()))
54 .header(
55 reqwest::header::ACCEPT,
56 reqwest::header::HeaderValue::from_static("application/json"),
57 )
58 .send()
59 .await
60 .unwrap();
61
62 assert_eq!(res.status(), reqwest::StatusCode::OK);
63 }
64
65 #[tokio::test]
test_accept_encoding_header_is_not_changed_if_set()66 async fn test_accept_encoding_header_is_not_changed_if_set() {
67 let server = server::http(move |req| async move {
68 assert_eq!(req.headers()["accept"], "*/*");
69 assert_eq!(req.headers()["accept-encoding"], "identity");
70 http::Response::default()
71 });
72
73 let client = reqwest::Client::new();
74
75 let res = client
76 .get(&format!("http://{}/accept-encoding", server.addr()))
77 .header(
78 reqwest::header::ACCEPT_ENCODING,
79 reqwest::header::HeaderValue::from_static("identity"),
80 )
81 .send()
82 .await
83 .unwrap();
84
85 assert_eq!(res.status(), reqwest::StatusCode::OK);
86 }
87
brotli_case(response_size: usize, chunk_size: usize)88 async fn brotli_case(response_size: usize, chunk_size: usize) {
89 use futures_util::stream::StreamExt;
90
91 let content: String = (0..response_size)
92 .into_iter()
93 .map(|i| format!("test {}", i))
94 .collect();
95
96 let mut encoder = brotli_crate::CompressorReader::new(content.as_bytes(), 4096, 5, 20);
97 let mut brotlied_content = Vec::new();
98 encoder.read_to_end(&mut brotlied_content).unwrap();
99
100 let mut response = format!(
101 "\
102 HTTP/1.1 200 OK\r\n\
103 Server: test-accept\r\n\
104 Content-Encoding: br\r\n\
105 Content-Length: {}\r\n\
106 \r\n",
107 &brotlied_content.len()
108 )
109 .into_bytes();
110 response.extend(&brotlied_content);
111
112 let server = server::http(move |req| {
113 assert!(req.headers()["accept-encoding"]
114 .to_str()
115 .unwrap()
116 .contains("br"));
117
118 let brotlied = brotlied_content.clone();
119 async move {
120 let len = brotlied.len();
121 let stream =
122 futures_util::stream::unfold((brotlied, 0), move |(brotlied, pos)| async move {
123 let chunk = brotlied.chunks(chunk_size).nth(pos)?.to_vec();
124
125 Some((chunk, (brotlied, pos + 1)))
126 });
127
128 let body = hyper::Body::wrap_stream(stream.map(Ok::<_, std::convert::Infallible>));
129
130 http::Response::builder()
131 .header("content-encoding", "br")
132 .header("content-length", len)
133 .body(body)
134 .unwrap()
135 }
136 });
137
138 let client = reqwest::Client::new();
139
140 let res = client
141 .get(&format!("http://{}/brotli", server.addr()))
142 .send()
143 .await
144 .expect("response");
145
146 let body = res.text().await.expect("text");
147 assert_eq!(body, content);
148 }
149