Skip to content

Commit bf44cd4

Browse files
authored
Merge pull request #49 from stephank/feat/zstd
Add support for zstd
2 parents 29ea42e + 963eab5 commit bf44cd4

File tree

2 files changed

+45
-2
lines changed

2 files changed

+45
-2
lines changed

src/resolve.rs

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ pub struct ResolvedFile<F = File> {
2424
pub handle: F,
2525
/// The resolved and sanitized path to the file.
2626
/// For directory indexes, this includes `index.html`.
27-
/// For pre-encoded files, this will include the compressed extension. (`.gz` or `.br`)
27+
/// For pre-encoded files, this will include the compressed extension. (`.gz`, `.br`, or `.zst`)
2828
pub path: PathBuf,
2929
/// Size in bytes.
3030
pub size: u64,
@@ -68,7 +68,7 @@ pub struct Resolver<O = TokioFileOpener> {
6868
/// Encodings the client is allowed to request with `Accept-Encoding`.
6969
///
7070
/// This only supports pre-encoded files, that exist adjacent to the original file, but with an
71-
/// additional `.br` or `.gz` suffix (after the original extension).
71+
/// additional `.gz`, `.br`, or `.zst` suffix (after the original extension).
7272
///
7373
/// Typically initialized with `AcceptEncoding::all()` or `AcceptEncoding::none()`.
7474
pub allowed_encodings: AcceptEncoding,
@@ -288,6 +288,18 @@ impl<O: FileOpener> Resolver<O> {
288288
.map(|mimetype| set_charset(mimetype).to_string());
289289

290290
// Resolve pre-encoded files.
291+
if accept_encoding.zstd {
292+
let mut zstd_path = path.clone().into_os_string();
293+
zstd_path.push(".zst");
294+
if let Ok(file) = self.opener.open(zstd_path.as_ref()).await {
295+
return Ok(ResolveResult::Found(ResolvedFile::new(
296+
file,
297+
zstd_path.into(),
298+
mime,
299+
Some(Encoding::Zstd),
300+
)));
301+
}
302+
}
291303
if accept_encoding.br {
292304
let mut br_path = path.clone().into_os_string();
293305
br_path.push(".br");
@@ -337,6 +349,8 @@ pub enum Encoding {
337349
Gzip,
338350
/// Response body is encoded with brotli.
339351
Br,
352+
/// Response body is encoded with zstd.
353+
Zstd,
340354
}
341355

342356
impl Encoding {
@@ -345,6 +359,7 @@ impl Encoding {
345359
HeaderValue::from_static(match self {
346360
Encoding::Gzip => "gzip",
347361
Encoding::Br => "br",
362+
Encoding::Zstd => "zstd",
348363
})
349364
}
350365
}
@@ -356,6 +371,8 @@ pub struct AcceptEncoding {
356371
pub gzip: bool,
357372
/// Look for `.br` files.
358373
pub br: bool,
374+
/// Look for `.zst` files.
375+
pub zstd: bool,
359376
}
360377

361378
impl AcceptEncoding {
@@ -364,6 +381,7 @@ impl AcceptEncoding {
364381
Self {
365382
gzip: true,
366383
br: true,
384+
zstd: true,
367385
}
368386
}
369387

@@ -372,6 +390,7 @@ impl AcceptEncoding {
372390
Self {
373391
gzip: false,
374392
br: false,
393+
zstd: false,
375394
}
376395
}
377396

@@ -384,6 +403,7 @@ impl AcceptEncoding {
384403
match enc.split(';').next().unwrap().trim() {
385404
"gzip" => res.gzip = true,
386405
"br" => res.br = true,
406+
"zstd" => res.zstd = true,
387407
_ => {}
388408
}
389409
}
@@ -398,6 +418,7 @@ impl BitAnd for AcceptEncoding {
398418
Self {
399419
gzip: self.gzip && rhs.gzip,
400420
br: self.br && rhs.br,
421+
zstd: self.zstd && rhs.zstd,
401422
}
402423
}
403424
}

tests/static.rs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -495,6 +495,28 @@ async fn serves_br() {
495495
assert_eq!(read_body(res).await, "fake brotli compression");
496496
}
497497

498+
#[tokio::test]
499+
async fn serves_zstd() {
500+
let harness = Harness::new(vec![
501+
("file1.html", "this is file1"),
502+
("file1.html.br", "fake brotli compression"),
503+
("file1.html.gz", "fake gzip compression"),
504+
("file1.html.zst", "fake zstd compression"),
505+
]);
506+
let req = Request::builder()
507+
.uri("/file1.html")
508+
.header(header::ACCEPT_ENCODING, "zstd;q=1.0, br;q=0.8, gzip;q=0.5")
509+
.body(())
510+
.expect("unable to build request");
511+
512+
let res = harness.request(req).await.unwrap();
513+
assert_eq!(
514+
res.headers().get(header::CONTENT_ENCODING),
515+
Some(&Encoding::Zstd.to_header_value())
516+
);
517+
assert_eq!(read_body(res).await, "fake zstd compression");
518+
}
519+
498520
#[tokio::test]
499521
async fn test_memory_fs() {
500522
let dir = Harness::create_temp_dir(vec![

0 commit comments

Comments
 (0)