Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for permessage-deflate WebSocket extension #3496

Open
wants to merge 11 commits into
base: master
Choose a base branch
from
Prev Previous commit
Next Next commit
Add tests
  • Loading branch information
segfault87 committed Nov 6, 2024
commit a2e3b62926b95a286165fa5d23473c64d6c86c2d
25 changes: 13 additions & 12 deletions actix-http/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 2,19 @@
//!
//! ## Crate Features
//!
//! | Feature | Functionality |
//! | ------------------- | ------------------------------------------- |
//! | `http2` | HTTP/2 support via [h2]. |
//! | `openssl` | TLS support via [OpenSSL]. |
//! | `rustls-0_20` | TLS support via rustls 0.20. |
//! | `rustls-0_21` | TLS support via rustls 0.21. |
//! | `rustls-0_22` | TLS support via rustls 0.22. |
//! | `rustls-0_23` | TLS support via [rustls] 0.23. |
//! | `compress-brotli` | Payload compression support: Brotli. |
//! | `compress-gzip` | Payload compression support: Deflate, Gzip. |
//! | `compress-zstd` | Payload compression support: Zstd. |
//! | `trust-dns` | Use [trust-dns] as the client DNS resolver. |
//! | Feature | Functionality |
//! | --------------------- | ------------------------------------------- |
//! | `http2` | HTTP/2 support via [h2]. |
//! | `openssl` | TLS support via [OpenSSL]. |
//! | `rustls-0_20` | TLS support via rustls 0.20. |
//! | `rustls-0_21` | TLS support via rustls 0.21. |
//! | `rustls-0_22` | TLS support via rustls 0.22. |
//! | `rustls-0_23` | TLS support via [rustls] 0.23. |
//! | `compress-brotli` | Payload compression support: Brotli. |
//! | `compress-gzip` | Payload compression support: Deflate, Gzip. |
//! | `compress-zstd` | Payload compression support: Zstd. |
//! | `compress-ws-deflate` | WebSocket DEFLATE compression support. |
//! | `trust-dns` | Use [trust-dns] as the client DNS resolver. |
//!
//! [h2]: https://crates.io/crates/h2
//! [OpenSSL]: https://crates.io/crates/openssl
Expand Down
58 changes: 38 additions & 20 deletions actix-http/src/ws/codec.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 6,7 @@ use tracing::error;

#[cfg(feature = "compress-ws-deflate")]
use super::deflate::{
DeflateCompressionContext, DeflateContext, DeflateDecompressionContext, RSV_BIT_DEFLATE_FLAG,
DeflateCompressionContext, DeflateDecompressionContext, RSV_BIT_DEFLATE_FLAG,
};
use super::{
frame::Parser,
Expand Down Expand Up @@ -100,6 100,8 @@ impl Encoder {
}

/// Create new WebSocket frames encoder with `permessage-deflate` extension support.
/// Compression context can be made from
/// [`DeflateSessionParameters::create_context`](super::DeflateSessionParameters::create_context).
#[cfg(feature = "compress-ws-deflate")]
pub fn new_deflate(compress: DeflateCompressionContext) -> Encoder {
Encoder {
Expand All @@ -109,7 111,11 @@ impl Encoder {
}
}

fn set_client_mode(mut self) -> Self {
/// Set encoder to client mode.
///
/// By default encoder works in server mode.
#[must_use = "This returns the a new Encoder, without modifying the original."]
pub fn client_mode(mut self) -> Self {
self.flags = Flags::empty();
self
}
Expand Down Expand Up @@ -305,6 311,8 @@ impl Decoder {
}

/// Create new WebSocket frames decoder with `permessage-deflate` extension support.
/// Decompression context can be made from
/// [`DeflateSessionParameters::create_context`](super::DeflateSessionParameters::create_context).
#[cfg(feature = "compress-ws-deflate")]
pub fn new_deflate(decompress: DeflateDecompressionContext) -> Decoder {
Decoder {
Expand All @@ -315,7 323,20 @@ impl Decoder {
}
}

fn set_client_mode(mut self) -> Self {
/// Set max frame size.
///
/// By default max size is set to 64KiB.
#[must_use = "This returns the a new Decoder, without modifying the original."]
pub fn max_size(mut self, size: usize) -> Self {
self.max_size = size;
self
}

/// Set decoder to client mode.
///
/// By default decoder works in server mode.
#[must_use = "This returns the a new Decoder, without modifying the original."]
pub fn client_mode(mut self) -> Self {
self.flags = Flags::empty();
self
}
Expand All @@ -333,11 354,6 @@ impl Decoder {
self
}

fn set_max_size(mut self, size: usize) -> Self {
self.max_size = size;
self
}

#[cfg(feature = "compress-ws-deflate")]
fn process_payload(
&mut self,
Expand Down Expand Up @@ -461,10 477,12 @@ impl codec::Decoder for Decoder {
}

/// WebSocket protocol codec.
/// This is essentially a combination of [`Encoder`] and [`Decoder`] and
/// actual conversion behaviors are defined in both structs respectively.
///
/// # Note
/// Cloning [`Codec`] creates a new codec with existing configurations
/// and will not preserve the current context.
/// and will not preserve the context information.
#[derive(Debug, Default)]
pub struct Codec {
encoder: Encoder,
Expand Down Expand Up @@ -510,13 528,13 @@ impl Codec {
}

/// Create new WebSocket frames codec with DEFLATE compression.
/// Both compression and decompression contexts can be made from
/// [`DeflateSessionParameters::create_context`](super::DeflateSessionParameters::create_context).
#[cfg(feature = "compress-ws-deflate")]
pub fn new_deflate(context: DeflateContext) -> Codec {
let DeflateContext {
compress,
decompress,
} = context;

pub fn new_deflate(
compress: DeflateCompressionContext,
decompress: DeflateDecompressionContext,
) -> Codec {
Codec {
encoder: Encoder::new_deflate(compress),
decoder: Decoder::new_deflate(decompress),
Expand All @@ -532,22 550,22 @@ impl Codec {

Codec {
encoder,
decoder: decoder.set_max_size(size),
decoder: decoder.max_size(size),
}
}

/// Set decoder to client mode.
/// Set codec to client mode.
///
/// By default decoder works in server mode.
/// By default codec works in server mode.
#[must_use = "This returns the a new Codec, without modifying the original."]
pub fn client_mode(self) -> Self {
let Self {
mut encoder,
mut decoder,
} = self;

encoder = encoder.set_client_mode();
decoder = decoder.set_client_mode();
encoder = encoder.client_mode();
decoder = decoder.client_mode();
#[cfg(feature = "compress-ws-deflate")]
{
if let Some(decoder) = &decoder.deflate_decompress {
Expand Down
Loading