mirror of
https://github.com/actix/actix-web.git
synced 2024-11-25 19:11:10 +00:00
remove BodyEncoding
trait (#2565)
This commit is contained in:
parent
19a46e3925
commit
0bc4ae9158
20 changed files with 355 additions and 403 deletions
11
.github/workflows/clippy-fmt.yml
vendored
11
.github/workflows/clippy-fmt.yml
vendored
|
@ -14,6 +14,7 @@ jobs:
|
|||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
components: rustfmt
|
||||
- name: Check with rustfmt
|
||||
uses: actions-rs/cargo@v1
|
||||
|
@ -30,10 +31,18 @@ jobs:
|
|||
uses: actions-rs/toolchain@v1
|
||||
with:
|
||||
toolchain: stable
|
||||
profile: minimal
|
||||
components: clippy
|
||||
override: true
|
||||
|
||||
- name: Generate Cargo.lock
|
||||
uses: actions-rs/cargo@v1
|
||||
with: { command: generate-lockfile }
|
||||
- name: Cache Dependencies
|
||||
uses: Swatinem/rust-cache@v1.2.0
|
||||
|
||||
- name: Check with Clippy
|
||||
uses: actions-rs/clippy-check@v1
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
args: --workspace --all-features --tests
|
||||
args: --workspace --tests --examples --all-features
|
||||
|
|
|
@ -15,8 +15,10 @@
|
|||
|
||||
### Removed
|
||||
- `Compress::new`; restricting compression algorithm is done through feature flags. [#2501]
|
||||
- `BodyEncoding` trait; signalling content encoding is now only done via the `Content-Encoding` header. [#2565]
|
||||
|
||||
[#2501]: https://github.com/actix/actix-web/pull/2501
|
||||
[#2565]: https://github.com/actix/actix-web/pull/2565
|
||||
|
||||
|
||||
## 4.0.0-beta.18 - 2021-12-29
|
||||
|
|
|
@ -597,7 +597,8 @@ mod tests {
|
|||
.to_request();
|
||||
let res = test::call_service(&srv, request).await;
|
||||
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]
|
||||
|
|
|
@ -9,14 +9,11 @@ use std::{
|
|||
use actix_service::{Service, ServiceFactory};
|
||||
use actix_web::{
|
||||
body::{self, BoxBody, SizedStream},
|
||||
dev::{
|
||||
AppService, BodyEncoding, HttpServiceFactory, ResourceDef, ServiceRequest,
|
||||
ServiceResponse,
|
||||
},
|
||||
dev::{AppService, HttpServiceFactory, ResourceDef, ServiceRequest, ServiceResponse},
|
||||
http::{
|
||||
header::{
|
||||
self, Charset, ContentDisposition, ContentEncoding, DispositionParam,
|
||||
DispositionType, ExtendedValue,
|
||||
DispositionType, ExtendedValue, HeaderValue,
|
||||
},
|
||||
StatusCode,
|
||||
},
|
||||
|
@ -224,7 +221,6 @@ impl NamedFile {
|
|||
})
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "experimental-io-uring"))]
|
||||
/// Attempts to open a file in read-only mode.
|
||||
///
|
||||
/// # Examples
|
||||
|
@ -232,6 +228,7 @@ impl NamedFile {
|
|||
/// use actix_files::NamedFile;
|
||||
/// let file = NamedFile::open("foo.txt");
|
||||
/// ```
|
||||
#[cfg(not(feature = "experimental-io-uring"))]
|
||||
pub fn open<P: AsRef<Path>>(path: P) -> io::Result<NamedFile> {
|
||||
let file = File::open(&path)?;
|
||||
Self::from_file(file, path)
|
||||
|
@ -295,23 +292,21 @@ impl NamedFile {
|
|||
self
|
||||
}
|
||||
|
||||
/// Set the MIME Content-Type for serving this file. By default
|
||||
/// the Content-Type is inferred from the filename extension.
|
||||
/// Set the MIME Content-Type for serving this file. By default the Content-Type is inferred
|
||||
/// from the filename extension.
|
||||
#[inline]
|
||||
pub fn set_content_type(mut self, mime_type: mime::Mime) -> Self {
|
||||
self.content_type = mime_type;
|
||||
self
|
||||
}
|
||||
|
||||
/// Set the Content-Disposition for serving this file. This allows
|
||||
/// changing the inline/attachment disposition as well as the filename
|
||||
/// sent to the peer.
|
||||
/// Set the Content-Disposition for serving this file. This allows changing the
|
||||
/// `inline/attachment` disposition as well as the filename sent to the peer.
|
||||
///
|
||||
/// By default the disposition is `inline` for `text/*`, `image/*`, `video/*` and
|
||||
/// `application/{javascript, json, wasm}` mime types, and `attachment` otherwise,
|
||||
/// and the filename is taken from the path provided in the `open` method
|
||||
/// after converting it to UTF-8 using.
|
||||
/// [`std::ffi::OsStr::to_string_lossy`]
|
||||
/// `application/{javascript, json, wasm}` mime types, and `attachment` otherwise, and the
|
||||
/// filename is taken from the path provided in the `open` method after converting it to UTF-8
|
||||
/// (using `to_string_lossy`).
|
||||
#[inline]
|
||||
pub fn set_content_disposition(mut self, cd: header::ContentDisposition) -> Self {
|
||||
self.content_disposition = cd;
|
||||
|
@ -337,7 +332,7 @@ impl NamedFile {
|
|||
self
|
||||
}
|
||||
|
||||
/// Specifies whether to use ETag or not.
|
||||
/// Specifies whether to return `ETag` header in response.
|
||||
///
|
||||
/// Default is true.
|
||||
#[inline]
|
||||
|
@ -346,7 +341,7 @@ impl NamedFile {
|
|||
self
|
||||
}
|
||||
|
||||
/// Specifies whether to use Last-Modified or not.
|
||||
/// Specifies whether to return `Last-Modified` header in response.
|
||||
///
|
||||
/// Default is true.
|
||||
#[inline]
|
||||
|
@ -364,7 +359,7 @@ impl NamedFile {
|
|||
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> {
|
||||
self.modified.as_ref().map(|mtime| {
|
||||
let ino = {
|
||||
|
@ -386,7 +381,7 @@ impl NamedFile {
|
|||
.duration_since(UNIX_EPOCH)
|
||||
.expect("modification time must be after epoch");
|
||||
|
||||
header::EntityTag::strong(format!(
|
||||
header::EntityTag::new_strong(format!(
|
||||
"{:x}:{:x}:{:x}:{:x}",
|
||||
ino,
|
||||
self.md.len(),
|
||||
|
@ -405,12 +400,13 @@ impl NamedFile {
|
|||
if self.status_code != StatusCode::OK {
|
||||
let mut res = HttpResponse::build(self.status_code);
|
||||
|
||||
if self.flags.contains(Flags::PREFER_UTF8) {
|
||||
let ct = equiv_utf8_text(self.content_type.clone());
|
||||
res.insert_header((header::CONTENT_TYPE, ct.to_string()));
|
||||
let ct = if self.flags.contains(Flags::PREFER_UTF8) {
|
||||
equiv_utf8_text(self.content_type.clone())
|
||||
} 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) {
|
||||
res.insert_header((
|
||||
|
@ -420,7 +416,7 @@ impl NamedFile {
|
|||
}
|
||||
|
||||
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);
|
||||
|
@ -478,12 +474,13 @@ impl NamedFile {
|
|||
|
||||
let mut res = HttpResponse::build(self.status_code);
|
||||
|
||||
if self.flags.contains(Flags::PREFER_UTF8) {
|
||||
let ct = equiv_utf8_text(self.content_type.clone());
|
||||
res.insert_header((header::CONTENT_TYPE, ct.to_string()));
|
||||
let ct = if self.flags.contains(Flags::PREFER_UTF8) {
|
||||
equiv_utf8_text(self.content_type.clone())
|
||||
} 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) {
|
||||
res.insert_header((
|
||||
|
@ -492,9 +489,8 @@ impl NamedFile {
|
|||
));
|
||||
}
|
||||
|
||||
// default compressing
|
||||
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 {
|
||||
|
@ -517,7 +513,12 @@ impl NamedFile {
|
|||
length = ranges[0].length;
|
||||
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((
|
||||
header::CONTENT_RANGE,
|
||||
format!("bytes {}-{}/{}", offset, offset + length - 1, self.md.len()),
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
- `QualityItem::min` semantics changed with `QualityItem::MIN`. [#2501]
|
||||
- Rename `ContentEncoding::{Br => Brotli}`. [#2501]
|
||||
- Minimum supported Rust version (MSRV) is now 1.54.
|
||||
- Rename `header::EntityTag::{weak => new_weak, strong => new_strong}`. [#2565]
|
||||
|
||||
### Fixed
|
||||
- `ContentEncoding::Identity` can now be parsed from a string. [#2501]
|
||||
|
@ -23,6 +24,7 @@
|
|||
- `ContentEncoding::is_compression()`. [#2501]
|
||||
|
||||
[#2501]: https://github.com/actix/actix-web/pull/2501
|
||||
[#2565]: https://github.com/actix/actix-web/pull/2565
|
||||
|
||||
|
||||
## 3.0.0-beta.17 - 2021-12-27
|
||||
|
|
|
@ -6,7 +6,7 @@ use ahash::AHashMap;
|
|||
use http::header::{HeaderName, HeaderValue};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
use crate::header::AsHeaderName;
|
||||
use super::AsHeaderName;
|
||||
|
||||
/// A multi-map of HTTP headers.
|
||||
///
|
||||
|
|
|
@ -50,10 +50,10 @@ pub use self::utils::{
|
|||
|
||||
/// An interface for types that already represent a valid header.
|
||||
pub trait Header: TryIntoHeaderValue {
|
||||
/// Returns the name of the header field
|
||||
/// Returns the name of the header field.
|
||||
fn name() -> HeaderName;
|
||||
|
||||
/// Parse a header
|
||||
/// Parse the header from a HTTP message.
|
||||
fn parse<M: HttpMessage>(msg: &M) -> Result<Self, ParseError>;
|
||||
}
|
||||
|
||||
|
|
|
@ -68,6 +68,7 @@ impl ContentEncoding {
|
|||
}
|
||||
|
||||
impl Default for ContentEncoding {
|
||||
#[inline]
|
||||
fn default() -> Self {
|
||||
Self::Identity
|
||||
}
|
||||
|
|
|
@ -102,12 +102,14 @@ actix-utils = "3.0.0"
|
|||
actix-web = { version = "4.0.0-beta.18", features = ["openssl"] }
|
||||
|
||||
brotli2 = "0.3.2"
|
||||
const-str = "0.3"
|
||||
env_logger = "0.9"
|
||||
flate2 = "1.0.13"
|
||||
futures-util = { version = "0.3.7", default-features = false }
|
||||
static_assertions = "1.1"
|
||||
rcgen = "0.8"
|
||||
rustls-pemfile = "0.2"
|
||||
zstd = "0.9"
|
||||
|
||||
[[example]]
|
||||
name = "client"
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
use std::{
|
||||
collections::HashMap,
|
||||
convert::Infallible,
|
||||
io::{Read, Write},
|
||||
net::{IpAddr, Ipv4Addr},
|
||||
sync::{
|
||||
|
@ -15,43 +16,16 @@ use cookie::Cookie;
|
|||
use futures_util::stream;
|
||||
use rand::Rng;
|
||||
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
use brotli2::write::BrotliEncoder;
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
use flate2::{read::GzDecoder, write::GzEncoder, Compression};
|
||||
|
||||
use actix_http::{ContentEncoding, HttpService, StatusCode};
|
||||
use actix_http::{HttpService, StatusCode};
|
||||
use actix_http_test::test_server;
|
||||
use actix_service::{fn_service, map_config, ServiceFactoryExt as _};
|
||||
use actix_web::{
|
||||
dev::{AppConfig, BodyEncoding},
|
||||
http::header,
|
||||
web, App, Error, HttpRequest, HttpResponse,
|
||||
};
|
||||
use actix_web::{dev::AppConfig, http::header, web, App, Error, HttpRequest, HttpResponse};
|
||||
use awc::error::{JsonPayloadError, PayloadError, SendRequestError};
|
||||
|
||||
const STR: &str = "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 \
|
||||
Hello World Hello World Hello World Hello World Hello World \
|
||||
Hello World Hello World Hello World Hello World Hello World";
|
||||
mod utils;
|
||||
|
||||
const S: &str = "Hello World ";
|
||||
const STR: &str = const_str::repeat!(S, 100);
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_simple() {
|
||||
|
@ -471,15 +445,12 @@ async fn test_no_decompress() {
|
|||
let srv = actix_test::start(|| {
|
||||
App::new()
|
||||
.wrap(actix_web::middleware::Compress::default())
|
||||
.service(web::resource("/").route(web::to(|| {
|
||||
let mut res = HttpResponse::Ok().body(STR);
|
||||
res.encode_with(header::ContentEncoding::Gzip);
|
||||
res
|
||||
})))
|
||||
.service(web::resource("/").route(web::to(|| HttpResponse::Ok().body(STR))))
|
||||
});
|
||||
|
||||
let mut res = awc::Client::new()
|
||||
.get(srv.url("/"))
|
||||
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -488,15 +459,12 @@ async fn test_no_decompress() {
|
|||
|
||||
// read response
|
||||
let bytes = res.body().await.unwrap();
|
||||
|
||||
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()));
|
||||
assert_eq!(utils::gzip::decode(bytes), STR.as_bytes());
|
||||
|
||||
// POST
|
||||
let mut res = awc::Client::new()
|
||||
.post(srv.url("/"))
|
||||
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -504,10 +472,7 @@ async fn test_no_decompress() {
|
|||
assert!(res.status().is_success());
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
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()));
|
||||
assert_eq!(utils::gzip::decode(bytes), STR.as_bytes());
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
|
@ -515,13 +480,9 @@ async fn test_no_decompress() {
|
|||
async fn test_client_gzip_encoding() {
|
||||
let srv = actix_test::start(|| {
|
||||
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()
|
||||
.insert_header(("content-encoding", "gzip"))
|
||||
.body(data)
|
||||
.insert_header(header::ContentEncoding::Gzip)
|
||||
.body(utils::gzip::encode(STR))
|
||||
})))
|
||||
});
|
||||
|
||||
|
@ -531,7 +492,7 @@ async fn test_client_gzip_encoding() {
|
|||
|
||||
// read response
|
||||
let bytes = response.body().await.unwrap();
|
||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||
assert_eq!(bytes, STR);
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
|
@ -539,13 +500,9 @@ async fn test_client_gzip_encoding() {
|
|||
async fn test_client_gzip_encoding_large() {
|
||||
let srv = actix_test::start(|| {
|
||||
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()
|
||||
.insert_header(("content-encoding", "gzip"))
|
||||
.body(data)
|
||||
.insert_header(header::ContentEncoding::Gzip)
|
||||
.body(utils::gzip::encode(STR.repeat(10)))
|
||||
})))
|
||||
});
|
||||
|
||||
|
@ -555,7 +512,7 @@ async fn test_client_gzip_encoding_large() {
|
|||
|
||||
// read response
|
||||
let bytes = response.body().await.unwrap();
|
||||
assert_eq!(bytes, Bytes::from(STR.repeat(10)));
|
||||
assert_eq!(bytes, STR.repeat(10));
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-gzip")]
|
||||
|
@ -569,12 +526,9 @@ async fn test_client_gzip_encoding_large_random() {
|
|||
|
||||
let srv = actix_test::start(|| {
|
||||
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()
|
||||
.insert_header(("content-encoding", "gzip"))
|
||||
.body(data)
|
||||
.insert_header(header::ContentEncoding::Gzip)
|
||||
.body(utils::gzip::encode(data))
|
||||
})))
|
||||
});
|
||||
|
||||
|
@ -584,7 +538,7 @@ async fn test_client_gzip_encoding_large_random() {
|
|||
|
||||
// read response
|
||||
let bytes = response.body().await.unwrap();
|
||||
assert_eq!(bytes, Bytes::from(data));
|
||||
assert_eq!(bytes, data);
|
||||
}
|
||||
|
||||
#[cfg(feature = "compress-brotli")]
|
||||
|
@ -592,12 +546,9 @@ async fn test_client_gzip_encoding_large_random() {
|
|||
async fn test_client_brotli_encoding() {
|
||||
let srv = actix_test::start(|| {
|
||||
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()
|
||||
.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(|| {
|
||||
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()
|
||||
.insert_header(("content-encoding", "br"))
|
||||
.body(data)
|
||||
.insert_header(header::ContentEncoding::Brotli)
|
||||
.body(utils::brotli::encode(&data))
|
||||
})))
|
||||
});
|
||||
|
||||
|
@ -636,27 +584,25 @@ async fn test_client_brotli_encoding_large_random() {
|
|||
|
||||
// read response
|
||||
let bytes = response.body().await.unwrap();
|
||||
assert_eq!(bytes.len(), data.len());
|
||||
assert_eq!(bytes, Bytes::from(data));
|
||||
assert_eq!(bytes, data);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_client_deflate_encoding() {
|
||||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|body: Bytes| {
|
||||
HttpResponse::Ok()
|
||||
.encode_with(ContentEncoding::Brotli)
|
||||
.body(body)
|
||||
}))
|
||||
App::new().default_service(web::to(|body: Bytes| HttpResponse::Ok().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();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||
assert_eq!(bytes, STR);
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
|
@ -668,14 +614,13 @@ async fn test_client_deflate_encoding_large_random() {
|
|||
.collect::<String>();
|
||||
|
||||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|body: Bytes| {
|
||||
HttpResponse::Ok()
|
||||
.encode_with(ContentEncoding::Brotli)
|
||||
.body(body)
|
||||
}))
|
||||
App::new().default_service(web::to(|body: Bytes| HttpResponse::Ok().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 bytes = res.body().await.unwrap();
|
||||
|
@ -688,15 +633,16 @@ async fn test_client_deflate_encoding_large_random() {
|
|||
async fn test_client_streaming_explicit() {
|
||||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|body: web::Payload| {
|
||||
HttpResponse::Ok()
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
.streaming(body)
|
||||
HttpResponse::Ok().streaming(body)
|
||||
}))
|
||||
});
|
||||
|
||||
let body =
|
||||
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();
|
||||
assert!(res.status().is_success());
|
||||
|
@ -709,17 +655,16 @@ async fn test_client_streaming_explicit() {
|
|||
async fn test_body_streaming_implicit() {
|
||||
let srv = actix_test::start(|| {
|
||||
App::new().default_service(web::to(|| {
|
||||
let body = stream::once(async {
|
||||
Ok::<_, actix_http::Error>(Bytes::from_static(STR.as_bytes()))
|
||||
});
|
||||
|
||||
HttpResponse::Ok()
|
||||
.encode_with(ContentEncoding::Gzip)
|
||||
.streaming(Box::pin(body))
|
||||
let body =
|
||||
stream::once(async { Ok::<_, Infallible>(Bytes::from_static(STR.as_bytes())) });
|
||||
HttpResponse::Ok().streaming(body)
|
||||
}))
|
||||
});
|
||||
|
||||
let req = srv.get("/").send();
|
||||
let req = srv
|
||||
.get("/")
|
||||
.insert_header((header::ACCEPT_ENCODING, "gzip"))
|
||||
.send();
|
||||
|
||||
let mut res = req.await.unwrap();
|
||||
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};
|
||||
|
||||
use crate::{http::header::ContentEncoding, HttpMessage as _};
|
||||
|
||||
use actix_router::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
|
||||
}
|
||||
|
||||
/// 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)
|
||||
}
|
||||
|
||||
/// An entity tag, defined
|
||||
/// in [RFC 7232 §2.3](https://datatracker.ietf.org/doc/html/rfc7232#section-2.3)
|
||||
/// An entity tag, defined in [RFC 7232 §2.3].
|
||||
///
|
||||
/// An entity tag consists of a string enclosed by two literal double quotes.
|
||||
/// 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"` | `"1"` | no 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 {
|
||||
/// Weakness indicator for the tag
|
||||
pub weak: bool,
|
||||
|
||||
/// The opaque string in between the DQUOTEs
|
||||
tag: String,
|
||||
}
|
||||
|
||||
impl EntityTag {
|
||||
/// Constructs a new EntityTag.
|
||||
/// Constructs a new `EntityTag`.
|
||||
///
|
||||
/// # Panics
|
||||
/// If the tag contains invalid characters.
|
||||
pub fn new(weak: bool, tag: String) -> EntityTag {
|
||||
|
@ -66,51 +69,64 @@ impl EntityTag {
|
|||
}
|
||||
|
||||
/// Constructs a new weak EntityTag.
|
||||
///
|
||||
/// # Panics
|
||||
/// If the tag contains invalid characters.
|
||||
pub fn weak(tag: String) -> EntityTag {
|
||||
pub fn new_weak(tag: String) -> EntityTag {
|
||||
EntityTag::new(true, tag)
|
||||
}
|
||||
|
||||
#[deprecated(since = "3.0.0", note = "Renamed to `new_weak`.")]
|
||||
pub fn weak(tag: String) -> EntityTag {
|
||||
Self::new_weak(tag)
|
||||
}
|
||||
|
||||
/// Constructs a new strong EntityTag.
|
||||
///
|
||||
/// # Panics
|
||||
/// If the tag contains invalid characters.
|
||||
pub fn strong(tag: String) -> EntityTag {
|
||||
pub fn new_strong(tag: String) -> EntityTag {
|
||||
EntityTag::new(false, tag)
|
||||
}
|
||||
|
||||
/// Get the tag.
|
||||
#[deprecated(since = "3.0.0", note = "Renamed to `new_strong`.")]
|
||||
pub fn strong(tag: String) -> EntityTag {
|
||||
Self::new_strong(tag)
|
||||
}
|
||||
|
||||
/// Returns tag.
|
||||
pub fn tag(&self) -> &str {
|
||||
self.tag.as_ref()
|
||||
}
|
||||
|
||||
/// Set the tag.
|
||||
/// Sets tag.
|
||||
///
|
||||
/// # Panics
|
||||
/// If the tag contains invalid characters.
|
||||
pub fn set_tag(&mut self, tag: String) {
|
||||
pub fn set_tag(&mut self, tag: impl Into<String>) {
|
||||
let tag = tag.into();
|
||||
assert!(check_slice_validity(&tag), "Invalid tag: {:?}", tag);
|
||||
self.tag = tag
|
||||
}
|
||||
|
||||
/// For strong comparison two entity-tags are equivalent if both are not
|
||||
/// weak and their opaque-tags match character-by-character.
|
||||
/// For strong comparison two entity-tags are equivalent if both are not weak and their
|
||||
/// opaque-tags match character-by-character.
|
||||
pub fn strong_eq(&self, other: &EntityTag) -> bool {
|
||||
!self.weak && !other.weak && self.tag == other.tag
|
||||
}
|
||||
|
||||
/// For weak comparison two entity-tags are equivalent if their
|
||||
/// opaque-tags match character-by-character, regardless of either or
|
||||
/// both being tagged as "weak".
|
||||
/// For weak comparison two entity-tags are equivalent if their opaque-tags match
|
||||
/// character-by-character, regardless of either or both being tagged as "weak".
|
||||
pub fn weak_eq(&self, other: &EntityTag) -> bool {
|
||||
self.tag == other.tag
|
||||
}
|
||||
|
||||
/// The inverse of `EntityTag.strong_eq()`.
|
||||
/// Returns the inverse of `strong_eq()`.
|
||||
pub fn strong_ne(&self, other: &EntityTag) -> bool {
|
||||
!self.strong_eq(other)
|
||||
}
|
||||
|
||||
/// The inverse of `EntityTag.weak_eq()`.
|
||||
/// Returns inverse of `weak_eq()`.
|
||||
pub fn weak_ne(&self, other: &EntityTag) -> bool {
|
||||
!self.weak_eq(other)
|
||||
}
|
||||
|
@ -178,23 +194,23 @@ mod tests {
|
|||
// Expected success
|
||||
assert_eq!(
|
||||
"\"foobar\"".parse::<EntityTag>().unwrap(),
|
||||
EntityTag::strong("foobar".to_owned())
|
||||
EntityTag::new_strong("foobar".to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
"\"\"".parse::<EntityTag>().unwrap(),
|
||||
EntityTag::strong("".to_owned())
|
||||
EntityTag::new_strong("".to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
"W/\"weaktag\"".parse::<EntityTag>().unwrap(),
|
||||
EntityTag::weak("weaktag".to_owned())
|
||||
EntityTag::new_weak("weaktag".to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
"W/\"\x65\x62\"".parse::<EntityTag>().unwrap(),
|
||||
EntityTag::weak("\x65\x62".to_owned())
|
||||
EntityTag::new_weak("\x65\x62".to_owned())
|
||||
);
|
||||
assert_eq!(
|
||||
"W/\"\"".parse::<EntityTag>().unwrap(),
|
||||
EntityTag::weak("".to_owned())
|
||||
EntityTag::new_weak("".to_owned())
|
||||
);
|
||||
}
|
||||
|
||||
|
@ -214,19 +230,19 @@ mod tests {
|
|||
#[test]
|
||||
fn test_etag_fmt() {
|
||||
assert_eq!(
|
||||
format!("{}", EntityTag::strong("foobar".to_owned())),
|
||||
format!("{}", EntityTag::new_strong("foobar".to_owned())),
|
||||
"\"foobar\""
|
||||
);
|
||||
assert_eq!(format!("{}", EntityTag::strong("".to_owned())), "\"\"");
|
||||
assert_eq!(format!("{}", EntityTag::new_strong("".to_owned())), "\"\"");
|
||||
assert_eq!(
|
||||
format!("{}", EntityTag::weak("weak-etag".to_owned())),
|
||||
format!("{}", EntityTag::new_weak("weak-etag".to_owned())),
|
||||
"W/\"weak-etag\""
|
||||
);
|
||||
assert_eq!(
|
||||
format!("{}", EntityTag::weak("\u{0065}".to_owned())),
|
||||
format!("{}", EntityTag::new_weak("\u{0065}".to_owned())),
|
||||
"W/\"\x65\""
|
||||
);
|
||||
assert_eq!(format!("{}", EntityTag::weak("".to_owned())), "W/\"\"");
|
||||
assert_eq!(format!("{}", EntityTag::new_weak("".to_owned())), "W/\"\"");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -237,29 +253,29 @@ mod tests {
|
|||
// | `W/"1"` | `W/"2"` | no match | no match |
|
||||
// | `W/"1"` | `"1"` | no match | match |
|
||||
// | `"1"` | `"1"` | match | match |
|
||||
let mut etag1 = EntityTag::weak("1".to_owned());
|
||||
let mut etag2 = EntityTag::weak("1".to_owned());
|
||||
let mut etag1 = EntityTag::new_weak("1".to_owned());
|
||||
let mut etag2 = EntityTag::new_weak("1".to_owned());
|
||||
assert!(!etag1.strong_eq(&etag2));
|
||||
assert!(etag1.weak_eq(&etag2));
|
||||
assert!(etag1.strong_ne(&etag2));
|
||||
assert!(!etag1.weak_ne(&etag2));
|
||||
|
||||
etag1 = EntityTag::weak("1".to_owned());
|
||||
etag2 = EntityTag::weak("2".to_owned());
|
||||
etag1 = EntityTag::new_weak("1".to_owned());
|
||||
etag2 = EntityTag::new_weak("2".to_owned());
|
||||
assert!(!etag1.strong_eq(&etag2));
|
||||
assert!(!etag1.weak_eq(&etag2));
|
||||
assert!(etag1.strong_ne(&etag2));
|
||||
assert!(etag1.weak_ne(&etag2));
|
||||
|
||||
etag1 = EntityTag::weak("1".to_owned());
|
||||
etag2 = EntityTag::strong("1".to_owned());
|
||||
etag1 = EntityTag::new_weak("1".to_owned());
|
||||
etag2 = EntityTag::new_strong("1".to_owned());
|
||||
assert!(!etag1.strong_eq(&etag2));
|
||||
assert!(etag1.weak_eq(&etag2));
|
||||
assert!(etag1.strong_ne(&etag2));
|
||||
assert!(!etag1.weak_ne(&etag2));
|
||||
|
||||
etag1 = EntityTag::strong("1".to_owned());
|
||||
etag2 = EntityTag::strong("1".to_owned());
|
||||
etag1 = EntityTag::new_strong("1".to_owned());
|
||||
etag2 = EntityTag::new_strong("1".to_owned());
|
||||
assert!(etag1.strong_eq(&etag2));
|
||||
assert!(etag1.weak_eq(&etag2));
|
||||
assert!(!etag1.strong_ne(&etag2));
|
||||
|
|
|
@ -31,7 +31,7 @@ crate::http::header::common_header! {
|
|||
///
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ETag(EntityTag::new(false, "xyzzy".to_owned()))
|
||||
/// ETag(EntityTag::new_strong("xyzzy".to_owned()))
|
||||
/// );
|
||||
/// ```
|
||||
///
|
||||
|
@ -41,7 +41,7 @@ crate::http::header::common_header! {
|
|||
///
|
||||
/// let mut builder = HttpResponse::Ok();
|
||||
/// builder.insert_header(
|
||||
/// ETag(EntityTag::new(true, "xyzzy".to_owned()))
|
||||
/// ETag(EntityTag::new_weak("xyzzy".to_owned()))
|
||||
/// );
|
||||
/// ```
|
||||
(ETag, ETAG) => [EntityTag]
|
||||
|
@ -50,29 +50,29 @@ crate::http::header::common_header! {
|
|||
// From the RFC
|
||||
crate::http::header::common_header_test!(test1,
|
||||
vec![b"\"xyzzy\""],
|
||||
Some(ETag(EntityTag::new(false, "xyzzy".to_owned()))));
|
||||
Some(ETag(EntityTag::new_strong("xyzzy".to_owned()))));
|
||||
crate::http::header::common_header_test!(test2,
|
||||
vec![b"W/\"xyzzy\""],
|
||||
Some(ETag(EntityTag::new(true, "xyzzy".to_owned()))));
|
||||
Some(ETag(EntityTag::new_weak("xyzzy".to_owned()))));
|
||||
crate::http::header::common_header_test!(test3,
|
||||
vec![b"\"\""],
|
||||
Some(ETag(EntityTag::new(false, "".to_owned()))));
|
||||
Some(ETag(EntityTag::new_strong("".to_owned()))));
|
||||
// Own tests
|
||||
crate::http::header::common_header_test!(test4,
|
||||
vec![b"\"foobar\""],
|
||||
Some(ETag(EntityTag::new(false, "foobar".to_owned()))));
|
||||
Some(ETag(EntityTag::new_strong("foobar".to_owned()))));
|
||||
crate::http::header::common_header_test!(test5,
|
||||
vec![b"\"\""],
|
||||
Some(ETag(EntityTag::new(false, "".to_owned()))));
|
||||
Some(ETag(EntityTag::new_strong("".to_owned()))));
|
||||
crate::http::header::common_header_test!(test6,
|
||||
vec![b"W/\"weak-etag\""],
|
||||
Some(ETag(EntityTag::new(true, "weak-etag".to_owned()))));
|
||||
Some(ETag(EntityTag::new_weak("weak-etag".to_owned()))));
|
||||
crate::http::header::common_header_test!(test7,
|
||||
vec![b"W/\"\x65\x62\""],
|
||||
Some(ETag(EntityTag::new(true, "\u{0065}\u{0062}".to_owned()))));
|
||||
Some(ETag(EntityTag::new_weak("\u{0065}\u{0062}".to_owned()))));
|
||||
crate::http::header::common_header_test!(test8,
|
||||
vec![b"W/\"\""],
|
||||
Some(ETag(EntityTag::new(true, "".to_owned()))));
|
||||
Some(ETag(EntityTag::new_weak("".to_owned()))));
|
||||
crate::http::header::common_header_test!(test9,
|
||||
vec![b"no-dquotes"],
|
||||
None::<ETag>);
|
||||
|
|
|
@ -54,14 +54,15 @@ common_header! {
|
|||
test1,
|
||||
vec![b"\"xyzzy\""],
|
||||
Some(HeaderField::Items(
|
||||
vec![EntityTag::new(false, "xyzzy".to_owned())])));
|
||||
vec![EntityTag::new_strong("xyzzy".to_owned())])));
|
||||
|
||||
crate::http::header::common_header_test!(
|
||||
test2,
|
||||
vec![b"\"xyzzy\", \"r2d2xxxx\", \"c3piozzzz\""],
|
||||
Some(HeaderField::Items(
|
||||
vec![EntityTag::new(false, "xyzzy".to_owned()),
|
||||
EntityTag::new(false, "r2d2xxxx".to_owned()),
|
||||
EntityTag::new(false, "c3piozzzz".to_owned())])));
|
||||
vec![EntityTag::new_strong("xyzzy".to_owned()),
|
||||
EntityTag::new_strong("r2d2xxxx".to_owned()),
|
||||
EntityTag::new_strong("c3piozzzz".to_owned())])));
|
||||
crate::http::header::common_header_test!(test3, vec![b"*"], Some(IfMatch::Any));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -82,8 +82,8 @@ mod tests {
|
|||
|
||||
if_none_match = Header::parse(&req);
|
||||
let mut entities: Vec<EntityTag> = Vec::new();
|
||||
let foobar_etag = EntityTag::new(false, "foobar".to_owned());
|
||||
let weak_etag = EntityTag::new(true, "weak-etag".to_owned());
|
||||
let foobar_etag = EntityTag::new_strong("foobar".to_owned());
|
||||
let weak_etag = EntityTag::new_weak("weak-etag".to_owned());
|
||||
entities.push(foobar_etag);
|
||||
entities.push(weak_etag);
|
||||
assert_eq!(if_none_match.ok(), Some(IfNoneMatch::Items(entities)));
|
||||
|
|
|
@ -16,7 +16,6 @@ use pin_project_lite::pin_project;
|
|||
|
||||
use crate::{
|
||||
body::{EitherBody, MessageBody},
|
||||
dev::BodyEncoding as _,
|
||||
http::{
|
||||
header::{self, AcceptEncoding, Encoding, HeaderValue},
|
||||
StatusCode,
|
||||
|
@ -176,15 +175,11 @@ where
|
|||
|
||||
match ready!(this.fut.poll(cx)) {
|
||||
Ok(resp) => {
|
||||
let enc = if let Some(enc) = resp.response().preferred_encoding() {
|
||||
enc
|
||||
} else {
|
||||
match this.encoding {
|
||||
let enc = match this.encoding {
|
||||
Encoding::Known(enc) => *enc,
|
||||
Encoding::Unknown(enc) => {
|
||||
unimplemented!("encoding {} should not be here", enc);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Poll::Ready(Ok(resp.map_body(move |head, body| {
|
||||
|
|
|
@ -1,14 +1,12 @@
|
|||
use actix_http::ContentEncoding;
|
||||
use actix_web::{
|
||||
dev::BodyEncoding as _,
|
||||
http::{header, StatusCode},
|
||||
middleware::Compress,
|
||||
web, App, HttpResponse,
|
||||
};
|
||||
use bytes::Bytes;
|
||||
|
||||
mod test_utils;
|
||||
use test_utils::{brotli, gzip, zstd};
|
||||
mod utils;
|
||||
|
||||
static LOREM: &[u8] = include_bytes!("fixtures/lorem.txt");
|
||||
static LOREM_GZIP: &[u8] = include_bytes!("fixtures/lorem.txt.gz");
|
||||
|
@ -27,7 +25,6 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded
|
||||
.insert_header(ContentEncoding::Gzip)
|
||||
.body(LOREM_GZIP)
|
||||
|
@ -38,7 +35,6 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded
|
||||
.insert_header(ContentEncoding::Brotli)
|
||||
.body(LOREM_BR)
|
||||
|
@ -49,7 +45,6 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded
|
||||
.insert_header(ContentEncoding::Zstd)
|
||||
.body(LOREM_ZSTD)
|
||||
|
@ -60,7 +55,6 @@ macro_rules! test_server {
|
|||
web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
// signal to compressor that content should not be altered
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
// signal to client that content is encoded as 7zip
|
||||
.insert_header((header::CONTENT_ENCODING, "xz"))
|
||||
.body(LOREM_XZ)
|
||||
|
@ -117,7 +111,7 @@ async fn negotiate_encoding_gzip() {
|
|||
.await
|
||||
.unwrap();
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(gzip::decode(bytes), LOREM);
|
||||
assert_eq!(utils::gzip::decode(bytes), LOREM);
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -146,7 +140,7 @@ async fn negotiate_encoding_br() {
|
|||
.await
|
||||
.unwrap();
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(brotli::decode(bytes), LOREM);
|
||||
assert_eq!(utils::brotli::decode(bytes), LOREM);
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -175,7 +169,7 @@ async fn negotiate_encoding_zstd() {
|
|||
.await
|
||||
.unwrap();
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(zstd::decode(bytes), LOREM);
|
||||
assert_eq!(utils::zstd::decode(bytes), LOREM);
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
|
|
@ -12,11 +12,7 @@ use std::{
|
|||
|
||||
use actix_web::{
|
||||
cookie::{Cookie, CookieBuilder},
|
||||
dev::BodyEncoding,
|
||||
http::{
|
||||
header::{self, ContentEncoding, ACCEPT_ENCODING, CONTENT_ENCODING, TRANSFER_ENCODING},
|
||||
StatusCode,
|
||||
},
|
||||
http::{header, StatusCode},
|
||||
middleware::{Compress, NormalizePath, TrailingSlash},
|
||||
web, App, Error, HttpResponse,
|
||||
};
|
||||
|
@ -31,30 +27,10 @@ use openssl::{
|
|||
x509::X509,
|
||||
};
|
||||
|
||||
mod test_utils;
|
||||
use test_utils::{brotli, deflate, gzip, zstd};
|
||||
mod utils;
|
||||
|
||||
const STR: &str = "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 \
|
||||
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 ";
|
||||
const STR: &str = const_str::repeat!(S, 100);
|
||||
|
||||
#[cfg(feature = "openssl")]
|
||||
fn openssl_config() -> SslAcceptor {
|
||||
|
@ -129,51 +105,52 @@ async fn test_body() {
|
|||
srv.stop().await;
|
||||
}
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn test_body_encoding_override() {
|
||||
let srv = actix_test::start_with(actix_test::config().h1(), || {
|
||||
App::new()
|
||||
.wrap(Compress::default())
|
||||
.service(web::resource("/").route(web::to(|| {
|
||||
HttpResponse::Ok()
|
||||
.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.encode_with(ContentEncoding::Deflate);
|
||||
res.map_into_boxed_body()
|
||||
})))
|
||||
});
|
||||
// enforcing an encoding per-response is removed
|
||||
// #[actix_rt::test]
|
||||
// async fn test_body_encoding_override() {
|
||||
// let srv = actix_test::start_with(actix_test::config().h1(), || {
|
||||
// App::new()
|
||||
// .wrap(Compress::default())
|
||||
// .service(web::resource("/").route(web::to(|| {
|
||||
// HttpResponse::Ok()
|
||||
// .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.encode_with(ContentEncoding::Deflate);
|
||||
// res.map_into_boxed_body()
|
||||
// })))
|
||||
// });
|
||||
|
||||
// Builder
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.no_decompress()
|
||||
.append_header((ACCEPT_ENCODING, "deflate"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
// // Builder
|
||||
// let mut res = srv
|
||||
// .get("/")
|
||||
// .no_decompress()
|
||||
// .append_header((ACCEPT_ENCODING, "deflate"))
|
||||
// .send()
|
||||
// .await
|
||||
// .unwrap();
|
||||
// assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
||||
// let bytes = res.body().await.unwrap();
|
||||
// assert_eq!(utils::deflate::decode(bytes), STR.as_bytes());
|
||||
|
||||
// Raw Response
|
||||
let mut res = srv
|
||||
.request(actix_web::http::Method::GET, srv.url("/raw"))
|
||||
.no_decompress()
|
||||
.append_header((ACCEPT_ENCODING, "deflate"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
// // Raw Response
|
||||
// let mut res = srv
|
||||
// .request(actix_web::http::Method::GET, srv.url("/raw"))
|
||||
// .no_decompress()
|
||||
// .append_header((ACCEPT_ENCODING, "deflate"))
|
||||
// .send()
|
||||
// .await
|
||||
// .unwrap();
|
||||
// assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
||||
// let bytes = res.body().await.unwrap();
|
||||
// assert_eq!(utils::deflate::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
// srv.stop().await;
|
||||
// }
|
||||
|
||||
#[actix_rt::test]
|
||||
async fn body_gzip_large() {
|
||||
|
@ -191,14 +168,14 @@ async fn body_gzip_large() {
|
|||
let mut res = srv
|
||||
.get("/")
|
||||
.no_decompress()
|
||||
.append_header((ACCEPT_ENCODING, "gzip"))
|
||||
.append_header((header::ACCEPT_ENCODING, "gzip"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(gzip::decode(bytes), data.as_bytes());
|
||||
assert_eq!(utils::gzip::decode(bytes), data.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -222,14 +199,14 @@ async fn test_body_gzip_large_random() {
|
|||
let mut res = srv
|
||||
.get("/")
|
||||
.no_decompress()
|
||||
.append_header((ACCEPT_ENCODING, "gzip"))
|
||||
.append_header((header::ACCEPT_ENCODING, "gzip"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(gzip::decode(bytes), data.as_bytes());
|
||||
assert_eq!(utils::gzip::decode(bytes), data.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -248,15 +225,18 @@ async fn test_body_chunked_implicit() {
|
|||
let mut res = srv
|
||||
.get("/")
|
||||
.no_decompress()
|
||||
.append_header((ACCEPT_ENCODING, "gzip"))
|
||||
.append_header((header::ACCEPT_ENCODING, "gzip"))
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
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();
|
||||
assert_eq!(gzip::decode(bytes), STR.as_bytes());
|
||||
assert_eq!(utils::gzip::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -274,7 +254,7 @@ async fn test_body_br_streaming() {
|
|||
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.append_header((ACCEPT_ENCODING, "br"))
|
||||
.append_header((header::ACCEPT_ENCODING, "br"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -282,7 +262,7 @@ async fn test_body_br_streaming() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(brotli::decode(bytes), STR.as_bytes());
|
||||
assert_eq!(utils::brotli::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -319,7 +299,7 @@ async fn test_no_chunking() {
|
|||
|
||||
let mut res = srv.get("/").send().await.unwrap();
|
||||
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();
|
||||
assert_eq!(bytes, Bytes::from_static(STR.as_ref()));
|
||||
|
@ -337,7 +317,7 @@ async fn test_body_deflate() {
|
|||
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.append_header((ACCEPT_ENCODING, "deflate"))
|
||||
.append_header((header::ACCEPT_ENCODING, "deflate"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -345,7 +325,7 @@ async fn test_body_deflate() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(deflate::decode(bytes), STR.as_bytes());
|
||||
assert_eq!(utils::deflate::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -360,7 +340,7 @@ async fn test_body_brotli() {
|
|||
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.append_header((ACCEPT_ENCODING, "br"))
|
||||
.append_header((header::ACCEPT_ENCODING, "br"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -368,7 +348,7 @@ async fn test_body_brotli() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(brotli::decode(bytes), STR.as_bytes());
|
||||
assert_eq!(utils::brotli::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -383,7 +363,7 @@ async fn test_body_zstd() {
|
|||
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.append_header((ACCEPT_ENCODING, "zstd"))
|
||||
.append_header((header::ACCEPT_ENCODING, "zstd"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -391,7 +371,7 @@ async fn test_body_zstd() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(zstd::decode(bytes), STR.as_bytes());
|
||||
assert_eq!(utils::zstd::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -409,7 +389,7 @@ async fn test_body_zstd_streaming() {
|
|||
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.append_header((ACCEPT_ENCODING, "zstd"))
|
||||
.append_header((header::ACCEPT_ENCODING, "zstd"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
|
@ -417,7 +397,7 @@ async fn test_body_zstd_streaming() {
|
|||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
let bytes = res.body().await.unwrap();
|
||||
assert_eq!(zstd::decode(bytes), STR.as_bytes());
|
||||
assert_eq!(utils::zstd::decode(bytes), STR.as_bytes());
|
||||
|
||||
srv.stop().await;
|
||||
}
|
||||
|
@ -432,8 +412,8 @@ async fn test_zstd_encoding() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "zstd"))
|
||||
.send_body(zstd::encode(STR));
|
||||
.append_header((header::CONTENT_ENCODING, "zstd"))
|
||||
.send_body(utils::zstd::encode(STR));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -463,8 +443,8 @@ async fn test_zstd_encoding_large() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "zstd"))
|
||||
.send_body(zstd::encode(&data));
|
||||
.append_header((header::CONTENT_ENCODING, "zstd"))
|
||||
.send_body(utils::zstd::encode(&data));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -484,8 +464,8 @@ async fn test_encoding() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.insert_header((CONTENT_ENCODING, "gzip"))
|
||||
.send_body(gzip::encode(STR));
|
||||
.insert_header((header::CONTENT_ENCODING, "gzip"))
|
||||
.send_body(utils::gzip::encode(STR));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -505,8 +485,8 @@ async fn test_gzip_encoding() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "gzip"))
|
||||
.send_body(gzip::encode(STR));
|
||||
.append_header((header::CONTENT_ENCODING, "gzip"))
|
||||
.send_body(utils::gzip::encode(STR));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -527,8 +507,8 @@ async fn test_gzip_encoding_large() {
|
|||
|
||||
let req = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "gzip"))
|
||||
.send_body(gzip::encode(&data));
|
||||
.append_header((header::CONTENT_ENCODING, "gzip"))
|
||||
.send_body(utils::gzip::encode(&data));
|
||||
let mut res = req.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -554,8 +534,8 @@ async fn test_reading_gzip_encoding_large_random() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "gzip"))
|
||||
.send_body(gzip::encode(&data));
|
||||
.append_header((header::CONTENT_ENCODING, "gzip"))
|
||||
.send_body(utils::gzip::encode(&data));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -575,8 +555,8 @@ async fn test_reading_deflate_encoding() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "deflate"))
|
||||
.send_body(deflate::encode(STR));
|
||||
.append_header((header::CONTENT_ENCODING, "deflate"))
|
||||
.send_body(utils::deflate::encode(STR));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -597,8 +577,8 @@ async fn test_reading_deflate_encoding_large() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "deflate"))
|
||||
.send_body(deflate::encode(&data));
|
||||
.append_header((header::CONTENT_ENCODING, "deflate"))
|
||||
.send_body(utils::deflate::encode(&data));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -624,8 +604,8 @@ async fn test_reading_deflate_encoding_large_random() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "deflate"))
|
||||
.send_body(deflate::encode(&data));
|
||||
.append_header((header::CONTENT_ENCODING, "deflate"))
|
||||
.send_body(utils::deflate::encode(&data));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -646,8 +626,8 @@ async fn test_brotli_encoding() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "br"))
|
||||
.send_body(brotli::encode(STR));
|
||||
.append_header((header::CONTENT_ENCODING, "br"))
|
||||
.send_body(utils::brotli::encode(STR));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -677,8 +657,8 @@ async fn test_brotli_encoding_large() {
|
|||
|
||||
let request = srv
|
||||
.post("/")
|
||||
.append_header((CONTENT_ENCODING, "br"))
|
||||
.send_body(brotli::encode(&data));
|
||||
.append_header((header::CONTENT_ENCODING, "br"))
|
||||
.send_body(utils::brotli::encode(&data));
|
||||
let mut res = request.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
||||
|
@ -697,8 +677,9 @@ async fn test_brotli_encoding_large_openssl() {
|
|||
let srv =
|
||||
actix_test::start_with(actix_test::config().openssl(openssl_config()), move || {
|
||||
App::new().service(web::resource("/").route(web::to(|bytes: Bytes| {
|
||||
// echo decompressed request body back in response
|
||||
HttpResponse::Ok()
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
.insert_header(header::ContentEncoding::Identity)
|
||||
.body(bytes)
|
||||
})))
|
||||
});
|
||||
|
@ -706,7 +687,7 @@ async fn test_brotli_encoding_large_openssl() {
|
|||
let mut res = srv
|
||||
.post("/")
|
||||
.append_header((header::CONTENT_ENCODING, "br"))
|
||||
.send_body(brotli::encode(&data))
|
||||
.send_body(utils::brotli::encode(&data))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
@ -758,16 +739,20 @@ 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| {
|
||||
// echo decompressed request body back in response
|
||||
HttpResponse::Ok()
|
||||
.encode_with(ContentEncoding::Identity)
|
||||
.insert_header(header::ContentEncoding::Identity)
|
||||
.body(bytes)
|
||||
})))
|
||||
});
|
||||
|
||||
let req = srv
|
||||
.post("/")
|
||||
.insert_header((actix_web::http::header::CONTENT_ENCODING, "deflate"))
|
||||
.send_stream(TestBody::new(Bytes::from(deflate::encode(&data)), 1024));
|
||||
.insert_header((header::CONTENT_ENCODING, "deflate"))
|
||||
.send_stream(TestBody::new(
|
||||
Bytes::from(utils::deflate::encode(&data)),
|
||||
1024,
|
||||
));
|
||||
|
||||
let mut res = req.await.unwrap();
|
||||
assert_eq!(res.status(), StatusCode::OK);
|
||||
|
@ -931,14 +916,14 @@ async fn test_accept_encoding_no_match() {
|
|||
|
||||
let mut res = srv
|
||||
.get("/")
|
||||
.insert_header((ACCEPT_ENCODING, "xz, identity;q=0"))
|
||||
.insert_header((header::ACCEPT_ENCODING, "xz, identity;q=0"))
|
||||
.no_decompress()
|
||||
.send()
|
||||
.await
|
||||
.unwrap();
|
||||
|
||||
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();
|
||||
// body should contain the supported encodings
|
||||
|
|
76
tests/utils.rs
Normal file
76
tests/utils.rs
Normal file
|
@ -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 a new issue