2022-01-03 14:17:57 +01:00
|
|
|
use actix_http::ContentEncoding;
|
|
|
|
use actix_web::{
|
|
|
|
http::{header, StatusCode},
|
|
|
|
middleware::Compress,
|
|
|
|
web, App, HttpResponse,
|
|
|
|
};
|
|
|
|
use bytes::Bytes;
|
|
|
|
|
2022-01-03 19:46:04 +01:00
|
|
|
mod utils;
|
2022-01-03 14:17:57 +01:00
|
|
|
|
|
|
|
static LOREM: &[u8] = include_bytes!("fixtures/lorem.txt");
|
|
|
|
static LOREM_GZIP: &[u8] = include_bytes!("fixtures/lorem.txt.gz");
|
|
|
|
static LOREM_BR: &[u8] = include_bytes!("fixtures/lorem.txt.br");
|
|
|
|
static LOREM_ZSTD: &[u8] = include_bytes!("fixtures/lorem.txt.zst");
|
|
|
|
static LOREM_XZ: &[u8] = include_bytes!("fixtures/lorem.txt.xz");
|
|
|
|
|
|
|
|
macro_rules! test_server {
|
|
|
|
() => {
|
|
|
|
actix_test::start(|| {
|
|
|
|
App::new()
|
|
|
|
.wrap(Compress::default())
|
2022-01-24 12:56:01 +01:00
|
|
|
.route(
|
|
|
|
"/static",
|
|
|
|
web::to(|| async { HttpResponse::Ok().body(LOREM) }),
|
|
|
|
)
|
2022-01-03 14:17:57 +01:00
|
|
|
.route(
|
|
|
|
"/static-gzip",
|
2022-01-24 12:56:01 +01:00
|
|
|
web::to(|| async {
|
2022-01-03 14:17:57 +01:00
|
|
|
HttpResponse::Ok()
|
|
|
|
// signal to compressor that content should not be altered
|
|
|
|
// signal to client that content is encoded
|
|
|
|
.insert_header(ContentEncoding::Gzip)
|
|
|
|
.body(LOREM_GZIP)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.route(
|
|
|
|
"/static-br",
|
2022-01-24 12:56:01 +01:00
|
|
|
web::to(|| async {
|
2022-01-03 14:17:57 +01:00
|
|
|
HttpResponse::Ok()
|
|
|
|
// signal to compressor that content should not be altered
|
|
|
|
// signal to client that content is encoded
|
|
|
|
.insert_header(ContentEncoding::Brotli)
|
|
|
|
.body(LOREM_BR)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.route(
|
|
|
|
"/static-zstd",
|
2022-01-24 12:56:01 +01:00
|
|
|
web::to(|| async {
|
2022-01-03 14:17:57 +01:00
|
|
|
HttpResponse::Ok()
|
|
|
|
// signal to compressor that content should not be altered
|
|
|
|
// signal to client that content is encoded
|
|
|
|
.insert_header(ContentEncoding::Zstd)
|
|
|
|
.body(LOREM_ZSTD)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.route(
|
|
|
|
"/static-xz",
|
2022-01-24 12:56:01 +01:00
|
|
|
web::to(|| async {
|
2022-01-03 14:17:57 +01:00
|
|
|
HttpResponse::Ok()
|
|
|
|
// signal to compressor that content should not be altered
|
|
|
|
// signal to client that content is encoded as 7zip
|
|
|
|
.insert_header((header::CONTENT_ENCODING, "xz"))
|
|
|
|
.body(LOREM_XZ)
|
|
|
|
}),
|
|
|
|
)
|
|
|
|
.route(
|
|
|
|
"/echo",
|
2022-01-24 12:56:01 +01:00
|
|
|
web::to(|body: Bytes| async move { HttpResponse::Ok().body(body) }),
|
2022-01-03 14:17:57 +01:00
|
|
|
)
|
|
|
|
})
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn negotiate_encoding_identity() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static")
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "identity"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING), None);
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn negotiate_encoding_gzip() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static")
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "gzip,br,zstd"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "gzip");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM));
|
|
|
|
|
|
|
|
let mut res = srv
|
|
|
|
.post("/static")
|
|
|
|
.no_decompress()
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "gzip,br,zstd"))
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let bytes = res.body().await.unwrap();
|
2022-01-03 19:46:04 +01:00
|
|
|
assert_eq!(utils::gzip::decode(bytes), LOREM);
|
2022-01-03 14:17:57 +01:00
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn negotiate_encoding_br() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static")
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "br,zstd,gzip"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "br");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM));
|
|
|
|
|
|
|
|
let mut res = srv
|
|
|
|
.post("/static")
|
|
|
|
.no_decompress()
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "br,zstd,gzip"))
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let bytes = res.body().await.unwrap();
|
2022-01-03 19:46:04 +01:00
|
|
|
assert_eq!(utils::brotli::decode(bytes), LOREM);
|
2022-01-03 14:17:57 +01:00
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn negotiate_encoding_zstd() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static")
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "zstd,gzip,br"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "zstd");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM));
|
|
|
|
|
|
|
|
let mut res = srv
|
|
|
|
.post("/static")
|
|
|
|
.no_decompress()
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "zstd,gzip,br"))
|
|
|
|
.send()
|
|
|
|
.await
|
|
|
|
.unwrap();
|
|
|
|
let bytes = res.body().await.unwrap();
|
2022-01-03 19:46:04 +01:00
|
|
|
assert_eq!(utils::zstd::decode(bytes), LOREM);
|
2022-01-03 14:17:57 +01:00
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(all(
|
|
|
|
feature = "compress-brotli",
|
|
|
|
feature = "compress-gzip",
|
|
|
|
feature = "compress-zstd",
|
|
|
|
))]
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn client_encoding_prefers_brotli() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv.post("/static").send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "br");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn gzip_no_decompress() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static-gzip")
|
|
|
|
// don't decompress response body
|
|
|
|
.no_decompress()
|
|
|
|
// signal that we want a compressed body
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "gzip,br,zstd"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "gzip");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM_GZIP));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn manual_custom_coding() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static-xz")
|
|
|
|
// don't decompress response body
|
|
|
|
.no_decompress()
|
|
|
|
// signal that we want a compressed body
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "xz"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "xz");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM_XZ));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn deny_identity_coding() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static")
|
|
|
|
// signal that we want a compressed body
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "br, identity;q=0"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "br");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn deny_identity_coding_no_decompress() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static-br")
|
|
|
|
// don't decompress response body
|
|
|
|
.no_decompress()
|
|
|
|
// signal that we want a compressed body
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "br, identity;q=0"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "br");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM_BR));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: fix test
|
|
|
|
// currently fails because negotiation doesn't consider unknown encoding types
|
|
|
|
#[ignore]
|
|
|
|
#[actix_rt::test]
|
|
|
|
async fn deny_identity_for_manual_coding() {
|
|
|
|
let srv = test_server!();
|
|
|
|
|
|
|
|
let req = srv
|
|
|
|
.post("/static-xz")
|
|
|
|
// don't decompress response body
|
|
|
|
.no_decompress()
|
|
|
|
// signal that we want a compressed body
|
|
|
|
.insert_header((header::ACCEPT_ENCODING, "xz, identity;q=0"))
|
|
|
|
.send();
|
|
|
|
|
|
|
|
let mut res = req.await.unwrap();
|
|
|
|
assert_eq!(res.status(), StatusCode::OK);
|
|
|
|
assert_eq!(res.headers().get(header::CONTENT_ENCODING).unwrap(), "xz");
|
|
|
|
|
|
|
|
let bytes = res.body().await.unwrap();
|
|
|
|
assert_eq!(bytes, Bytes::from_static(LOREM_XZ));
|
|
|
|
|
|
|
|
srv.stop().await;
|
|
|
|
}
|