staticfiles: add Content-Length header (closes #1479) (#1492)

* staticfiles: add Content-Length header (closes #1479)

* make linter happy, rename "Html" in identifiers to "HTML"
This commit is contained in:
Martin Bertschler 2017-03-12 23:41:49 +01:00 committed by Matt Holt
parent 5e48f0a412
commit 96bfb9f347
3 changed files with 78 additions and 62 deletions

View File

@ -12,6 +12,7 @@ import (
"strings"
"errors"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)

View File

@ -201,6 +201,7 @@ func (fs FileServer) serveFile(w http.ResponseWriter, r *http.Request, name stri
w.Header().Add("Vary", "Accept-Encoding")
w.Header().Set("Content-Encoding", encoding)
w.Header().Set("Content-Length", strconv.FormatInt(encodedFileInfo.Size(), 10))
defer f.Close()
break

View File

@ -8,6 +8,7 @@ import (
"net/url"
"os"
"path/filepath"
"strconv"
"strings"
"testing"
"time"
@ -23,16 +24,16 @@ var (
)
var (
webrootFile1Html = filepath.Join("webroot", "file1.html")
webrootDirFile2Html = filepath.Join("webroot", "dir", "file2.html")
webrootDirHiddenHtml = filepath.Join("webroot", "dir", "hidden.html")
webrootDirwithindexIndeHtml = filepath.Join("webroot", "dirwithindex", "index.html")
webrootSubGzippedHtml = filepath.Join("webroot", "sub", "gzipped.html")
webrootSubGzippedHtmlGz = filepath.Join("webroot", "sub", "gzipped.html.gz")
webrootSubGzippedHtmlBr = filepath.Join("webroot", "sub", "gzipped.html.br")
webrootSubBrotliHtml = filepath.Join("webroot", "sub", "brotli.html")
webrootSubBrotliHtmlGz = filepath.Join("webroot", "sub", "brotli.html.gz")
webrootSubBrotliHtmlBr = filepath.Join("webroot", "sub", "brotli.html.br")
webrootFile1HTML = filepath.Join("webroot", "file1.html")
webrootDirFile2HTML = filepath.Join("webroot", "dir", "file2.html")
webrootDirHiddenHTML = filepath.Join("webroot", "dir", "hidden.html")
webrootDirwithindexIndeHTML = filepath.Join("webroot", "dirwithindex", "index.html")
webrootSubGzippedHTML = filepath.Join("webroot", "sub", "gzipped.html")
webrootSubGzippedHTMLGz = filepath.Join("webroot", "sub", "gzipped.html.gz")
webrootSubGzippedHTMLBr = filepath.Join("webroot", "sub", "gzipped.html.br")
webrootSubBrotliHTML = filepath.Join("webroot", "sub", "brotli.html")
webrootSubBrotliHTMLGz = filepath.Join("webroot", "sub", "brotli.html.gz")
webrootSubBrotliHTMLBr = filepath.Join("webroot", "sub", "brotli.html.br")
webrootSubBarDirWithIndexIndexHTML = filepath.Join("webroot", "bar", "dirwithindex", "index.html")
)
@ -49,16 +50,16 @@ var (
// '------ hidden.html
var testFiles = map[string]string{
"unreachable.html": "<h1>must not leak</h1>",
webrootFile1Html: "<h1>file1.html</h1>",
webrootDirFile2Html: "<h1>dir/file2.html</h1>",
webrootDirwithindexIndeHtml: "<h1>dirwithindex/index.html</h1>",
webrootDirHiddenHtml: "<h1>dir/hidden.html</h1>",
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",
webrootFile1HTML: "<h1>file1.html</h1>",
webrootDirFile2HTML: "<h1>dir/file2.html</h1>",
webrootDirwithindexIndeHTML: "<h1>dirwithindex/index.html</h1>",
webrootDirHiddenHTML: "<h1>dir/hidden.html</h1>",
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",
webrootSubBarDirWithIndexIndexHTML: "<h1>bar/dirwithindex/index.html</h1>",
}
@ -76,15 +77,16 @@ func TestServeHTTP(t *testing.T) {
movedPermanently := "Moved Permanently"
tests := []struct {
url string
cleanedPath string
acceptEncoding string
expectedLocation string
expectedStatus int
expectedBodyContent string
expectedEtag string
expectedVary string
expectedEncoding string
url string
cleanedPath string
acceptEncoding string
expectedLocation string
expectedStatus int
expectedBodyContent string
expectedEtag string
expectedVary string
expectedEncoding string
expectedContentLength string
}{
// Test 0 - access without any path
{
@ -98,17 +100,19 @@ func TestServeHTTP(t *testing.T) {
},
// Test 2 - access existing file
{
url: "https://foo/file1.html",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootFile1Html],
expectedEtag: `"2n9cj"`,
url: "https://foo/file1.html",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootFile1HTML],
expectedEtag: `"2n9cj"`,
expectedContentLength: strconv.Itoa(len(testFiles[webrootFile1HTML])),
},
// Test 3 - access folder with index file with trailing slash
{
url: "https://foo/dirwithindex/",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootDirwithindexIndeHtml],
expectedEtag: `"2n9cw"`,
url: "https://foo/dirwithindex/",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootDirwithindexIndeHTML],
expectedEtag: `"2n9cw"`,
expectedContentLength: strconv.Itoa(len(testFiles[webrootDirwithindexIndeHTML])),
},
// Test 4 - access folder with index file without trailing slash
{
@ -148,10 +152,11 @@ func TestServeHTTP(t *testing.T) {
},
// Test 10 - access a index file directly
{
url: "https://foo/dirwithindex/index.html",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootDirwithindexIndeHtml],
expectedEtag: `"2n9cw"`,
url: "https://foo/dirwithindex/index.html",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootDirwithindexIndeHTML],
expectedEtag: `"2n9cw"`,
expectedContentLength: strconv.Itoa(len(testFiles[webrootDirwithindexIndeHTML])),
},
// Test 11 - send a request with query params
{
@ -193,33 +198,36 @@ func TestServeHTTP(t *testing.T) {
},
// Test 18 - try to get pre-gzipped file.
{
url: "https://foo/sub/gzipped.html",
acceptEncoding: "gzip",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootSubGzippedHtmlGz],
expectedEtag: `"2n9ch"`,
expectedVary: "Accept-Encoding",
expectedEncoding: "gzip",
url: "https://foo/sub/gzipped.html",
acceptEncoding: "gzip",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootSubGzippedHTMLGz],
expectedEtag: `"2n9ch"`,
expectedVary: "Accept-Encoding",
expectedEncoding: "gzip",
expectedContentLength: strconv.Itoa(len(testFiles[webrootSubGzippedHTMLGz])),
},
// Test 19 - try to get pre-brotli encoded file.
{
url: "https://foo/sub/brotli.html",
acceptEncoding: "br,gzip",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootSubBrotliHtmlBr],
expectedEtag: `"2n9cg"`,
expectedVary: "Accept-Encoding",
expectedEncoding: "br",
url: "https://foo/sub/brotli.html",
acceptEncoding: "br,gzip",
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootSubBrotliHTMLBr],
expectedEtag: `"2n9cg"`,
expectedVary: "Accept-Encoding",
expectedEncoding: "br",
expectedContentLength: strconv.Itoa(len(testFiles[webrootSubBrotliHTMLBr])),
},
// Test 20 - not allowed to get pre-brotli encoded file.
{
url: "https://foo/sub/brotli.html",
acceptEncoding: "nicebrew", // contains "br" substring but not "br"
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootSubBrotliHtml],
expectedEtag: `"2n9cd"`,
expectedVary: "",
expectedEncoding: "",
url: "https://foo/sub/brotli.html",
acceptEncoding: "nicebrew", // contains "br" substring but not "br"
expectedStatus: http.StatusOK,
expectedBodyContent: testFiles[webrootSubBrotliHTML],
expectedEtag: `"2n9cd"`,
expectedVary: "",
expectedEncoding: "",
expectedContentLength: strconv.Itoa(len(testFiles[webrootSubBrotliHTML])),
},
// Test 20 - treat existing file as a directory.
{
@ -280,6 +288,7 @@ func TestServeHTTP(t *testing.T) {
body := responseRecorder.Body.String()
vary := responseRecorder.Header().Get("Vary")
encoding := responseRecorder.Header().Get("Content-Encoding")
length := responseRecorder.Header().Get("Content-Length")
// check if error matches expectations
if err != nil {
@ -317,6 +326,11 @@ func TestServeHTTP(t *testing.T) {
t.Errorf("Test %d: Expected Location header %q, found %q", i, test.expectedLocation, l)
}
}
// check content length
if test.expectedContentLength != length {
t.Errorf("Test %d: Expected Content-Length header %s, found %s", i, test.expectedContentLength, length)
}
}
}