Skip to main content

ntex/http/encoding/
mod.rs

1//! Content-Encoding support
2//!
3//! Supports `gzip`, `deflate` and `zstd`. Large chunks are encoded and
4//! decoded on the blocking thread pool, smaller ones on the current thread.
5use zstd::zstd_safe::WriteBuf;
6
7use crate::rt::{BlockingResult, spawn_blocking};
8use crate::util::{BufMut, BytesMut};
9
10mod decoder;
11mod encoder;
12
13pub use self::decoder::Decoder;
14pub use self::encoder::Encoder;
15
16#[cfg(test)]
17thread_local! {
18    static OFFLOADED: std::cell::Cell<usize> = const { std::cell::Cell::new(0) };
19}
20
21/// Run `f` on the blocking thread pool.
22fn offload<F, R>(f: F) -> BlockingResult<R>
23where
24    F: FnOnce() -> R + Send + 'static,
25    R: Send + 'static,
26{
27    #[cfg(test)]
28    OFFLOADED.with(|n| n.set(n.get() + 1));
29    spawn_blocking(f)
30}
31
32#[cfg(test)]
33fn offloaded() -> usize {
34    OFFLOADED.with(std::cell::Cell::get)
35}
36
37fn zstd_error(code: usize) -> std::io::Error {
38    std::io::Error::other(zstd::zstd_safe::get_error_name(code))
39}
40
41/// The spare capacity of a buffer, `zstd` writes its output directly into it.
42struct Spare<'a> {
43    buf: &'a mut BytesMut,
44    start: usize,
45    ptr: *mut u8,
46    capacity: usize,
47}
48
49impl<'a> Spare<'a> {
50    fn new(buf: &'a mut BytesMut) -> Self {
51        let start = buf.len();
52        let spare = buf.chunk_mut();
53        let (ptr, capacity) = (spare.as_mut_ptr(), spare.len());
54        Spare {
55            buf,
56            start,
57            ptr,
58            capacity,
59        }
60    }
61}
62
63// SAFETY: `ptr` points to `capacity` bytes of the buffer's spare capacity, and
64// `filled_until` only extends the buffer over bytes zstd has written.
65unsafe impl WriteBuf for Spare<'_> {
66    fn as_slice(&self) -> &[u8] {
67        &self.buf[self.start..]
68    }
69
70    fn capacity(&self) -> usize {
71        self.capacity
72    }
73
74    fn as_mut_ptr(&mut self) -> *mut u8 {
75        self.ptr
76    }
77
78    unsafe fn filled_until(&mut self, n: usize) {
79        unsafe { self.buf.set_len(self.start + n) }
80    }
81}