mirror of https://github.com/fafhrd91/actix-web
remove BodyEncoding trait
This commit is contained in:
parent
19a46e3925
commit
9dabaafb12
|
@ -597,7 +597,8 @@ mod tests {
|
||||||
.to_request();
|
.to_request();
|
||||||
let res = test::call_service(&srv, request).await;
|
let res = test::call_service(&srv, request).await;
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
assert!(!res.headers().contains_key(header::CONTENT_ENCODING));
|
assert!(res.headers().contains_key(header::CONTENT_ENCODING));
|
||||||
|
assert!(!test::read_body(res).await.is_empty());
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
|
|
|
@ -9,14 +9,11 @@ use std::{
|
||||||
use actix_service::{Service, ServiceFactory};
|
use actix_service::{Service, ServiceFactory};
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
body::{self, BoxBody, SizedStream},
|
body::{self, BoxBody, SizedStream},
|
||||||
dev::{
|
dev::{AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse},
|
||||||
AppService, BodyEncoding, HttpServiceFactory, ResourceDef, ServiceRequest,
|
|
||||||
ServiceResponse,
|
|
||||||
},
|
|
||||||
http::{
|
http::{
|
||||||
header::{
|
header::{
|
||||||
self, Charset, ContentDisposition, ContentEncoding, DispositionParam,
|
self, Charset, ContentDisposition, ContentEncoding, DispositionParam,
|
||||||
DispositionType, ExtendedValue,
|
DispositionType, ExtendedValue, HeaderValue,
|
||||||
},
|
},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
},
|
},
|
||||||
|
@ -224,7 +221,6 @@ impl NamedFile {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "experimental-io-uring"))]
|
|
||||||
/// Attempts to open a file in read-only mode.
|
/// Attempts to open a file in read-only mode.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
|
@ -232,6 +228,7 @@ impl NamedFile {
|
||||||
/// use actix_files::NamedFile;
|
/// use actix_files::NamedFile;
|
||||||
/// let file = NamedFile::open("foo.txt");
|
/// let file = NamedFile::open("foo.txt");
|
||||||
/// ```
|
/// ```
|
||||||
|
#[cfg(not(feature = "experimental-io-uring"))]
|
||||||
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<NamedFile> {
|
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<NamedFile> {
|
||||||
let file = File::open(&path)?;
|
let file = File::open(&path)?;
|
||||||
Self::from_file(file, path)
|
Self::from_file(file, path)
|
||||||
|
@ -295,23 +292,21 @@ impl NamedFile {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the MIME Content-Type for serving this file. By default
|
/// Set the MIME Content-Type for serving this file. By default the Content-Type is inferred
|
||||||
/// the Content-Type is inferred from the filename extension.
|
/// from the filename extension.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_content_type(mut self, mime_type: mime::Mime) -> Self {
|
pub fn set_content_type(mut self, mime_type: mime::Mime) -> Self {
|
||||||
self.content_type = mime_type;
|
self.content_type = mime_type;
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the Content-Disposition for serving this file. This allows
|
/// Set the Content-Disposition for serving this file. This allows changing the
|
||||||
/// changing the inline/attachment disposition as well as the filename
|
/// `inline/attachment` disposition as well as the filename sent to the peer.
|
||||||
/// sent to the peer.
|
|
||||||
///
|
///
|
||||||
/// By default the disposition is `inline` for `text/*`, `image/*`, `video/*` and
|
/// By default the disposition is `inline` for `text/*`, `image/*`, `video/*` and
|
||||||
/// `application/{javascript, json, wasm}` mime types, and `attachment` otherwise,
|
/// `application/{javascript, json, wasm}` mime types, and `attachment` otherwise, and the
|
||||||
/// and the filename is taken from the path provided in the `open` method
|
/// filename is taken from the path provided in the `open` method after converting it to UTF-8
|
||||||
/// after converting it to UTF-8 using.
|
/// (using `to_string_lossy`).
|
||||||
/// [`std::ffi::OsStr::to_string_lossy`]
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn set_content_disposition(mut self, cd: header::ContentDisposition) -> Self {
|
pub fn set_content_disposition(mut self, cd: header::ContentDisposition) -> Self {
|
||||||
self.content_disposition = cd;
|
self.content_disposition = cd;
|
||||||
|
@ -337,7 +332,7 @@ impl NamedFile {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies whether to use ETag or not.
|
/// Specifies whether to return `ETag` header in response.
|
||||||
///
|
///
|
||||||
/// Default is true.
|
/// Default is true.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -346,7 +341,7 @@ impl NamedFile {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Specifies whether to use Last-Modified or not.
|
/// Specifies whether to return `Last-Modified` header in response.
|
||||||
///
|
///
|
||||||
/// Default is true.
|
/// Default is true.
|
||||||
#[inline]
|
#[inline]
|
||||||
|
@ -364,7 +359,7 @@ impl NamedFile {
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a etag in a format is similar to Apache's.
|
/// Creates an `ETag` in a format is similar to Apache's.
|
||||||
pub(crate) fn etag(&self) -> Option<header::EntityTag> {
|
pub(crate) fn etag(&self) -> Option<header::EntityTag> {
|
||||||
self.modified.as_ref().map(|mtime| {
|
self.modified.as_ref().map(|mtime| {
|
||||||
let ino = {
|
let ino = {
|
||||||
|
@ -405,12 +400,13 @@ impl NamedFile {
|
||||||
if self.status_code != StatusCode::OK {
|
if self.status_code != StatusCode::OK {
|
||||||
let mut res = HttpResponse::build(self.status_code);
|
let mut res = HttpResponse::build(self.status_code);
|
||||||
|
|
||||||
if self.flags.contains(Flags::PREFER_UTF8) {
|
let ct = if self.flags.contains(Flags::PREFER_UTF8) {
|
||||||
let ct = equiv_utf8_text(self.content_type.clone());
|
equiv_utf8_text(self.content_type.clone())
|
||||||
res.insert_header((header::CONTENT_TYPE, ct.to_string()));
|
|
||||||
} else {
|
} else {
|
||||||
res.insert_header((header::CONTENT_TYPE, self.content_type.to_string()));
|
self.content_type
|
||||||
}
|
};
|
||||||
|
|
||||||
|
res.insert_header((header::CONTENT_TYPE, ct.to_string()));
|
||||||
|
|
||||||
if self.flags.contains(Flags::CONTENT_DISPOSITION) {
|
if self.flags.contains(Flags::CONTENT_DISPOSITION) {
|
||||||
res.insert_header((
|
res.insert_header((
|
||||||
|
@ -420,7 +416,7 @@ impl NamedFile {
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(current_encoding) = self.encoding {
|
if let Some(current_encoding) = self.encoding {
|
||||||
res.encode_with(current_encoding);
|
res.insert_header((header::CONTENT_ENCODING, current_encoding.as_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
let reader = chunked::new_chunked_read(self.md.len(), 0, self.file);
|
let reader = chunked::new_chunked_read(self.md.len(), 0, self.file);
|
||||||
|
@ -478,12 +474,13 @@ impl NamedFile {
|
||||||
|
|
||||||
let mut res = HttpResponse::build(self.status_code);
|
let mut res = HttpResponse::build(self.status_code);
|
||||||
|
|
||||||
if self.flags.contains(Flags::PREFER_UTF8) {
|
let ct = if self.flags.contains(Flags::PREFER_UTF8) {
|
||||||
let ct = equiv_utf8_text(self.content_type.clone());
|
equiv_utf8_text(self.content_type.clone())
|
||||||
res.insert_header((header::CONTENT_TYPE, ct.to_string()));
|
|
||||||
} else {
|
} else {
|
||||||
res.insert_header((header::CONTENT_TYPE, self.content_type.to_string()));
|
self.content_type
|
||||||
}
|
};
|
||||||
|
|
||||||
|
res.insert_header((header::CONTENT_TYPE, ct.to_string()));
|
||||||
|
|
||||||
if self.flags.contains(Flags::CONTENT_DISPOSITION) {
|
if self.flags.contains(Flags::CONTENT_DISPOSITION) {
|
||||||
res.insert_header((
|
res.insert_header((
|
||||||
|
@ -492,9 +489,8 @@ impl NamedFile {
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
// default compressing
|
|
||||||
if let Some(current_encoding) = self.encoding {
|
if let Some(current_encoding) = self.encoding {
|
||||||
res.encode_with(current_encoding);
|
res.insert_header((header::CONTENT_ENCODING, current_encoding.as_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(lm) = last_modified {
|
if let Some(lm) = last_modified {
|
||||||
|
@ -517,7 +513,12 @@ impl NamedFile {
|
||||||
length = ranges[0].length;
|
length = ranges[0].length;
|
||||||
offset = ranges[0].start;
|
offset = ranges[0].start;
|
||||||
|
|
||||||
res.encode_with(ContentEncoding::Identity);
|
// don't allow compression middleware to modify partial content
|
||||||
|
res.insert_header((
|
||||||
|
header::CONTENT_ENCODING,
|
||||||
|
HeaderValue::from_static("identity"),
|
||||||
|
));
|
||||||
|
|
||||||
res.insert_header((
|
res.insert_header((
|
||||||
header::CONTENT_RANGE,
|
header::CONTENT_RANGE,
|
||||||
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
|
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
|
||||||
|
|
|
@ -6,7 +6,7 @@ use ahash::AHashMap;
|
||||||
use http::header::{HeaderName, HeaderValue};
|
use http::header::{HeaderName, HeaderValue};
|
||||||
use smallvec::{smallvec, SmallVec};
|
use smallvec::{smallvec, SmallVec};
|
||||||
|
|
||||||
use crate::header::AsHeaderName;
|
use super::AsHeaderName;
|
||||||
|
|
||||||
/// A multi-map of HTTP headers.
|
/// A multi-map of HTTP headers.
|
||||||
///
|
///
|
||||||
|
|
|
@ -50,10 +50,10 @@ pub use self::utils::{
|
||||||
|
|
||||||
/// An interface for types that already represent a valid header.
|
/// An interface for types that already represent a valid header.
|
||||||
pub trait Header: TryIntoHeaderValue {
|
pub trait Header: TryIntoHeaderValue {
|
||||||
/// Returns the name of the header field
|
/// Returns the name of the header field.
|
||||||
fn name() -> HeaderName;
|
fn name() -> HeaderName;
|
||||||
|
|
||||||
/// Parse a header
|
/// Parse the header from a HTTP message.
|
||||||
fn parse<M: HttpMessage>(msg: &M) -> Result<Self, ParseError>;
|
fn parse<M: HttpMessage>(msg: &M) -> Result<Self, ParseError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -68,6 +68,7 @@ impl ContentEncoding {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for ContentEncoding {
|
impl Default for ContentEncoding {
|
||||||
|
#[inline]
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
Self::Identity
|
Self::Identity
|
||||||
}
|
}
|
||||||
|
|
|
@ -102,12 +102,14 @@ actix-utils = "3.0.0"
|
||||||
actix-web = { version = "4.0.0-beta.18", features = ["openssl"] }
|
actix-web = { version = "4.0.0-beta.18", features = ["openssl"] }
|
||||||
|
|
||||||
brotli2 = "0.3.2"
|
brotli2 = "0.3.2"
|
||||||
|
const-str = "0.3"
|
||||||
env_logger = "0.9"
|
env_logger = "0.9"
|
||||||
flate2 = "1.0.13"
|
flate2 = "1.0.13"
|
||||||
futures-util = { version = "0.3.7", default-features = false }
|
futures-util = { version = "0.3.7", default-features = false }
|
||||||
static_assertions = "1.1"
|
static_assertions = "1.1"
|
||||||
rcgen = "0.8"
|
rcgen = "0.8"
|
||||||
rustls-pemfile = "0.2"
|
rustls-pemfile = "0.2"
|
||||||
|
zstd = "0.9"
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "client"
|
name = "client"
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
|
convert::Infallible,
|
||||||
io::{Read, Write},
|
io::{Read, Write},
|
||||||
net::{IpAddr, Ipv4Addr},
|
net::{IpAddr, Ipv4Addr},
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -15,43 +16,16 @@ use cookie::Cookie;
|
||||||
use futures_util::stream;
|
use futures_util::stream;
|
||||||
use rand::Rng;
|
use rand::Rng;
|
||||||
|
|
||||||
#[cfg(feature = "compress-brotli")]
|
use actix_http::{HttpService, StatusCode};
|
||||||
use brotli2::write::BrotliEncoder;
|
|
||||||
|
|
||||||
#[cfg(feature = "compress-gzip")]
|
|
||||||
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
|
|
||||||
|
|
||||||
use actix_http::{ContentEncoding, HttpService, StatusCode};
|
|
||||||
use actix_http_test::test_server;
|
use actix_http_test::test_server;
|
||||||
use actix_service::{fn_service, map_config, ServiceFactoryExt as _};
|
use actix_service::{fn_service, map_config, ServiceFactoryExt as _};
|
||||||
use actix_web::{
|
use actix_web::{dev::AppConfig, http::header, web, App, Error, HttpRequest, HttpResponse};
|
||||||
dev::{AppConfig, BodyEncoding},
|
|
||||||
http::header,
|
|
||||||
web, App, Error, HttpRequest, HttpResponse,
|
|
||||||
};
|
|
||||||
use awc::error::{JsonPayloadError, PayloadError, SendRequestError};
|
use awc::error::{JsonPayloadError, PayloadError, SendRequestError};
|
||||||
|
|
||||||
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
mod utils;
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
const S: &str = "Hello World ";
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
const STR: &str = const_str::repeat!(S, 100);
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World";
|
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_simple() {
|
async fn test_simple() {
|
||||||
|
@ -471,15 +445,12 @@ async fn test_no_decompress() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new()
|
App::new()
|
||||||
.wrap(actix_web::middleware::Compress::default())
|
.wrap(actix_web::middleware::Compress::default())
|
||||||
.service(web::resource("/").route(web::to(|| {
|
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||||
let mut res = HttpResponse::Ok().body(STR);
|
|
||||||
res.encode_with(header::ContentEncoding::Gzip);
|
|
||||||
res
|
|
||||||
})))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let mut res = awc::Client::new()
|
let mut res = awc::Client::new()
|
||||||
.get(srv.url("/"))
|
.get(srv.url("/"))
|
||||||
|
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -488,15 +459,12 @@ async fn test_no_decompress() {
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
|
assert_eq!(utils::gzip::decode(bytes), STR.as_bytes());
|
||||||
let mut e = GzDecoder::new(&bytes[..]);
|
|
||||||
let mut dec = Vec::new();
|
|
||||||
e.read_to_end(&mut dec).unwrap();
|
|
||||||
assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
|
|
||||||
|
|
||||||
// POST
|
// POST
|
||||||
let mut res = awc::Client::new()
|
let mut res = awc::Client::new()
|
||||||
.post(srv.url("/"))
|
.post(srv.url("/"))
|
||||||
|
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -504,10 +472,7 @@ async fn test_no_decompress() {
|
||||||
assert!(res.status().is_success());
|
assert!(res.status().is_success());
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
let mut e = GzDecoder::new(&bytes[..]);
|
assert_eq!(utils::gzip::decode(bytes), STR.as_bytes());
|
||||||
let mut dec = Vec::new();
|
|
||||||
e.read_to_end(&mut dec).unwrap();
|
|
||||||
assert_eq!(Bytes::from(dec), Bytes::from_static(STR.as_ref()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compress-gzip")]
|
#[cfg(feature = "compress-gzip")]
|
||||||
|
@ -515,13 +480,9 @@ async fn test_no_decompress() {
|
||||||
async fn test_client_gzip_encoding() {
|
async fn test_client_gzip_encoding() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().service(web::resource("/").route(web::to(|| {
|
App::new().service(web::resource("/").route(web::to(|| {
|
||||||
let mut e = GzEncoder::new(Vec::new(), Compression::default());
|
|
||||||
e.write_all(STR.as_ref()).unwrap();
|
|
||||||
let data = e.finish().unwrap();
|
|
||||||
|
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.insert_header(("content-encoding", "gzip"))
|
.insert_header(header::ContentEncoding::Gzip)
|
||||||
.body(data)
|
.body(utils::gzip::encode(STR))
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -531,7 +492,7 @@ async fn test_client_gzip_encoding() {
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let bytes = response.body().await.unwrap();
|
let bytes = response.body().await.unwrap();
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
assert_eq!(bytes, STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compress-gzip")]
|
#[cfg(feature = "compress-gzip")]
|
||||||
|
@ -539,13 +500,9 @@ async fn test_client_gzip_encoding() {
|
||||||
async fn test_client_gzip_encoding_large() {
|
async fn test_client_gzip_encoding_large() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().service(web::resource("/").route(web::to(|| {
|
App::new().service(web::resource("/").route(web::to(|| {
|
||||||
let mut e = GzEncoder::new(Vec::new(), Compression::default());
|
|
||||||
e.write_all(STR.repeat(10).as_ref()).unwrap();
|
|
||||||
let data = e.finish().unwrap();
|
|
||||||
|
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.insert_header(("content-encoding", "gzip"))
|
.insert_header(header::ContentEncoding::Gzip)
|
||||||
.body(data)
|
.body(utils::gzip::encode(STR.repeat(10)))
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -555,7 +512,7 @@ async fn test_client_gzip_encoding_large() {
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let bytes = response.body().await.unwrap();
|
let bytes = response.body().await.unwrap();
|
||||||
assert_eq!(bytes, Bytes::from(STR.repeat(10)));
|
assert_eq!(bytes, STR.repeat(10));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compress-gzip")]
|
#[cfg(feature = "compress-gzip")]
|
||||||
|
@ -569,12 +526,9 @@ async fn test_client_gzip_encoding_large_random() {
|
||||||
|
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
|
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
|
||||||
let mut e = GzEncoder::new(Vec::new(), Compression::default());
|
|
||||||
e.write_all(&data).unwrap();
|
|
||||||
let data = e.finish().unwrap();
|
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.insert_header(("content-encoding", "gzip"))
|
.insert_header(header::ContentEncoding::Gzip)
|
||||||
.body(data)
|
.body(utils::gzip::encode(data))
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -584,7 +538,7 @@ async fn test_client_gzip_encoding_large_random() {
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let bytes = response.body().await.unwrap();
|
let bytes = response.body().await.unwrap();
|
||||||
assert_eq!(bytes, Bytes::from(data));
|
assert_eq!(bytes, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "compress-brotli")]
|
#[cfg(feature = "compress-brotli")]
|
||||||
|
@ -592,12 +546,9 @@ async fn test_client_gzip_encoding_large_random() {
|
||||||
async fn test_client_brotli_encoding() {
|
async fn test_client_brotli_encoding() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
|
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
|
||||||
let mut e = BrotliEncoder::new(Vec::new(), 5);
|
|
||||||
e.write_all(&data).unwrap();
|
|
||||||
let data = e.finish().unwrap();
|
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.insert_header(("content-encoding", "br"))
|
.insert_header(("content-encoding", "br"))
|
||||||
.body(data)
|
.body(utils::brotli::encode(data))
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -621,12 +572,9 @@ async fn test_client_brotli_encoding_large_random() {
|
||||||
|
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
|
App::new().service(web::resource("/").route(web::to(|data: Bytes| {
|
||||||
let mut e = BrotliEncoder::new(Vec::new(), 5);
|
|
||||||
e.write_all(&data).unwrap();
|
|
||||||
let data = e.finish().unwrap();
|
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.insert_header(("content-encoding", "br"))
|
.insert_header(header::ContentEncoding::Brotli)
|
||||||
.body(data)
|
.body(utils::brotli::encode(&data))
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -636,27 +584,25 @@ async fn test_client_brotli_encoding_large_random() {
|
||||||
|
|
||||||
// read response
|
// read response
|
||||||
let bytes = response.body().await.unwrap();
|
let bytes = response.body().await.unwrap();
|
||||||
assert_eq!(bytes.len(), data.len());
|
assert_eq!(bytes, data);
|
||||||
assert_eq!(bytes, Bytes::from(data));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn test_client_deflate_encoding() {
|
async fn test_client_deflate_encoding() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().default_service(web::to(|body: Bytes| {
|
App::new().default_service(web::to(|body: Bytes| HttpResponse::Ok().body(body)))
|
||||||
HttpResponse::Ok()
|
|
||||||
.encode_with(ContentEncoding::Brotli)
|
|
||||||
.body(body)
|
|
||||||
}))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let req = srv.post("/").send_body(STR);
|
let req = srv
|
||||||
|
.post("/")
|
||||||
|
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
|
.send_body(STR);
|
||||||
|
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
assert_eq!(bytes, STR);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
|
@ -668,14 +614,13 @@ async fn test_client_deflate_encoding_large_random() {
|
||||||
.collect::<String>();
|
.collect::<String>();
|
||||||
|
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().default_service(web::to(|body: Bytes| {
|
App::new().default_service(web::to(|body: Bytes| HttpResponse::Ok().body(body)))
|
||||||
HttpResponse::Ok()
|
|
||||||
.encode_with(ContentEncoding::Brotli)
|
|
||||||
.body(body)
|
|
||||||
}))
|
|
||||||
});
|
});
|
||||||
|
|
||||||
let req = srv.post("/").send_body(data.clone());
|
let req = srv
|
||||||
|
.post("/")
|
||||||
|
.insert_header((header::ACCEPT_ENCODING, "br"))
|
||||||
|
.send_body(data.clone());
|
||||||
|
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
|
@ -688,15 +633,16 @@ async fn test_client_deflate_encoding_large_random() {
|
||||||
async fn test_client_streaming_explicit() {
|
async fn test_client_streaming_explicit() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().default_service(web::to(|body: web::Payload| {
|
App::new().default_service(web::to(|body: web::Payload| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok().streaming(body)
|
||||||
.encode_with(ContentEncoding::Identity)
|
|
||||||
.streaming(body)
|
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
let body =
|
let body =
|
||||||
stream::once(async { Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes())) });
|
stream::once(async { Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes())) });
|
||||||
let req = srv.post("/").send_stream(Box::pin(body));
|
let req = srv
|
||||||
|
.post("/")
|
||||||
|
.insert_header((header::ACCEPT_ENCODING, "identity"))
|
||||||
|
.send_stream(Box::pin(body));
|
||||||
|
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
assert!(res.status().is_success());
|
assert!(res.status().is_success());
|
||||||
|
@ -709,17 +655,16 @@ async fn test_client_streaming_explicit() {
|
||||||
async fn test_body_streaming_implicit() {
|
async fn test_body_streaming_implicit() {
|
||||||
let srv = actix_test::start(|| {
|
let srv = actix_test::start(|| {
|
||||||
App::new().default_service(web::to(|| {
|
App::new().default_service(web::to(|| {
|
||||||
let body = stream::once(async {
|
let body =
|
||||||
Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes()))
|
stream::once(async { Ok::<_, Infallible>(Bytes::from_static(STR.as_bytes())) });
|
||||||
});
|
HttpResponse::Ok().streaming(body)
|
||||||
|
|
||||||
HttpResponse::Ok()
|
|
||||||
.encode_with(ContentEncoding::Gzip)
|
|
||||||
.streaming(Box::pin(body))
|
|
||||||
}))
|
}))
|
||||||
});
|
});
|
||||||
|
|
||||||
let req = srv.get("/").send();
|
let req = srv
|
||||||
|
.get("/")
|
||||||
|
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
|
.send();
|
||||||
|
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
assert!(res.status().is_success());
|
assert!(res.status().is_success());
|
||||||
|
|
78
src/dev.rs
78
src/dev.rs
|
@ -22,8 +22,6 @@ pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse, We
|
||||||
|
|
||||||
pub use crate::types::{JsonBody, Readlines, UrlEncoded};
|
pub use crate::types::{JsonBody, Readlines, UrlEncoded};
|
||||||
|
|
||||||
use crate::{http::header::ContentEncoding, HttpMessage as _};
|
|
||||||
|
|
||||||
use actix_router::Patterns;
|
use actix_router::Patterns;
|
||||||
|
|
||||||
pub(crate) fn ensure_leading_slash(mut patterns: Patterns) -> Patterns {
|
pub(crate) fn ensure_leading_slash(mut patterns: Patterns) -> Patterns {
|
||||||
|
@ -44,79 +42,3 @@ pub(crate) fn ensure_leading_slash(mut patterns: Patterns) -> Patterns {
|
||||||
|
|
||||||
patterns
|
patterns
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Helper trait for managing response encoding.
|
|
||||||
pub trait BodyEncoding {
|
|
||||||
/// Get content encoding
|
|
||||||
fn preferred_encoding(&self) -> Option<ContentEncoding>;
|
|
||||||
|
|
||||||
/// Set content encoding to use.
|
|
||||||
///
|
|
||||||
/// Must be used with [`Compress`] to take effect.
|
|
||||||
///
|
|
||||||
/// [`Compress`]: crate::middleware::Compress
|
|
||||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self;
|
|
||||||
}
|
|
||||||
|
|
||||||
struct CompressWith(ContentEncoding);
|
|
||||||
|
|
||||||
impl BodyEncoding for crate::HttpResponseBuilder {
|
|
||||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
|
||||||
self.extensions().get::<CompressWith>().map(|enc| enc.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
|
||||||
self.extensions_mut().insert(CompressWith(encoding));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> BodyEncoding for crate::HttpResponse<B> {
|
|
||||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
|
||||||
self.extensions().get::<CompressWith>().map(|enc| enc.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
|
||||||
self.extensions_mut().insert(CompressWith(encoding));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> BodyEncoding for ServiceResponse<B> {
|
|
||||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
|
||||||
self.request()
|
|
||||||
.extensions()
|
|
||||||
.get::<CompressWith>()
|
|
||||||
.map(|enc| enc.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
|
||||||
self.request()
|
|
||||||
.extensions_mut()
|
|
||||||
.insert(CompressWith(encoding));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove these impls ?
|
|
||||||
impl BodyEncoding for actix_http::ResponseBuilder {
|
|
||||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
|
||||||
self.extensions().get::<CompressWith>().map(|enc| enc.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
|
||||||
self.extensions_mut().insert(CompressWith(encoding));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<B> BodyEncoding for actix_http::Response<B> {
|
|
||||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
|
||||||
self.extensions().get::<CompressWith>().map(|enc| enc.0)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
|
||||||
self.extensions_mut().insert(CompressWith(encoding));
|
|
||||||
self
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,8 +17,7 @@ fn check_slice_validity(slice: &str) -> bool {
|
||||||
slice.bytes().all(entity_validate_char)
|
slice.bytes().all(entity_validate_char)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entity tag, defined
|
/// An entity tag, defined in [RFC 7232 §2.3].
|
||||||
/// in [RFC 7232 §2.3](https://datatracker.ietf.org/doc/html/rfc7232#section-2.3)
|
|
||||||
///
|
///
|
||||||
/// An entity tag consists of a string enclosed by two literal double quotes.
|
/// An entity tag consists of a string enclosed by two literal double quotes.
|
||||||
/// Preceding the first double quote is an optional weakness indicator,
|
/// Preceding the first double quote is an optional weakness indicator,
|
||||||
|
@ -48,16 +47,20 @@ fn check_slice_validity(slice: &str) -> bool {
|
||||||
/// | `W/"1"` | `W/"2"` | no match | no match |
|
/// | `W/"1"` | `W/"2"` | no match | no match |
|
||||||
/// | `W/"1"` | `"1"` | no match | match |
|
/// | `W/"1"` | `"1"` | no match | match |
|
||||||
/// | `"1"` | `"1"` | match | match |
|
/// | `"1"` | `"1"` | match | match |
|
||||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
///
|
||||||
|
/// [RFC 7232 §2.3](https://datatracker.ietf.org/doc/html/rfc7232#section-2.3)
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct EntityTag {
|
pub struct EntityTag {
|
||||||
/// Weakness indicator for the tag
|
/// Weakness indicator for the tag
|
||||||
pub weak: bool,
|
pub weak: bool,
|
||||||
|
|
||||||
/// The opaque string in between the DQUOTEs
|
/// The opaque string in between the DQUOTEs
|
||||||
tag: String,
|
tag: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl EntityTag {
|
impl EntityTag {
|
||||||
/// Constructs a new EntityTag.
|
/// Constructs a new EntityTag.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// If the tag contains invalid characters.
|
/// If the tag contains invalid characters.
|
||||||
pub fn new(weak: bool, tag: String) -> EntityTag {
|
pub fn new(weak: bool, tag: String) -> EntityTag {
|
||||||
|
@ -66,6 +69,7 @@ impl EntityTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new weak EntityTag.
|
/// Constructs a new weak EntityTag.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// If the tag contains invalid characters.
|
/// If the tag contains invalid characters.
|
||||||
pub fn weak(tag: String) -> EntityTag {
|
pub fn weak(tag: String) -> EntityTag {
|
||||||
|
@ -73,6 +77,7 @@ impl EntityTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Constructs a new strong EntityTag.
|
/// Constructs a new strong EntityTag.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// If the tag contains invalid characters.
|
/// If the tag contains invalid characters.
|
||||||
pub fn strong(tag: String) -> EntityTag {
|
pub fn strong(tag: String) -> EntityTag {
|
||||||
|
@ -85,6 +90,7 @@ impl EntityTag {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set the tag.
|
/// Set the tag.
|
||||||
|
///
|
||||||
/// # Panics
|
/// # Panics
|
||||||
/// If the tag contains invalid characters.
|
/// If the tag contains invalid characters.
|
||||||
pub fn set_tag(&mut self, tag: String) {
|
pub fn set_tag(&mut self, tag: String) {
|
||||||
|
|
|
@ -16,7 +16,6 @@ use pin_project_lite::pin_project;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
body::{EitherBody, MessageBody},
|
body::{EitherBody, MessageBody},
|
||||||
dev::BodyEncoding as _,
|
|
||||||
http::{
|
http::{
|
||||||
header::{self, AcceptEncoding, Encoding, HeaderValue},
|
header::{self, AcceptEncoding, Encoding, HeaderValue},
|
||||||
StatusCode,
|
StatusCode,
|
||||||
|
@ -176,14 +175,10 @@ where
|
||||||
|
|
||||||
match ready!(this.fut.poll(cx)) {
|
match ready!(this.fut.poll(cx)) {
|
||||||
Ok(resp) => {
|
Ok(resp) => {
|
||||||
let enc = if let Some(enc) = resp.response().preferred_encoding() {
|
let enc = match this.encoding {
|
||||||
enc
|
Encoding::Known(enc) => *enc,
|
||||||
} else {
|
Encoding::Unknown(enc) => {
|
||||||
match this.encoding {
|
unimplemented!("encoding {} should not be here", enc);
|
||||||
Encoding::Known(enc) => *enc,
|
|
||||||
Encoding::Unknown(enc) => {
|
|
||||||
unimplemented!("encoding {} should not be here", enc);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,14 +1,12 @@
|
||||||
use actix_http::ContentEncoding;
|
use actix_http::ContentEncoding;
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::BodyEncoding as _,
|
|
||||||
http::{header, StatusCode},
|
http::{header, StatusCode},
|
||||||
middleware::Compress,
|
middleware::Compress,
|
||||||
web, App, HttpResponse,
|
web, App, HttpResponse,
|
||||||
};
|
};
|
||||||
use bytes::Bytes;
|
use bytes::Bytes;
|
||||||
|
|
||||||
mod test_utils;
|
mod utils;
|
||||||
use test_utils::{brotli, gzip, zstd};
|
|
||||||
|
|
||||||
static LOREM: &[u8] = include_bytes!("fixtures/lorem.txt");
|
static LOREM: &[u8] = include_bytes!("fixtures/lorem.txt");
|
||||||
static LOREM_GZIP: &[u8] = include_bytes!("fixtures/lorem.txt.gz");
|
static LOREM_GZIP: &[u8] = include_bytes!("fixtures/lorem.txt.gz");
|
||||||
|
@ -27,7 +25,6 @@ macro_rules! test_server {
|
||||||
web::to(|| {
|
web::to(|| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
// signal to compressor that content should not be altered
|
// signal to compressor that content should not be altered
|
||||||
.encode_with(ContentEncoding::Identity)
|
|
||||||
// signal to client that content is encoded
|
// signal to client that content is encoded
|
||||||
.insert_header(ContentEncoding::Gzip)
|
.insert_header(ContentEncoding::Gzip)
|
||||||
.body(LOREM_GZIP)
|
.body(LOREM_GZIP)
|
||||||
|
@ -38,7 +35,6 @@ macro_rules! test_server {
|
||||||
web::to(|| {
|
web::to(|| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
// signal to compressor that content should not be altered
|
// signal to compressor that content should not be altered
|
||||||
.encode_with(ContentEncoding::Identity)
|
|
||||||
// signal to client that content is encoded
|
// signal to client that content is encoded
|
||||||
.insert_header(ContentEncoding::Brotli)
|
.insert_header(ContentEncoding::Brotli)
|
||||||
.body(LOREM_BR)
|
.body(LOREM_BR)
|
||||||
|
@ -49,7 +45,6 @@ macro_rules! test_server {
|
||||||
web::to(|| {
|
web::to(|| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
// signal to compressor that content should not be altered
|
// signal to compressor that content should not be altered
|
||||||
.encode_with(ContentEncoding::Identity)
|
|
||||||
// signal to client that content is encoded
|
// signal to client that content is encoded
|
||||||
.insert_header(ContentEncoding::Zstd)
|
.insert_header(ContentEncoding::Zstd)
|
||||||
.body(LOREM_ZSTD)
|
.body(LOREM_ZSTD)
|
||||||
|
@ -60,7 +55,7 @@ macro_rules! test_server {
|
||||||
web::to(|| {
|
web::to(|| {
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
// signal to compressor that content should not be altered
|
// signal to compressor that content should not be altered
|
||||||
.encode_with(ContentEncoding::Identity)
|
// .encode_with(ContentEncoding::Identity)
|
||||||
// signal to client that content is encoded as 7zip
|
// signal to client that content is encoded as 7zip
|
||||||
.insert_header((header::CONTENT_ENCODING, "xz"))
|
.insert_header((header::CONTENT_ENCODING, "xz"))
|
||||||
.body(LOREM_XZ)
|
.body(LOREM_XZ)
|
||||||
|
@ -146,7 +141,7 @@ async fn negotiate_encoding_br() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(brotli::decode(bytes), LOREM);
|
assert_eq!(utils::brotli::decode(bytes), LOREM);
|
||||||
|
|
||||||
srv.stop().await;
|
srv.stop().await;
|
||||||
}
|
}
|
||||||
|
@ -175,7 +170,7 @@ async fn negotiate_encoding_zstd() {
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(zstd::decode(bytes), LOREM);
|
assert_eq!(utils::zstd::decode(bytes), LOREM);
|
||||||
|
|
||||||
srv.stop().await;
|
srv.stop().await;
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,11 +12,7 @@ use std::{
|
||||||
|
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
cookie::{Cookie, CookieBuilder},
|
cookie::{Cookie, CookieBuilder},
|
||||||
dev::BodyEncoding,
|
http::{header, StatusCode},
|
||||||
http::{
|
|
||||||
header::{self, ContentEncoding, ACCEPT_ENCODING, CONTENT_ENCODING, TRANSFER_ENCODING},
|
|
||||||
StatusCode,
|
|
||||||
},
|
|
||||||
middleware::{Compress, NormalizePath, TrailingSlash},
|
middleware::{Compress, NormalizePath, TrailingSlash},
|
||||||
web, App, Error, HttpResponse,
|
web, App, Error, HttpResponse,
|
||||||
};
|
};
|
||||||
|
@ -31,30 +27,11 @@ use openssl::{
|
||||||
x509::X509,
|
x509::X509,
|
||||||
};
|
};
|
||||||
|
|
||||||
mod test_utils;
|
mod utils;
|
||||||
use test_utils::{brotli, deflate, gzip, zstd};
|
use utils::{brotli, deflate, gzip, zstd};
|
||||||
|
|
||||||
const STR: &str = "Hello World Hello World Hello World Hello World Hello World \
|
const S: &str = "Hello World ";
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
const STR: &str = const_str::repeat!(S, 100);
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World \
|
|
||||||
Hello World Hello World Hello World Hello World Hello World";
|
|
||||||
|
|
||||||
#[cfg(feature = "openssl")]
|
#[cfg(feature = "openssl")]
|
||||||
fn openssl_config() -> SslAcceptor {
|
fn openssl_config() -> SslAcceptor {
|
||||||
|
@ -129,51 +106,52 @@ async fn test_body() {
|
||||||
srv.stop().await;
|
srv.stop().await;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[actix_rt::test]
|
// enforcing an encoding per-response is removed
|
||||||
async fn test_body_encoding_override() {
|
// #[actix_rt::test]
|
||||||
let srv = actix_test::start_with(actix_test::config().h1(), || {
|
// async fn test_body_encoding_override() {
|
||||||
App::new()
|
// let srv = actix_test::start_with(actix_test::config().h1(), || {
|
||||||
.wrap(Compress::default())
|
// App::new()
|
||||||
.service(web::resource("/").route(web::to(|| {
|
// .wrap(Compress::default())
|
||||||
HttpResponse::Ok()
|
// .service(web::resource("/").route(web::to(|| {
|
||||||
.encode_with(ContentEncoding::Deflate)
|
// HttpResponse::Ok()
|
||||||
.body(STR)
|
// .encode_with(ContentEncoding::Deflate)
|
||||||
})))
|
// .body(STR)
|
||||||
.service(web::resource("/raw").route(web::to(|| {
|
// })))
|
||||||
let mut res = HttpResponse::with_body(actix_web::http::StatusCode::OK, STR);
|
// .service(web::resource("/raw").route(web::to(|| {
|
||||||
res.encode_with(ContentEncoding::Deflate);
|
// let mut res = HttpResponse::with_body(actix_web::http::StatusCode::OK, STR);
|
||||||
res.map_into_boxed_body()
|
// res.encode_with(ContentEncoding::Deflate);
|
||||||
})))
|
// res.map_into_boxed_body()
|
||||||
});
|
// })))
|
||||||
|
// });
|
||||||
|
|
||||||
// Builder
|
// // Builder
|
||||||
let mut res = srv
|
// let mut res = srv
|
||||||
.get("/")
|
// .get("/")
|
||||||
.no_decompress()
|
// .no_decompress()
|
||||||
.append_header((ACCEPT_ENCODING, "deflate"))
|
// .append_header((ACCEPT_ENCODING, "deflate"))
|
||||||
.send()
|
// .send()
|
||||||
.await
|
// .await
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
// assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
// let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
// assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
||||||
|
|
||||||
// Raw Response
|
// // Raw Response
|
||||||
let mut res = srv
|
// let mut res = srv
|
||||||
.request(actix_web::http::Method::GET, srv.url("/raw"))
|
// .request(actix_web::http::Method::GET, srv.url("/raw"))
|
||||||
.no_decompress()
|
// .no_decompress()
|
||||||
.append_header((ACCEPT_ENCODING, "deflate"))
|
// .append_header((ACCEPT_ENCODING, "deflate"))
|
||||||
.send()
|
// .send()
|
||||||
.await
|
// .await
|
||||||
.unwrap();
|
// .unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
// assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
// let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
// assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
||||||
|
|
||||||
srv.stop().await;
|
// srv.stop().await;
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[actix_rt::test]
|
#[actix_rt::test]
|
||||||
async fn body_gzip_large() {
|
async fn body_gzip_large() {
|
||||||
|
@ -191,7 +169,7 @@ async fn body_gzip_large() {
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.append_header((ACCEPT_ENCODING, "gzip"))
|
.append_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -222,7 +200,7 @@ async fn test_body_gzip_large_random() {
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.append_header((ACCEPT_ENCODING, "gzip"))
|
.append_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
@ -248,12 +226,15 @@ async fn test_body_chunked_implicit() {
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.append_header((ACCEPT_ENCODING, "gzip"))
|
.append_header((header::ACCEPT_ENCODING, "gzip"))
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
assert_eq!(res.headers().get(TRANSFER_ENCODING).unwrap(), "chunked");
|
assert_eq!(
|
||||||
|
res.headers().get(header::TRANSFER_ENCODING).unwrap(),
|
||||||
|
"chunked"
|
||||||
|
);
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(gzip::decode(bytes), STR.as_bytes());
|
assert_eq!(gzip::decode(bytes), STR.as_bytes());
|
||||||
|
@ -274,7 +255,7 @@ async fn test_body_br_streaming() {
|
||||||
|
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.append_header((ACCEPT_ENCODING, "br"))
|
.append_header((header::ACCEPT_ENCODING, "br"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -319,7 +300,7 @@ async fn test_no_chunking() {
|
||||||
|
|
||||||
let mut res = srv.get("/").send().await.unwrap();
|
let mut res = srv.get("/").send().await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
assert!(!res.headers().contains_key(TRANSFER_ENCODING));
|
assert!(!res.headers().contains_key(header::TRANSFER_ENCODING));
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||||
|
@ -337,7 +318,7 @@ async fn test_body_deflate() {
|
||||||
|
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.append_header((ACCEPT_ENCODING, "deflate"))
|
.append_header((header::ACCEPT_ENCODING, "deflate"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -360,7 +341,7 @@ async fn test_body_brotli() {
|
||||||
|
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.append_header((ACCEPT_ENCODING, "br"))
|
.append_header((header::ACCEPT_ENCODING, "br"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -383,7 +364,7 @@ async fn test_body_zstd() {
|
||||||
|
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.append_header((ACCEPT_ENCODING, "zstd"))
|
.append_header((header::ACCEPT_ENCODING, "zstd"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -409,7 +390,7 @@ async fn test_body_zstd_streaming() {
|
||||||
|
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.append_header((ACCEPT_ENCODING, "zstd"))
|
.append_header((header::ACCEPT_ENCODING, "zstd"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
|
@ -432,7 +413,7 @@ async fn test_zstd_encoding() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "zstd"))
|
.append_header((header::CONTENT_ENCODING, "zstd"))
|
||||||
.send_body(zstd::encode(STR));
|
.send_body(zstd::encode(STR));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -463,7 +444,7 @@ async fn test_zstd_encoding_large() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "zstd"))
|
.append_header((header::CONTENT_ENCODING, "zstd"))
|
||||||
.send_body(zstd::encode(&data));
|
.send_body(zstd::encode(&data));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -484,7 +465,7 @@ async fn test_encoding() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.insert_header((CONTENT_ENCODING, "gzip"))
|
.insert_header((header::CONTENT_ENCODING, "gzip"))
|
||||||
.send_body(gzip::encode(STR));
|
.send_body(gzip::encode(STR));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -505,7 +486,7 @@ async fn test_gzip_encoding() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "gzip"))
|
.append_header((header::CONTENT_ENCODING, "gzip"))
|
||||||
.send_body(gzip::encode(STR));
|
.send_body(gzip::encode(STR));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -527,7 +508,7 @@ async fn test_gzip_encoding_large() {
|
||||||
|
|
||||||
let req = srv
|
let req = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "gzip"))
|
.append_header((header::CONTENT_ENCODING, "gzip"))
|
||||||
.send_body(gzip::encode(&data));
|
.send_body(gzip::encode(&data));
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -554,7 +535,7 @@ async fn test_reading_gzip_encoding_large_random() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "gzip"))
|
.append_header((header::CONTENT_ENCODING, "gzip"))
|
||||||
.send_body(gzip::encode(&data));
|
.send_body(gzip::encode(&data));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -575,7 +556,7 @@ async fn test_reading_deflate_encoding() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "deflate"))
|
.append_header((header::CONTENT_ENCODING, "deflate"))
|
||||||
.send_body(deflate::encode(STR));
|
.send_body(deflate::encode(STR));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -597,7 +578,7 @@ async fn test_reading_deflate_encoding_large() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "deflate"))
|
.append_header((header::CONTENT_ENCODING, "deflate"))
|
||||||
.send_body(deflate::encode(&data));
|
.send_body(deflate::encode(&data));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -624,7 +605,7 @@ async fn test_reading_deflate_encoding_large_random() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "deflate"))
|
.append_header((header::CONTENT_ENCODING, "deflate"))
|
||||||
.send_body(deflate::encode(&data));
|
.send_body(deflate::encode(&data));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -646,7 +627,7 @@ async fn test_brotli_encoding() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "br"))
|
.append_header((header::CONTENT_ENCODING, "br"))
|
||||||
.send_body(brotli::encode(STR));
|
.send_body(brotli::encode(STR));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -677,7 +658,7 @@ async fn test_brotli_encoding_large() {
|
||||||
|
|
||||||
let request = srv
|
let request = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.append_header((CONTENT_ENCODING, "br"))
|
.append_header((header::CONTENT_ENCODING, "br"))
|
||||||
.send_body(brotli::encode(&data));
|
.send_body(brotli::encode(&data));
|
||||||
let mut res = request.await.unwrap();
|
let mut res = request.await.unwrap();
|
||||||
assert_eq!(res.status(), StatusCode::OK);
|
assert_eq!(res.status(), StatusCode::OK);
|
||||||
|
@ -697,8 +678,9 @@ async fn test_brotli_encoding_large_openssl() {
|
||||||
let srv =
|
let srv =
|
||||||
actix_test::start_with(actix_test::config().openssl(openssl_config()), move || {
|
actix_test::start_with(actix_test::config().openssl(openssl_config()), move || {
|
||||||
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
||||||
|
// echo decompressed request body back in response
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.encode_with(ContentEncoding::Identity)
|
.insert_header(header::ContentEncoding::Identity)
|
||||||
.body(bytes)
|
.body(bytes)
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
@ -758,15 +740,16 @@ mod plus_rustls {
|
||||||
|
|
||||||
let srv = actix_test::start_with(actix_test::config().rustls(tls_config()), || {
|
let srv = actix_test::start_with(actix_test::config().rustls(tls_config()), || {
|
||||||
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
||||||
|
// echo decompressed request body back in response
|
||||||
HttpResponse::Ok()
|
HttpResponse::Ok()
|
||||||
.encode_with(ContentEncoding::Identity)
|
.insert_header(header::ContentEncoding::Identity)
|
||||||
.body(bytes)
|
.body(bytes)
|
||||||
})))
|
})))
|
||||||
});
|
});
|
||||||
|
|
||||||
let req = srv
|
let req = srv
|
||||||
.post("/")
|
.post("/")
|
||||||
.insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate"))
|
.insert_header((header::CONTENT_ENCODING, "deflate"))
|
||||||
.send_stream(TestBody::new(Bytes::from(deflate::encode(&data)), 1024));
|
.send_stream(TestBody::new(Bytes::from(deflate::encode(&data)), 1024));
|
||||||
|
|
||||||
let mut res = req.await.unwrap();
|
let mut res = req.await.unwrap();
|
||||||
|
@ -931,14 +914,14 @@ async fn test_accept_encoding_no_match() {
|
||||||
|
|
||||||
let mut res = srv
|
let mut res = srv
|
||||||
.get("/")
|
.get("/")
|
||||||
.insert_header((ACCEPT_ENCODING, "xz, identity;q=0"))
|
.insert_header((header::ACCEPT_ENCODING, "xz, identity;q=0"))
|
||||||
.no_decompress()
|
.no_decompress()
|
||||||
.send()
|
.send()
|
||||||
.await
|
.await
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
|
assert_eq!(res.status(), StatusCode::NOT_ACCEPTABLE);
|
||||||
assert_eq!(res.headers().get(CONTENT_ENCODING), None);
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING), None);
|
||||||
|
|
||||||
let bytes = res.body().await.unwrap();
|
let bytes = res.body().await.unwrap();
|
||||||
// body should contain the supported encodings
|
// body should contain the supported encodings
|
||||||
|
|
|
@ -0,0 +1,76 @@
|
||||||
|
// compiling some tests will trigger unused function warnings even though other tests use them
|
||||||
|
#![allow(dead_code)]
|
||||||
|
|
||||||
|
use std::io::{Read as _, Write as _};
|
||||||
|
|
||||||
|
pub mod gzip {
|
||||||
|
use super::*;
|
||||||
|
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
|
||||||
|
|
||||||
|
pub fn encode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut encoder = GzEncoder::new(Vec::new(), Compression::fast());
|
||||||
|
encoder.write_all(bytes.as_ref()).unwrap();
|
||||||
|
encoder.finish().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut decoder = GzDecoder::new(bytes.as_ref());
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
decoder.read_to_end(&mut buf).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod deflate {
|
||||||
|
use super::*;
|
||||||
|
use flate2::{read::ZlibDecoder, write::ZlibEncoder, Compression};
|
||||||
|
|
||||||
|
pub fn encode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut encoder = ZlibEncoder::new(Vec::new(), Compression::fast());
|
||||||
|
encoder.write_all(bytes.as_ref()).unwrap();
|
||||||
|
encoder.finish().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut decoder = ZlibDecoder::new(bytes.as_ref());
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
decoder.read_to_end(&mut buf).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod brotli {
|
||||||
|
use super::*;
|
||||||
|
use ::brotli2::{read::BrotliDecoder, write::BrotliEncoder};
|
||||||
|
|
||||||
|
pub fn encode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut encoder = BrotliEncoder::new(Vec::new(), 3);
|
||||||
|
encoder.write_all(bytes.as_ref()).unwrap();
|
||||||
|
encoder.finish().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut decoder = BrotliDecoder::new(bytes.as_ref());
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
decoder.read_to_end(&mut buf).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod zstd {
|
||||||
|
use super::*;
|
||||||
|
use ::zstd::stream::{read::Decoder, write::Encoder};
|
||||||
|
|
||||||
|
pub fn encode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut encoder = Encoder::new(Vec::new(), 3).unwrap();
|
||||||
|
encoder.write_all(bytes.as_ref()).unwrap();
|
||||||
|
encoder.finish().unwrap()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn decode(bytes: impl AsRef<[u8]>) -> Vec<u8> {
|
||||||
|
let mut decoder = Decoder::new(bytes.as_ref()).unwrap();
|
||||||
|
let mut buf = Vec::new();
|
||||||
|
decoder.read_to_end(&mut buf).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue