water_http/server/encoding/
mod.rs1use std::borrow::Cow;
2use std::future::Future;
3use std::io::Write;
4use std::pin::Pin;
5use flate2::write::{GzEncoder,DeflateEncoder};
6#[derive(Debug)]
8pub struct EncodingConfigurations {
9 pub(crate) logic:EncodingLogic,
10 pub threshold_for_encoding_response:usize,
19
20}
21
22impl EncodingConfigurations {
23
24 pub (crate) fn is_not_none(&self)->bool {self.logic.is_not_none()}
25
26 pub fn default()->Self{
30 EncodingConfigurations {
31 logic:EncodingLogic::None,
32 threshold_for_encoding_response:4_000_000
33 }
34 }
35
36
37 pub fn set_logic(&mut self,logic:EncodingLogic){
39 self.logic = logic;
40 }
41
42
43 pub fn set_threshold(&mut self,max:usize){
45 self.threshold_for_encoding_response = max;
46 }
47
48
49 pub (crate) async fn encode(&self,accept_encoding:Cow<'_, str>,data:&[u8])->
50 Option<EncodedData> {
51 let accept_encoding = accept_encoding.to_lowercase();
52 match self.logic {
53 EncodingLogic::All => {return self.default_encode(accept_encoding,data).await}
54 EncodingLogic::Default => {return self.default_encode(accept_encoding,data).await}
55 EncodingLogic::Zstd => {
56 if accept_encoding.contains("zstd") {
57 let data = zstd_encode(data);
58 if let Some(data) = data {
59 return Some(
60 EncodedData::new(
61 EncodingLogic::Zstd,
62 data
63 )
64 )
65 }
66 }
67 }
68 EncodingLogic::Brotli => {
69 if accept_encoding.contains("br") {
70 let data = brotli_encode(data);
71 if let Some(data) = data {
72 return Some(
73 EncodedData::new(
74 EncodingLogic::Brotli,
75 data
76 )
77 )
78 }
79 }
80 }
81 EncodingLogic::Gzip => {
82 if accept_encoding.contains("gzip") {
83 let data = gzip_encode(data);
84 if let Some(data) = data {
85 return Some(
86 EncodedData::new(
87 EncodingLogic::Gzip,
88 data
89 )
90 )
91 }
92 }
93 }
94 EncodingLogic::Deflate => {
95 if accept_encoding.contains("deflate") {
96 let data = deflate_encode(data);
97 if let Some(data) = data {
98 return Some(
99 EncodedData::new(
100 EncodingLogic::Default,
101 data
102 )
103 )
104 }
105 }
106 }
107 EncodingLogic::Lz4 => {
108 if accept_encoding.contains("lz4") {
109 let data = lz4_encode(data);
110 if let Some(data) = data {
111 return Some(
112 EncodedData::new(
113 EncodingLogic::Lz4,
114 data
115 )
116 )
117 }
118 }
119 }
120 EncodingLogic::Bzip2 => {
121 if accept_encoding.contains("bzip2") {
122 let data = b2zip_encode(data);
123 if let Some(data) = data {
124 return Some(
125 EncodedData::new(
126 EncodingLogic::Bzip2,
127 data
128 )
129 )
130 }
131 }
132 }
133 EncodingLogic::Snappy => {
134 if accept_encoding.contains("snappy") {
135 let data = b2zip_encode(data);
136 if let Some(data) = data {
137 return Some(
138 EncodedData::new(
139 EncodingLogic::Snappy,
140 data
141 )
142 )
143 }
144 }
145 }
146 EncodingLogic::None => {return None}
147 EncodingLogic::Custom(callback) => {
148 if let Ok(res) = callback(&accept_encoding,data).await {
149 return Some(res)
150 }
151 return None;
152 }
153 }
154 None
155 }
156 pub (crate) async fn default_encode(&self,accept_encoding:String,data:&[u8])->Option<EncodedData>{
157 let logic = match Self::pick_best_encoding(&accept_encoding) {
158 Some(d)=>{d}
159 _ => { return None}
160 };
161 match logic {
162 EncodingLogic::Zstd => {
163 if accept_encoding.contains("zstd") {
164 let data = zstd_encode(data);
165 if let Some(data) = data {
166 return Some(
167 EncodedData::new(
168 EncodingLogic::Zstd,
169 data
170 )
171 )
172 }
173 }
174 }
175 EncodingLogic::Brotli => {
176 if accept_encoding.contains("br") {
177 let data = brotli_encode(data);
178 if let Some(data) = data {
179 return Some(
180 EncodedData::new(
181 EncodingLogic::Brotli,
182 data
183 )
184 )
185 }
186 }
187 }
188 EncodingLogic::Gzip => {
189 if accept_encoding.contains("gzip") {
190 let data = gzip_encode(data);
191 if let Some(data) = data {
192 return Some(
193 EncodedData::new(
194 EncodingLogic::Gzip,
195 data
196 )
197 )
198 }
199 }
200 }
201 EncodingLogic::Deflate => {
202 if accept_encoding.contains("deflate") {
203 let data = deflate_encode(data);
204 if let Some(data) = data {
205 return Some(
206 EncodedData::new(
207 EncodingLogic::Default,
208 data
209 )
210 )
211 }
212 }
213 }
214 EncodingLogic::Lz4 => {
215 if accept_encoding.contains("lz4") {
216 let data = lz4_encode(data);
217 if let Some(data) = data {
218 return Some(
219 EncodedData::new(
220 EncodingLogic::Lz4,
221 data
222 )
223 )
224 }
225 }
226 }
227 EncodingLogic::Bzip2 => {
228 if accept_encoding.contains("bzip2") {
229 let data = b2zip_encode(data);
230 if let Some(data) = data {
231 return Some(
232 EncodedData::new(
233 EncodingLogic::Bzip2,
234 data
235 )
236 )
237 }
238 }
239 }
240 EncodingLogic::Snappy => {
241 if accept_encoding.contains("snappy") {
242 let data = snappy_encode(data);
243 if let Some(data) = data {
244 return Some(
245 EncodedData::new(
246 EncodingLogic::Snappy,
247 data
248 )
249 )
250 }
251 }
252 }
253 _ => {}
254
255 }
256 None
257 }
258 fn pick_best_encoding(header: &str) -> Option<EncodingLogic> {
259 let supported_encodings = vec!["br", "zstd", "gzip", "deflate", "lz4", "bzip2", "snappy"];
260 for encoding in supported_encodings {
261 if header.contains(encoding) {
262 return match encoding {
263 "br" => Some(EncodingLogic::Brotli),
264 "zstd" => Some(EncodingLogic::Zstd),
265 "gzip" => Some(EncodingLogic::Gzip),
266 "deflate" => Some(EncodingLogic::Deflate),
267 "lz4" => Some(EncodingLogic::Lz4),
268 "bzip2" => Some(EncodingLogic::Bzip2),
269 "snappy" => Some(EncodingLogic::Snappy),
270 _ => None,
271 };
272 }
273 }
274 None
275 }
276
277}
278
279#[derive(Debug)]
281pub enum EncodingLogic{
282 All,
284 Default,
286 Zstd,
288 Brotli,
290 Gzip,
292 Deflate,
294 Snappy,
296 Bzip2,
298 Lz4,
300 None,
302 Custom(fn (&str,&[u8])->Pin<Box<dyn Future<Output=Result<EncodedData,()>> + Send>>)
304}
305
306
307impl EncodingLogic {
308
309 pub (crate) fn is_not_none(&self)->bool{
310 if let EncodingLogic::None = self {return false}
311 return true
312 }
313
314
315 pub (crate) fn content_encoding(&self)->Option<&str>{
316 match self {
317
318 EncodingLogic::Zstd => {Some("zstd")}
319 EncodingLogic::Brotli => {Some("br")}
320 EncodingLogic::Gzip => {Some("gzip")}
321 EncodingLogic::Deflate => {Some("deflate")}
322 EncodingLogic::Snappy => {Some("snappy")}
323 EncodingLogic::Bzip2 => {Some("bzip2")}
324 EncodingLogic::Lz4 => {Some("lz4")}
325 _ =>{None}
326 }
327
328 }
329
330}
331
332
333pub struct EncodedData {
335 pub(crate) logic:String,
336 pub(crate) data:Vec<u8>
337}
338
339
340impl EncodedData {
341
342 pub (crate) fn new(logic:EncodingLogic,data:Vec<u8>)->Self{
343 Self {
344 logic:logic.content_encoding().unwrap_or("").to_owned(),
345 data
346 }
347 }
348}
349unsafe impl Send for EncodedData {}
350unsafe impl Send for EncodingLogic {}
351unsafe impl Send for EncodingConfigurations {}
352
353fn gzip_encode(data:&[u8])->Option<Vec<u8>>{
354 let mut encoder = GzEncoder::new(Vec::new(),flate2::Compression::best());
355 if encoder.write_all(data).is_err() {return None;}
356 if let Ok(res) = encoder.finish() { return Some(res)}
357 None
358}
359fn deflate_encode(data:&[u8])->Option<Vec<u8>>{
360 let mut encoder = DeflateEncoder::new(Vec::new(),flate2::Compression::best());
361 if encoder.write_all(data).is_err() {return None;}
362 if let Ok(res) = encoder.finish() { return Some(res)}
363 None
364}
365fn zstd_encode(data:&[u8])->Option<Vec<u8>>{
366 let mut encoder =
367 match zstd::stream::Encoder::new(Vec::new(),3) {
368 Ok(r) => {r}
369 Err(_) => { return None}
370 };
371 if encoder.write_all(data).is_err() {return None}
372 if let Ok(res) = encoder.finish() {
373 return Some(res)
374 }
375 None
376}
377fn brotli_encode(data:&[u8])->Option<Vec<u8>>{
378 let mut encoder = brotli::CompressorWriter::new(Vec::new(), 4096, 5, 22);
379 if encoder.write_all(data).is_err() {return None}
380 Some(encoder.into_inner())
381 }
382fn snappy_encode(data:&[u8])->Option<Vec<u8>> {
383 let mut encoder = snap::write::FrameEncoder::new(Vec::new());
384 if encoder.write_all(data).is_err() { return None}
385 if let Ok(res) = encoder.into_inner() {
386 return Some(res)
387 }
388 return None;
389}
390fn lz4_encode(data: &[u8]) -> Option<Vec<u8>> {
391 let mut encoder = lz4::EncoderBuilder::new().build(Vec::new()).expect("Failed to create LZ4 encoder");
392 if let Err(_) = encoder.write_all(data) { return None}
393 let (compressed, result) = encoder.finish();
394 if let Err(_) = result { return None}
395 Some(compressed)
396}
397
398fn b2zip_encode(data:&[u8])->Option<Vec<u8>>{
399 let mut encoder = bzip2::write::BzEncoder::new(Vec::new(),bzip2::Compression::best());
400 if encoder.write_all(data).is_err() { return None}
401 if let Ok(res) = encoder.finish() {
402 return Some(res);
403 }
404 None
405}