mirror of
https://github.com/caddyserver/caddy.git
synced 2025-01-22 16:46:53 +01:00
staticfiles: Support pre-compressed zstd, make etag content-encoding-aware (#2626)
* Add support for precompressed zstd files (rfc8478) * Avoid the hash lookup for the file extension. * Only calculate Etag once
This commit is contained in:
parent
43458bda46
commit
120811e7f7
2 changed files with 27 additions and 20 deletions
|
@ -184,15 +184,14 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request) (int, err
|
||||||
return http.StatusNotFound, nil
|
return http.StatusNotFound, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
etag := calculateEtag(d)
|
etagInfo := d
|
||||||
|
|
||||||
// look for compressed versions of the file on disk, if the client supports that encoding
|
// look for compressed versions of the file on disk, if the client supports that encoding
|
||||||
for _, encoding := range staticEncodingPriority {
|
for _, encoding := range staticEncodingPriority {
|
||||||
// see if the client accepts a compressed encoding we offer
|
// see if the client accepts a compressed encoding we offer
|
||||||
acceptEncoding := strings.Split(r.Header.Get("Accept-Encoding"), ",")
|
acceptEncoding := strings.Split(r.Header.Get("Accept-Encoding"), ",")
|
||||||
accepted := false
|
accepted := false
|
||||||
for _, acc := range acceptEncoding {
|
for _, acc := range acceptEncoding {
|
||||||
if strings.TrimSpace(acc) == encoding {
|
if strings.TrimSpace(acc) == encoding.name {
|
||||||
accepted = true
|
accepted = true
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
@ -204,7 +203,7 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request) (int, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// see if the compressed version of this file exists
|
// see if the compressed version of this file exists
|
||||||
encodedFile, err := fs.Root.Open(reqPath + staticEncoding[encoding])
|
encodedFile, err := fs.Root.Open(reqPath + encoding.ext)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
@ -222,13 +221,15 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request) (int, err
|
||||||
|
|
||||||
// the encoded file is now what we're serving
|
// the encoded file is now what we're serving
|
||||||
f = encodedFile
|
f = encodedFile
|
||||||
etag = calculateEtag(encodedFileInfo)
|
etagInfo = encodedFileInfo
|
||||||
w.Header().Add("Vary", "Accept-Encoding")
|
w.Header().Add("Vary", "Accept-Encoding")
|
||||||
w.Header().Set("Content-Encoding", encoding)
|
w.Header().Set("Content-Encoding", encoding.name)
|
||||||
w.Header().Set("Content-Length", strconv.FormatInt(encodedFileInfo.Size(), 10))
|
w.Header().Set("Content-Length", strconv.FormatInt(encodedFileInfo.Size(), 10))
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
|
||||||
|
etag := calculateEtag(etagInfo)
|
||||||
|
|
||||||
// Set the ETag returned to the user-agent. Note that a conditional If-None-Match
|
// Set the ETag returned to the user-agent. Note that a conditional If-None-Match
|
||||||
// request is handled in http.ServeContent below, which checks against this ETag value.
|
// request is handled in http.ServeContent below, which checks against this ETag value.
|
||||||
w.Header().Set("ETag", etag)
|
w.Header().Set("ETag", etag)
|
||||||
|
@ -279,16 +280,9 @@ var DefaultIndexPages = []string{
|
||||||
"default.txt",
|
"default.txt",
|
||||||
}
|
}
|
||||||
|
|
||||||
// staticEncoding is a map of content-encoding to a file extension.
|
|
||||||
// If client accepts given encoding (via Accept-Encoding header) and compressed file with given extensions exists
|
|
||||||
// it will be served to the client instead of original one.
|
|
||||||
var staticEncoding = map[string]string{
|
|
||||||
"gzip": ".gz",
|
|
||||||
"br": ".br",
|
|
||||||
}
|
|
||||||
|
|
||||||
// staticEncodingPriority is a list of preferred static encodings (most efficient compression to least one).
|
// staticEncodingPriority is a list of preferred static encodings (most efficient compression to least one).
|
||||||
var staticEncodingPriority = []string{
|
var staticEncodingPriority = []struct{ name, ext string }{
|
||||||
"br",
|
{"zstd", ".zst"},
|
||||||
"gzip",
|
{"br", ".br"},
|
||||||
|
{"gzip", ".gz"},
|
||||||
}
|
}
|
||||||
|
|
|
@ -264,6 +264,17 @@ func TestServeHTTP(t *testing.T) {
|
||||||
expectedLocation: "https://foo/example.com/../",
|
expectedLocation: "https://foo/example.com/../",
|
||||||
expectedBodyContent: movedPermanently,
|
expectedBodyContent: movedPermanently,
|
||||||
},
|
},
|
||||||
|
// Test 30 - try to get pre- file.
|
||||||
|
{
|
||||||
|
url: "https://foo/sub/gzipped.html",
|
||||||
|
acceptEncoding: "zstd",
|
||||||
|
expectedStatus: http.StatusOK,
|
||||||
|
expectedBodyContent: testFiles[webrootSubGzippedHTMLZst],
|
||||||
|
expectedEtag: `"2n9ci"`,
|
||||||
|
expectedVary: "Accept-Encoding",
|
||||||
|
expectedEncoding: "zstd",
|
||||||
|
expectedContentLength: strconv.Itoa(len(testFiles[webrootSubGzippedHTMLZst])),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, test := range tests {
|
for i, test := range tests {
|
||||||
|
@ -546,6 +557,7 @@ var (
|
||||||
webrootSubGzippedHTML = filepath.Join(webrootName, "sub", "gzipped.html")
|
webrootSubGzippedHTML = filepath.Join(webrootName, "sub", "gzipped.html")
|
||||||
webrootSubGzippedHTMLGz = filepath.Join(webrootName, "sub", "gzipped.html.gz")
|
webrootSubGzippedHTMLGz = filepath.Join(webrootName, "sub", "gzipped.html.gz")
|
||||||
webrootSubGzippedHTMLBr = filepath.Join(webrootName, "sub", "gzipped.html.br")
|
webrootSubGzippedHTMLBr = filepath.Join(webrootName, "sub", "gzipped.html.br")
|
||||||
|
webrootSubGzippedHTMLZst = filepath.Join(webrootName, "sub", "gzipped.html.zst")
|
||||||
webrootSubBrotliHTML = filepath.Join(webrootName, "sub", "brotli.html")
|
webrootSubBrotliHTML = filepath.Join(webrootName, "sub", "brotli.html")
|
||||||
webrootSubBrotliHTMLGz = filepath.Join(webrootName, "sub", "brotli.html.gz")
|
webrootSubBrotliHTMLGz = filepath.Join(webrootName, "sub", "brotli.html.gz")
|
||||||
webrootSubBrotliHTMLBr = filepath.Join(webrootName, "sub", "brotli.html.br")
|
webrootSubBrotliHTMLBr = filepath.Join(webrootName, "sub", "brotli.html.br")
|
||||||
|
@ -573,9 +585,10 @@ var testFiles = map[string]string{
|
||||||
webrootSubGzippedHTML: "<h1>gzipped.html</h1>",
|
webrootSubGzippedHTML: "<h1>gzipped.html</h1>",
|
||||||
webrootSubGzippedHTMLGz: "1.gzipped.html.gz",
|
webrootSubGzippedHTMLGz: "1.gzipped.html.gz",
|
||||||
webrootSubGzippedHTMLBr: "2.gzipped.html.br",
|
webrootSubGzippedHTMLBr: "2.gzipped.html.br",
|
||||||
webrootSubBrotliHTML: "3.brotli.html",
|
webrootSubGzippedHTMLZst: "3.gzipped.html.zst",
|
||||||
webrootSubBrotliHTMLGz: "4.brotli.html.gz",
|
webrootSubBrotliHTML: "4.brotli.html",
|
||||||
webrootSubBrotliHTMLBr: "5.brotli.html.br",
|
webrootSubBrotliHTMLGz: "5.brotli.html.gz",
|
||||||
|
webrootSubBrotliHTMLBr: "6.brotli.html.br",
|
||||||
webrootSubBarDirWithIndexIndexHTML: "<h1>bar/dirwithindex/index.html</h1>",
|
webrootSubBarDirWithIndexIndexHTML: "<h1>bar/dirwithindex/index.html</h1>",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue