use crate::{
base::{Data, Header, OpCode},
connection::Mode,
extension::{Extension, Param}
};
use flate2::{Compress, Compression, Decompress, FlushCompress, FlushDecompress};
use log::debug;
use smallvec::SmallVec;
#[derive(Debug)]
pub struct Deflate {
mode: Mode,
enabled: bool,
buffer: Vec<u8>,
client_params: SmallVec<[Param<'static>; 2]>,
server_params: SmallVec<[Param<'static>; 2]>,
client_max_window_bits: u8,
server_max_window_bits: u8
}
impl Deflate {
pub fn new(mode: Mode) -> Self {
let client_params = match mode {
Mode::Server => SmallVec::new(),
Mode::Client => {
let mut params = SmallVec::new();
params.push(Param::new("server_no_context_takeover"));
params
}
};
Deflate {
mode,
enabled: false,
buffer: Vec::new(),
client_params,
server_params: SmallVec::new(),
client_max_window_bits: 15,
server_max_window_bits: 15
}
}
}
impl Extension for Deflate {
fn name(&self) -> &str {
"permessage-deflate"
}
fn is_enabled(&self) -> bool {
self.enabled
}
fn params(&self) -> &[Param] {
match self.mode {
Mode::Client => &self.client_params,
Mode::Server => &self.server_params
}
}
fn configure(&mut self, params: &[Param]) -> Result<(), crate::BoxError> {
self.enabled = false;
match self.mode {
Mode::Server => {
self.server_params.clear();
for p in params {
match p.name() {
"client_max_window_bits" => {} "server_max_window_bits" => {
if let Some(Ok(v)) = p.value().map(|s| s.parse::<u8>()) {
if v != 15 {
debug!("unacceptable server_max_window_bits: {:?}", v);
return Ok(())
}
let mut x = Param::new("server_max_window_bits");
x.set_value(Some(v.to_string()));
self.server_params.push(x);
self.server_max_window_bits = v;
} else {
debug!("invalid server_max_window_bits: {:?}", p.value());
return Ok(())
}
}
"client_no_context_takeover" =>
self.server_params.push(Param::new("client_no_context_takeover")),
"server_no_context_takeover" =>
self.server_params.push(Param::new("server_no_context_takeover")),
_ => {
debug!("{}: unknown parameter: {}", self.name(), p.name());
return Ok(())
}
}
}
}
Mode::Client => {
let mut server_no_context_takeover = false;
for p in params {
match p.name() {
"server_no_context_takeover" => server_no_context_takeover = true,
"server_max_window_bits" => {}
"client_no_context_takeover" => {} _ => {
debug!("{}: unknown parameter: {}", self.name(), p.name());
return Ok(())
}
}
}
if !server_no_context_takeover {
debug!("{}: server did not confirm no context takeover", self.name());
return Ok(())
}
}
}
self.enabled = true;
Ok(())
}
fn reserved_bits(&self) -> (bool, bool, bool) {
(true, false, false)
}
fn decode(&mut self, hdr: &mut Header, data: &mut Option<Data>) -> Result<(), crate::BoxError> {
match hdr.opcode() {
OpCode::Binary | OpCode::Text if hdr.is_rsv1() && hdr.is_fin() => {}
OpCode::Continue if hdr.is_fin() => {}
_ => return Ok(())
}
if let Some(data) = data {
data.bytes_mut().extend_from_slice(&[0, 0, 0xFF, 0xFF]); self.buffer.clear();
let mut d = Decompress::new(false);
while (d.total_in() as usize) < data.as_ref().len() {
let off = d.total_in() as usize;
self.buffer.reserve(data.as_ref().len() - off);
d.decompress_vec(&data.as_ref()[off ..], &mut self.buffer, FlushDecompress::Sync)?;
}
data.bytes_mut().clear();
data.bytes_mut().extend_from_slice(&self.buffer);
hdr.set_rsv1(false);
}
Ok(())
}
fn encode(&mut self, hdr: &mut Header, data: &mut Option<Data>) -> Result<(), crate::BoxError> {
match hdr.opcode() {
OpCode::Text | OpCode::Binary => {},
_ => return Ok(())
}
if let Some(data) = data {
let mut c = Compress::new(Compression::fast(), false);
self.buffer.clear();
while (c.total_in() as usize) < data.as_ref().len() {
let off = c.total_in() as usize;
self.buffer.reserve(data.as_ref().len() - off);
c.compress_vec(&data.as_ref()[off ..], &mut self.buffer, FlushCompress::Sync)?;
}
if self.buffer.capacity() - self.buffer.len() < 5 {
self.buffer.reserve(5); c.compress_vec(&[], &mut self.buffer, FlushCompress::Sync)?;
}
let n = self.buffer.len() - 4;
self.buffer.truncate(n); data.bytes_mut().clear();
data.bytes_mut().extend_from_slice(&self.buffer);
hdr.set_rsv1(true);
}
Ok(())
}
}