mirror of https://github.com/fafhrd91/actix-web
rename BodyEncoding methods
This commit is contained in:
parent
d981dda09b
commit
b540c4c9b8
|
@ -420,7 +420,7 @@ impl NamedFile {
|
|||
}
|
||||
|
||||
if let Some(current_encoding) = self.encoding {
|
||||
res.encoding(current_encoding);
|
||||
res.encode_with(current_encoding);
|
||||
}
|
||||
|
||||
let reader = chunked::new_chunked_read(self.md.len(), 0, self.file);
|
||||
|
@ -494,7 +494,7 @@ impl NamedFile {
|
|||
|
||||
// default compressing
|
||||
if let Some(current_encoding) = self.encoding {
|
||||
res.encoding(current_encoding);
|
||||
res.encode_with(current_encoding);
|
||||
}
|
||||
|
||||
if let Some(lm) = last_modified {
|
||||
|
@ -517,7 +517,7 @@ impl NamedFile {
|
|||
length = ranges[0].length;
|
||||
offset = ranges[0].start;
|
||||
|
||||
res.encoding(ContentEncoding::Identity);
|
||||
res.encode_with(ContentEncoding::Identity);
|
||||
res.insert_header((
|
||||
header::CONTENT_RANGE,
|
||||
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
|
||||
|
|
|
@ -20,7 +20,7 @@ pub struct ContentEncodingParseError;
|
|||
/// See [IANA HTTP Content Coding Registry].
|
||||
///
|
||||
/// [IANA HTTP Content Coding Registry]: https://www.iana.org/assignments/http-parameters/http-parameters.xhtml
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
#[non_exhaustive]
|
||||
pub enum ContentEncoding {
|
||||
/// Indicates the no-op identity encoding.
|
||||
|
@ -42,12 +42,6 @@ pub enum ContentEncoding {
|
|||
}
|
||||
|
||||
impl ContentEncoding {
|
||||
// /// Is the content compressed?
|
||||
// #[inline]
|
||||
// pub const fn is_compression(self) -> bool {
|
||||
// matches!(self, ContentEncoding::Identity)
|
||||
// }
|
||||
|
||||
/// Convert content encoding to string.
|
||||
#[inline]
|
||||
pub const fn as_str(self) -> &'static str {
|
||||
|
@ -82,16 +76,18 @@ impl Default for ContentEncoding {
|
|||
impl FromStr for ContentEncoding {
|
||||
type Err = ContentEncodingParseError;
|
||||
|
||||
fn from_str(val: &str) -> Result<Self, Self::Err> {
|
||||
let val = val.trim();
|
||||
fn from_str(enc: &str) -> Result<Self, Self::Err> {
|
||||
let enc = enc.trim();
|
||||
|
||||
if val.eq_ignore_ascii_case("br") {
|
||||
if enc.eq_ignore_ascii_case("br") {
|
||||
Ok(ContentEncoding::Brotli)
|
||||
} else if val.eq_ignore_ascii_case("gzip") {
|
||||
} else if enc.eq_ignore_ascii_case("gzip") {
|
||||
Ok(ContentEncoding::Gzip)
|
||||
} else if val.eq_ignore_ascii_case("deflate") {
|
||||
} else if enc.eq_ignore_ascii_case("deflate") {
|
||||
Ok(ContentEncoding::Deflate)
|
||||
} else if val.eq_ignore_ascii_case("zstd") {
|
||||
} else if enc.eq_ignore_ascii_case("identity") {
|
||||
Ok(ContentEncoding::Identity)
|
||||
} else if enc.eq_ignore_ascii_case("zstd") {
|
||||
Ok(ContentEncoding::Zstd)
|
||||
} else {
|
||||
Err(ContentEncodingParseError)
|
||||
|
|
|
@ -473,7 +473,7 @@ async fn test_no_decompress() {
|
|||
.wrap(actix_web::middleware::Compress::default())
|
||||
.service(web::resource("/").route(web::to(|| {
|
||||
let mut res = HttpResponse::Ok().body(STR);
|
||||
res.encoding(header::ContentEncoding::Gzip);
|
||||
res.encode_with(header::ContentEncoding::Gzip);
|
||||
res
|
||||
})))
|
||||
});
|
||||
|
@ -645,7 +645,7 @@ async fn test_client_deflate_encoding() {
|
|||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|body: Bytes| {
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Brotli)
|
||||
.encode_with(ContentEncoding::Brotli)
|
||||
.body(body)
|
||||
}))
|
||||
});
|
||||
|
@ -670,7 +670,7 @@ async fn test_client_deflate_encoding_large_random() {
|
|||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|body: Bytes| {
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Brotli)
|
||||
.encode_with(ContentEncoding::Brotli)
|
||||
.body(body)
|
||||
}))
|
||||
});
|
||||
|
@ -689,7 +689,7 @@ async fn test_client_streaming_explicit() {
|
|||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|body: web::Payload| {
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
.streaming(body)
|
||||
}))
|
||||
});
|
||||
|
@ -714,7 +714,7 @@ async fn test_body_streaming_implicit() {
|
|||
});
|
||||
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Gzip)
|
||||
.encode_with(ContentEncoding::Gzip)
|
||||
.streaming(Box::pin(body))
|
||||
}))
|
||||
});
|
||||
|
|
|
@ -12,16 +12,16 @@ save_exit_code() {
|
|||
[ "$CMD_EXIT" = "0" ] || EXIT=$CMD_EXIT
|
||||
}
|
||||
|
||||
save_exit_code cargo test --lib --tests -p=actix-router --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-http --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-web --features=rustls,openssl -- --skip=test_reading_deflate_encoding_large_random_rustls
|
||||
save_exit_code cargo test --lib --tests -p=actix-web-codegen --all-features
|
||||
save_exit_code cargo test --lib --tests -p=awc --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-http-test --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-test --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-files
|
||||
save_exit_code cargo test --lib --tests -p=actix-multipart --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-web-actors --all-features
|
||||
save_exit_code cargo test --lib --tests -p=actix-router --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-http --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-web --features=rustls,openssl -- --nocapture --skip=test_reading_deflate_encoding_large_random_rustls
|
||||
save_exit_code cargo test --lib --tests -p=actix-web-codegen --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=awc --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-http-test --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-test --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-files -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-multipart --all-features -- --nocapture
|
||||
save_exit_code cargo test --lib --tests -p=actix-web-actors --all-features -- --nocapture
|
||||
|
||||
save_exit_code cargo test --workspace --doc
|
||||
|
||||
|
|
119
src/dev.rs
119
src/dev.rs
|
@ -22,7 +22,7 @@ pub use crate::service::{HttpServiceFactory, ServiceRequest, ServiceResponse, We
|
|||
|
||||
pub use crate::types::{JsonBody, Readlines, UrlEncoded};
|
||||
|
||||
use crate::http::header::ContentEncoding;
|
||||
use crate::{http::header::ContentEncoding, HttpMessage as _};
|
||||
|
||||
use actix_router::Patterns;
|
||||
|
||||
|
@ -47,60 +47,105 @@ pub(crate) fn ensure_leading_slash(mut patterns: Patterns) -> Patterns {
|
|||
|
||||
/// Helper trait for managing response encoding.
|
||||
///
|
||||
/// Use `encoding` to flag response as already encoded. For example, when serving a Gzip compressed
|
||||
/// file from disk.
|
||||
/// Use `pre_encoded_with` to flag response as already encoded. For example, when serving a Gzip
|
||||
/// compressed file from disk.
|
||||
pub trait BodyEncoding {
|
||||
/// Get content encoding
|
||||
fn get_encoding(&self) -> Option<ContentEncoding>;
|
||||
fn preferred_encoding(&self) -> Option<ContentEncoding>;
|
||||
|
||||
/// Set content encoding
|
||||
/// Set content encoding to use.
|
||||
///
|
||||
/// Must be used with [`crate::middleware::Compress`] to take effect.
|
||||
fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self;
|
||||
/// Must be used with [`Compress`] to take effect.
|
||||
///
|
||||
/// [`Compress`]: crate::middleware::Compress
|
||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self;
|
||||
|
||||
/// Flags that a file already is encoded so that [`Compress`] does not modify it.
|
||||
///
|
||||
/// Effectively a shortcut for `compress_with("identity")`
|
||||
/// plus `insert_header(ContentEncoding, encoding)`.
|
||||
///
|
||||
/// [`Compress`]: crate::middleware::Compress
|
||||
fn pre_encoded_with(&mut self, encoding: ContentEncoding) -> &mut Self;
|
||||
}
|
||||
|
||||
struct Enc(ContentEncoding);
|
||||
struct CompressWith(ContentEncoding);
|
||||
|
||||
impl BodyEncoding for actix_http::ResponseBuilder {
|
||||
fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
}
|
||||
|
||||
fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(Enc(encoding));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> BodyEncoding for actix_http::Response<B> {
|
||||
fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
}
|
||||
|
||||
fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(Enc(encoding));
|
||||
self
|
||||
}
|
||||
}
|
||||
struct PreCompressed(ContentEncoding);
|
||||
|
||||
impl BodyEncoding for crate::HttpResponseBuilder {
|
||||
fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<CompressWith>().map(|enc| enc.0)
|
||||
}
|
||||
|
||||
fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(Enc(encoding));
|
||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(CompressWith(encoding));
|
||||
self
|
||||
}
|
||||
|
||||
fn pre_encoded_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(PreCompressed(encoding));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<B> BodyEncoding for crate::HttpResponse<B> {
|
||||
fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
fn preferred_encoding(&self) -> Option<ContentEncoding> {
|
||||
self.extensions().get::<CompressWith>().map(|enc| enc.0)
|
||||
}
|
||||
|
||||
fn encoding(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(Enc(encoding));
|
||||
fn encode_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(CompressWith(encoding));
|
||||
self
|
||||
}
|
||||
|
||||
fn pre_encoded_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.extensions_mut().insert(PreCompressed(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
|
||||
}
|
||||
|
||||
fn pre_encoded_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
self.request()
|
||||
.extensions_mut()
|
||||
.insert(PreCompressed(encoding));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
// impl BodyEncoding for actix_http::ResponseBuilder {
|
||||
// fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
// self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
// }
|
||||
|
||||
// fn compress_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
// self.extensions_mut().insert(Enc(encoding));
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl<B> BodyEncoding for actix_http::Response<B> {
|
||||
// fn get_encoding(&self) -> Option<ContentEncoding> {
|
||||
// self.extensions().get::<Enc>().map(|enc| enc.0)
|
||||
// }
|
||||
|
||||
// fn compress_with(&mut self, encoding: ContentEncoding) -> &mut Self {
|
||||
// self.extensions_mut().insert(Enc(encoding));
|
||||
// self
|
||||
// }
|
||||
// }
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashSet;
|
||||
|
||||
use super::{common_header, Encoding, Preference, Quality, QualityItem};
|
||||
use super::{common_header, ContentEncoding, Encoding, Preference, Quality, QualityItem};
|
||||
use crate::http::header;
|
||||
|
||||
common_header! {
|
||||
|
@ -31,7 +31,7 @@ common_header! {
|
|||
///
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// AcceptEncoding(vec![QualityItem::max(Preference::Specific(Encoding::Gzip))])
|
||||
/// AcceptEncoding(vec![QualityItem::max(Preference::Specific(Encoding::gzip()))])
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
|
@ -57,8 +57,8 @@ common_header! {
|
|||
order_of_appearance,
|
||||
vec![b"br, gzip"],
|
||||
Some(AcceptEncoding(vec![
|
||||
QualityItem::max(Preference::Specific(Encoding::Brotli)),
|
||||
QualityItem::max(Preference::Specific(Encoding::Gzip)),
|
||||
QualityItem::max(Preference::Specific(Encoding::brotli())),
|
||||
QualityItem::max(Preference::Specific(Encoding::gzip())),
|
||||
]))
|
||||
);
|
||||
|
||||
|
@ -76,7 +76,7 @@ common_header! {
|
|||
only_gzip_no_identity,
|
||||
vec![b"gzip, *; q=0"],
|
||||
Some(AcceptEncoding(vec![
|
||||
QualityItem::max(Preference::Specific(Encoding::Gzip)),
|
||||
QualityItem::max(Preference::Specific(Encoding::gzip())),
|
||||
QualityItem::zero(Preference::Any),
|
||||
]))
|
||||
);
|
||||
|
@ -109,7 +109,7 @@ impl AcceptEncoding {
|
|||
|
||||
if self.0.is_empty() {
|
||||
// though it is not recommended to encode in this case, return identity encoding
|
||||
return Some(Encoding::Identity);
|
||||
return Some(Encoding::identity());
|
||||
}
|
||||
|
||||
// 2. If the representation has no content-coding, then it is acceptable by default unless
|
||||
|
@ -119,10 +119,10 @@ impl AcceptEncoding {
|
|||
let acceptable_items = self.ranked_items().collect::<Vec<_>>();
|
||||
|
||||
let identity_acceptable = is_identity_acceptable(&acceptable_items);
|
||||
let identity_supported = supported_set.contains(&Encoding::Identity);
|
||||
let identity_supported = supported_set.contains(&Encoding::identity());
|
||||
|
||||
if identity_acceptable && identity_supported && supported_set.len() == 1 {
|
||||
return Some(Encoding::Identity);
|
||||
return Some(Encoding::identity());
|
||||
}
|
||||
|
||||
// 3. If the representation's content-coding is one of the content-codings listed in the
|
||||
|
@ -144,7 +144,7 @@ impl AcceptEncoding {
|
|||
match matched {
|
||||
Some(Preference::Specific(enc)) => Some(enc),
|
||||
|
||||
_ if identity_acceptable => Some(Encoding::Identity),
|
||||
_ if identity_acceptable => Some(Encoding::identity()),
|
||||
|
||||
_ => None,
|
||||
}
|
||||
|
@ -190,14 +190,15 @@ impl AcceptEncoding {
|
|||
match self.0.iter().find(|pref| {
|
||||
matches!(
|
||||
pref.item,
|
||||
Preference::Any | Preference::Specific(Encoding::Identity)
|
||||
Preference::Any
|
||||
| Preference::Specific(Encoding::Known(ContentEncoding::Identity))
|
||||
)
|
||||
}) {
|
||||
// "identity" or "*" found so no representation is acceptable
|
||||
Some(_) => None,
|
||||
|
||||
// implicit "identity" is acceptable
|
||||
None => Some(Preference::Specific(Encoding::Identity)),
|
||||
None => Some(Preference::Specific(Encoding::identity())),
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -240,7 +241,9 @@ fn is_identity_acceptable(items: &'_ [QualityItem<Preference<Encoding>>]) -> boo
|
|||
for q in items {
|
||||
match (q.quality, &q.item) {
|
||||
// occurrence of "identity;q=n"; return true if quality is non-zero
|
||||
(q, Preference::Specific(Encoding::Identity)) => return q > Quality::ZERO,
|
||||
(q, Preference::Specific(Encoding::Known(ContentEncoding::Identity))) => {
|
||||
return q > Quality::ZERO
|
||||
}
|
||||
|
||||
// occurrence of "*;q=n"; return true if quality is non-zero
|
||||
(q, Preference::Any) => return q > Quality::ZERO,
|
||||
|
@ -308,80 +311,82 @@ mod tests {
|
|||
|
||||
let test = accept_encoding!();
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Identity].iter()),
|
||||
Some(Encoding::Identity),
|
||||
test.negotiate([Encoding::identity()].iter()),
|
||||
Some(Encoding::identity()),
|
||||
);
|
||||
|
||||
let test = accept_encoding!("identity;q=0");
|
||||
assert_eq!(test.negotiate([Encoding::Identity].iter()), None);
|
||||
assert_eq!(test.negotiate([Encoding::identity()].iter()), None);
|
||||
|
||||
let test = accept_encoding!("*;q=0");
|
||||
assert_eq!(test.negotiate([Encoding::Identity].iter()), None);
|
||||
assert_eq!(test.negotiate([Encoding::identity()].iter()), None);
|
||||
|
||||
let test = accept_encoding!();
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Identity),
|
||||
test.negotiate([Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::identity()),
|
||||
);
|
||||
|
||||
let test = accept_encoding!("gzip");
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip),
|
||||
test.negotiate([Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip()),
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Brotli, Encoding::Identity].iter()),
|
||||
Some(Encoding::Identity),
|
||||
test.negotiate([Encoding::brotli(), Encoding::identity()].iter()),
|
||||
Some(Encoding::identity()),
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Brotli, Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip),
|
||||
test.negotiate([Encoding::brotli(), Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip()),
|
||||
);
|
||||
|
||||
let test = accept_encoding!("gzip", "identity;q=0");
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip),
|
||||
test.negotiate([Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip()),
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Brotli, Encoding::Identity].iter()),
|
||||
test.negotiate([Encoding::brotli(), Encoding::identity()].iter()),
|
||||
None
|
||||
);
|
||||
|
||||
let test = accept_encoding!("gzip", "*;q=0");
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip),
|
||||
test.negotiate([Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip()),
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Brotli, Encoding::Identity].iter()),
|
||||
test.negotiate([Encoding::brotli(), Encoding::identity()].iter()),
|
||||
None
|
||||
);
|
||||
|
||||
let test = accept_encoding!("gzip", "deflate", "br");
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip),
|
||||
test.negotiate([Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip()),
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Brotli, Encoding::Identity].iter()),
|
||||
Some(Encoding::Brotli)
|
||||
test.negotiate([Encoding::brotli(), Encoding::identity()].iter()),
|
||||
Some(Encoding::brotli())
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Deflate, Encoding::Identity].iter()),
|
||||
Some(Encoding::Deflate)
|
||||
test.negotiate([Encoding::deflate(), Encoding::identity()].iter()),
|
||||
Some(Encoding::deflate())
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Deflate, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip)
|
||||
test.negotiate(
|
||||
[Encoding::gzip(), Encoding::deflate(), Encoding::identity()].iter()
|
||||
),
|
||||
Some(Encoding::gzip())
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Gzip, Encoding::Brotli, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip)
|
||||
test.negotiate([Encoding::gzip(), Encoding::brotli(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip())
|
||||
);
|
||||
assert_eq!(
|
||||
test.negotiate([Encoding::Brotli, Encoding::Gzip, Encoding::Identity].iter()),
|
||||
Some(Encoding::Gzip)
|
||||
test.negotiate([Encoding::brotli(), Encoding::gzip(), Encoding::identity()].iter()),
|
||||
Some(Encoding::gzip())
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,36 +1,44 @@
|
|||
use std::{fmt, str};
|
||||
|
||||
/// A value to represent an encoding used in the `Accept-Encoding` header.
|
||||
use actix_http::ContentEncoding;
|
||||
|
||||
/// A value to represent an encoding used in the `Accept-Encoding` and `Content-Encoding` header.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum Encoding {
|
||||
/// The no-op "identity" encoding.
|
||||
Identity,
|
||||
/// A supported content encoding. See [`ContentEncoding`] for variants.
|
||||
Known(ContentEncoding),
|
||||
|
||||
/// Brotli compression (`br`).
|
||||
Brotli,
|
||||
/// Some other encoding that is less common, can be any string.
|
||||
Unknown(String),
|
||||
}
|
||||
|
||||
/// Gzip compression.
|
||||
Gzip,
|
||||
impl Encoding {
|
||||
pub const fn identity() -> Self {
|
||||
Self::Known(ContentEncoding::Identity)
|
||||
}
|
||||
|
||||
/// Deflate (LZ77) encoding.
|
||||
Deflate,
|
||||
pub const fn brotli() -> Self {
|
||||
Self::Known(ContentEncoding::Brotli)
|
||||
}
|
||||
|
||||
/// Zstd compression.
|
||||
Zstd,
|
||||
pub const fn deflate() -> Self {
|
||||
Self::Known(ContentEncoding::Deflate)
|
||||
}
|
||||
|
||||
/// Some other encoding that is less common, can be any String.
|
||||
Other(String),
|
||||
pub const fn gzip() -> Self {
|
||||
Self::Known(ContentEncoding::Gzip)
|
||||
}
|
||||
|
||||
pub const fn zstd() -> Self {
|
||||
Self::Known(ContentEncoding::Zstd)
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Encoding {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(match self {
|
||||
Encoding::Identity => "identity",
|
||||
Encoding::Brotli => "br",
|
||||
Encoding::Gzip => "gzip",
|
||||
Encoding::Deflate => "deflate",
|
||||
Encoding::Zstd => "zstd",
|
||||
Encoding::Other(ref enc) => enc.as_ref(),
|
||||
Encoding::Known(enc) => enc.as_str(),
|
||||
Encoding::Unknown(enc) => enc.as_str(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -38,14 +46,10 @@ impl fmt::Display for Encoding {
|
|||
impl str::FromStr for Encoding {
|
||||
type Err = crate::error::ParseError;
|
||||
|
||||
fn from_str(enc_str: &str) -> Result<Self, crate::error::ParseError> {
|
||||
match enc_str {
|
||||
"identity" => Ok(Self::Identity),
|
||||
"br" => Ok(Self::Brotli),
|
||||
"gzip" => Ok(Self::Gzip),
|
||||
"deflate" => Ok(Self::Deflate),
|
||||
"zstd" => Ok(Self::Zstd),
|
||||
_ => Ok(Self::Other(enc_str.to_owned())),
|
||||
fn from_str(enc: &str) -> Result<Self, crate::error::ParseError> {
|
||||
match enc.parse::<ContentEncoding>() {
|
||||
Ok(enc) => Ok(Self::Known(enc)),
|
||||
Err(_) => Ok(Self::Unknown(enc.to_owned())),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ use pin_project_lite::pin_project;
|
|||
|
||||
use crate::{
|
||||
body::{EitherBody, MessageBody},
|
||||
dev::BodyEncoding,
|
||||
dev::BodyEncoding as _,
|
||||
http::{
|
||||
header::{self, AcceptEncoding, ContentEncoding, Encoding, HeaderValue},
|
||||
StatusCode,
|
||||
|
@ -111,22 +111,22 @@ static SUPPORTED_ENCODINGS_STRING: Lazy<String> = Lazy::new(|| {
|
|||
});
|
||||
|
||||
static SUPPORTED_ENCODINGS: Lazy<Vec<Encoding>> = Lazy::new(|| {
|
||||
let mut encodings = vec![Encoding::Identity];
|
||||
let mut encodings = vec![Encoding::identity()];
|
||||
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
{
|
||||
encodings.push(Encoding::Brotli);
|
||||
encodings.push(Encoding::brotli());
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
{
|
||||
encodings.push(Encoding::Gzip);
|
||||
encodings.push(Encoding::Deflate);
|
||||
encodings.push(Encoding::gzip());
|
||||
encodings.push(Encoding::deflate());
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-zstd")]
|
||||
{
|
||||
encodings.push(Encoding::Zstd);
|
||||
encodings.push(Encoding::zstd());
|
||||
}
|
||||
|
||||
assert!(
|
||||
|
@ -158,7 +158,7 @@ where
|
|||
// missing header; fallback to identity
|
||||
None => {
|
||||
return Either::left(CompressResponse {
|
||||
encoding: Encoding::Identity,
|
||||
encoding: Encoding::identity(),
|
||||
fut: self.service.call(req),
|
||||
_phantom: PhantomData,
|
||||
})
|
||||
|
@ -217,16 +217,14 @@ where
|
|||
|
||||
match ready!(this.fut.poll(cx)) {
|
||||
Ok(resp) => {
|
||||
let enc = if let Some(enc) = resp.response().get_encoding() {
|
||||
let enc = if let Some(enc) = resp.response().preferred_encoding() {
|
||||
enc
|
||||
} else {
|
||||
match this.encoding {
|
||||
Encoding::Brotli => ContentEncoding::Brotli,
|
||||
Encoding::Gzip => ContentEncoding::Gzip,
|
||||
Encoding::Deflate => ContentEncoding::Deflate,
|
||||
Encoding::Identity => ContentEncoding::Identity,
|
||||
Encoding::Zstd => ContentEncoding::Zstd,
|
||||
enc => unimplemented!("encoding {} should not be here", enc),
|
||||
Encoding::Known(enc) => *enc,
|
||||
Encoding::Unknown(enc) => {
|
||||
unimplemented!("encoding {} should not be here", enc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
@ -27,7 +27,7 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded
|
||||
.insert_header(ContentEncoding::Gzip)
|
||||
.body(LOREM_GZIP)
|
||||
|
@ -38,7 +38,7 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded
|
||||
.insert_header(ContentEncoding::Brotli)
|
||||
.body(LOREM_BR)
|
||||
|
@ -49,7 +49,7 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded
|
||||
.insert_header(ContentEncoding::Zstd)
|
||||
.body(LOREM_ZSTD)
|
||||
|
@ -60,7 +60,7 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded as 7zip
|
||||
.insert_header((header::CONTENT_ENCODING, "xz"))
|
||||
.body(LOREM_XZ)
|
||||
|
|
|
@ -136,12 +136,12 @@ async fn test_body_encoding_override() {
|
|||
.wrap(Compress::new(ContentEncoding::Gzip))
|
||||
.service(web::resource("/").route(web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Deflate)
|
||||
.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);
|
||||
res.encoding(ContentEncoding::Deflate);
|
||||
res.encode_with(ContentEncoding::Deflate);
|
||||
res.map_into_boxed_body()
|
||||
})))
|
||||
});
|
||||
|
@ -704,7 +704,7 @@ async fn test_brotli_encoding_large_openssl() {
|
|||
actix_test::start_with(actix_test::config().openssl(openssl_config()), move || {
|
||||
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
.body(bytes)
|
||||
})))
|
||||
});
|
||||
|
@ -765,20 +765,15 @@ mod plus_rustls {
|
|||
let srv = actix_test::start_with(actix_test::config().rustls(tls_config()), || {
|
||||
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
||||
HttpResponse::Ok()
|
||||
.encoding(ContentEncoding::Identity)
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
.body(bytes)
|
||||
})))
|
||||
});
|
||||
|
||||
// encode data
|
||||
let mut e = ZlibEncoder::new(Vec::new(), Compression::default());
|
||||
e.write_all(data.as_ref()).unwrap();
|
||||
let enc = e.finish().unwrap();
|
||||
|
||||
let req = srv
|
||||
.post("/")
|
||||
.insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate"))
|
||||
.send_stream(TestBody::new(Bytes::from(enc), 1024));
|
||||
.send_stream(TestBody::new(Bytes::from(deflate::encode(&data)), 1024));
|
||||
|
||||
let mut res = req.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
|
|
@ -1,3 +1,6 @@
|
|||
// 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 {
|
||||
|
|
Loading…
Reference in New Issue