Commit 96bfb9f3 authored by Martin Bertschler's avatar Martin Bertschler Committed by Matt Holt

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

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

* make linter happy, rename "Html" in identifiers to "HTML"
parent 5e48f0a4
......@@ -12,6 +12,7 @@ import (
"strings"
"errors"
"github.com/mholt/caddy"
"github.com/mholt/caddy/caddyhttp/httpserver"
)
......
......@@ -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
......
......@@ -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)
}
}
}
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment