diff options
author | feistel <6742251-feistel@users.noreply.gitlab.com> | 2020-10-13 13:52:50 +0300 |
---|---|---|
committer | Vladimir Shushlin <vshushlin@gitlab.com> | 2020-10-13 13:52:50 +0300 |
commit | 77b42fad727a8d8166d8d9a3aa6951f530a664ea (patch) | |
tree | f6b7ca7cea056fabc00fa163decd685dbca3e172 /internal/serving/disk | |
parent | 5f461b42e39419795b2669278398a9a7c6ed2cd9 (diff) |
Ensure the content encoding is correct before reading the body
Avoid strange EOF error when the encoding is wrong
Diffstat (limited to 'internal/serving/disk')
-rw-r--r-- | internal/serving/disk/helpers.go | 61 | ||||
-rw-r--r-- | internal/serving/disk/reader.go | 4 |
2 files changed, 44 insertions, 21 deletions
diff --git a/internal/serving/disk/helpers.go b/internal/serving/disk/helpers.go index 1ff83683..5456724a 100644 --- a/internal/serving/disk/helpers.go +++ b/internal/serving/disk/helpers.go @@ -5,6 +5,7 @@ import ( "io" "mime" "net/http" + "os" "path/filepath" "strconv" "strings" @@ -13,6 +14,19 @@ import ( "gitlab.com/gitlab-org/gitlab-pages/internal/vfs" ) +var compressedEncodings = map[string]string{ + "br": ".br", + "gzip": ".gz", +} + +// Server side content encoding priority. +// Map iteration order is not deterministic in go, so we need this array to specify the priority +// when the client doesn't provide one +var compressedEncodingsPriority = []string{ + "br", + "gzip", +} + func endsWithSlash(path string) bool { return strings.HasSuffix(path, "/") } @@ -46,33 +60,42 @@ func (reader *Reader) detectContentType(ctx context.Context, root vfs.Root, path return contentType, nil } -func acceptsGZip(r *http.Request) bool { +func (reader *Reader) handleContentEncoding(ctx context.Context, w http.ResponseWriter, r *http.Request, root vfs.Root, fullPath string) string { + // don't accept range requests for compressed content if r.Header.Get("Range") != "" { - return false + return fullPath } - offers := []string{"gzip", "identity"} - acceptedEncoding := httputil.NegotiateContentEncoding(r, offers) - return acceptedEncoding == "gzip" -} + files := map[string]os.FileInfo{} -func (reader *Reader) handleGZip(ctx context.Context, w http.ResponseWriter, r *http.Request, root vfs.Root, fullPath string) string { - if !acceptsGZip(r) { - return fullPath - } + // finding compressed files + for encoding, extension := range compressedEncodings { + path := fullPath + extension - gzipPath := fullPath + ".gz" + // Ensure the file is not a symlink + if fi, err := root.Lstat(ctx, path); err == nil && fi.Mode().IsRegular() { + files[encoding] = fi + } + } - // Ensure the .gz file is not a symlink - fi, err := root.Lstat(ctx, gzipPath) - if err != nil || !fi.Mode().IsRegular() { - return fullPath + offers := make([]string, 0, len(files)+1) + for _, encoding := range compressedEncodingsPriority { + if _, ok := files[encoding]; ok { + offers = append(offers, encoding) + } } + offers = append(offers, "identity") - w.Header().Set("Content-Encoding", "gzip") + acceptedEncoding := httputil.NegotiateContentEncoding(r, offers) + + if fi, ok := files[acceptedEncoding]; ok { + w.Header().Set("Content-Encoding", acceptedEncoding) - // http.ServeContent doesn't set Content-Length if Content-Encoding is set - w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10)) + // http.ServeContent doesn't set Content-Length if Content-Encoding is set + w.Header().Set("Content-Length", strconv.FormatInt(fi.Size(), 10)) + + return fullPath + compressedEncodings[acceptedEncoding] + } - return gzipPath + return fullPath } diff --git a/internal/serving/disk/reader.go b/internal/serving/disk/reader.go index 6afe7947..e7f15a1e 100644 --- a/internal/serving/disk/reader.go +++ b/internal/serving/disk/reader.go @@ -169,7 +169,7 @@ func (reader *Reader) resolvePath(ctx context.Context, root vfs.Root, subPath .. } func (reader *Reader) serveFile(ctx context.Context, w http.ResponseWriter, r *http.Request, root vfs.Root, origPath string, accessControl bool) error { - fullPath := reader.handleGZip(ctx, w, r, root, origPath) + fullPath := reader.handleContentEncoding(ctx, w, r, root, origPath) file, err := root.Open(ctx, fullPath) if err != nil { @@ -212,7 +212,7 @@ func (reader *Reader) serveFile(ctx context.Context, w http.ResponseWriter, r *h } func (reader *Reader) serveCustomFile(ctx context.Context, w http.ResponseWriter, r *http.Request, code int, root vfs.Root, origPath string) error { - fullPath := reader.handleGZip(ctx, w, r, root, origPath) + fullPath := reader.handleContentEncoding(ctx, w, r, root, origPath) // Open and serve content of file file, err := root.Open(ctx, fullPath) |