diff options
author | rouzier <[email protected]> | 2019-07-18 15:50:01 -0400 |
---|---|---|
committer | Matt Holt <[email protected]> | 2019-07-18 13:50:01 -0600 |
commit | 120811e7f728734c701dac4ec44a2934e2cca6fc (patch) | |
tree | 5ba7feb5cdb1dd55dd7fbb459b2128645f75e5f3 | |
parent | 43458bda468e69b21c29a0bad93064136759c898 (diff) | |
download | caddy-120811e7f728734c701dac4ec44a2934e2cca6fc.tar.gz caddy-120811e7f728734c701dac4ec44a2934e2cca6fc.zip |
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
-rw-r--r-- | caddyhttp/staticfiles/fileserver.go | 28 | ||||
-rw-r--r-- | caddyhttp/staticfiles/fileserver_test.go | 19 |
2 files changed, 27 insertions, 20 deletions
diff --git a/caddyhttp/staticfiles/fileserver.go b/caddyhttp/staticfiles/fileserver.go index 273498553..5690ceb93 100644 --- a/caddyhttp/staticfiles/fileserver.go +++ b/caddyhttp/staticfiles/fileserver.go @@ -184,15 +184,14 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request) (int, err return http.StatusNotFound, nil } - etag := calculateEtag(d) - + etagInfo := d // look for compressed versions of the file on disk, if the client supports that encoding for _, encoding := range staticEncodingPriority { // see if the client accepts a compressed encoding we offer acceptEncoding := strings.Split(r.Header.Get("Accept-Encoding"), ",") accepted := false for _, acc := range acceptEncoding { - if strings.TrimSpace(acc) == encoding { + if strings.TrimSpace(acc) == encoding.name { accepted = true 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 - encodedFile, err := fs.Root.Open(reqPath + staticEncoding[encoding]) + encodedFile, err := fs.Root.Open(reqPath + encoding.ext) if err != nil { 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 f = encodedFile - etag = calculateEtag(encodedFileInfo) + etagInfo = encodedFileInfo 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)) break } + etag := calculateEtag(etagInfo) + // 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. w.Header().Set("ETag", etag) @@ -279,16 +280,9 @@ var DefaultIndexPages = []string{ "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). -var staticEncodingPriority = []string{ - "br", - "gzip", +var staticEncodingPriority = []struct{ name, ext string }{ + {"zstd", ".zst"}, + {"br", ".br"}, + {"gzip", ".gz"}, } diff --git a/caddyhttp/staticfiles/fileserver_test.go b/caddyhttp/staticfiles/fileserver_test.go index 3eb10e3ad..a534d8c85 100644 --- a/caddyhttp/staticfiles/fileserver_test.go +++ b/caddyhttp/staticfiles/fileserver_test.go @@ -264,6 +264,17 @@ func TestServeHTTP(t *testing.T) { expectedLocation: "https://foo/example.com/../", 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 { @@ -546,6 +557,7 @@ var ( webrootSubGzippedHTML = filepath.Join(webrootName, "sub", "gzipped.html") webrootSubGzippedHTMLGz = filepath.Join(webrootName, "sub", "gzipped.html.gz") webrootSubGzippedHTMLBr = filepath.Join(webrootName, "sub", "gzipped.html.br") + webrootSubGzippedHTMLZst = filepath.Join(webrootName, "sub", "gzipped.html.zst") webrootSubBrotliHTML = filepath.Join(webrootName, "sub", "brotli.html") webrootSubBrotliHTMLGz = filepath.Join(webrootName, "sub", "brotli.html.gz") webrootSubBrotliHTMLBr = filepath.Join(webrootName, "sub", "brotli.html.br") @@ -573,9 +585,10 @@ var testFiles = map[string]string{ webrootSubGzippedHTML: "<h1>gzipped.html</h1>", webrootSubGzippedHTMLGz: "1.gzipped.html.gz", webrootSubGzippedHTMLBr: "2.gzipped.html.br", - webrootSubBrotliHTML: "3.brotli.html", - webrootSubBrotliHTMLGz: "4.brotli.html.gz", - webrootSubBrotliHTMLBr: "5.brotli.html.br", + webrootSubGzippedHTMLZst: "3.gzipped.html.zst", + webrootSubBrotliHTML: "4.brotli.html", + webrootSubBrotliHTMLGz: "5.brotli.html.gz", + webrootSubBrotliHTMLBr: "6.brotli.html.br", webrootSubBarDirWithIndexIndexHTML: "<h1>bar/dirwithindex/index.html</h1>", } |