Commit 21b2e5a0 authored by Matthew Holt's avatar Matthew Holt

Refactored file server to return errors

parent 878ae7ea
...@@ -2,9 +2,11 @@ package server ...@@ -2,9 +2,11 @@ package server
import ( import (
"net/http" "net/http"
"os"
"path" "path"
"strings" "strings"
"github.com/mholt/caddy/middleware"
"github.com/mholt/caddy/middleware/browse" "github.com/mholt/caddy/middleware/browse"
) )
...@@ -16,7 +18,7 @@ import ( ...@@ -16,7 +18,7 @@ import (
// Copyright 2009 The Go Authors. All rights reserved. // Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
func FileServer(root http.FileSystem) http.Handler { func FileServer(root http.FileSystem) middleware.Handler {
return &fileHandler{root} return &fileHandler{root}
} }
...@@ -24,30 +26,32 @@ type fileHandler struct { ...@@ -24,30 +26,32 @@ type fileHandler struct {
root http.FileSystem root http.FileSystem
} }
func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { func (f *fileHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) (int, error) {
upath := r.URL.Path upath := r.URL.Path
if !strings.HasPrefix(upath, "/") { if !strings.HasPrefix(upath, "/") {
upath = "/" + upath upath = "/" + upath
r.URL.Path = upath r.URL.Path = upath
} }
serveFile(w, r, f.root, path.Clean(upath), true) return serveFile(w, r, f.root, path.Clean(upath))
} }
// name is '/'-separated, not filepath.Separator. // name is '/'-separated, not filepath.Separator.
func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string, redirect bool) { func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name string) (int, error) {
f, err := fs.Open(name) f, err := fs.Open(name)
if err != nil { if err != nil {
// TODO expose actual error? if os.IsPermission(err) {
http.NotFound(w, r) return http.StatusForbidden, err
return }
return http.StatusNotFound, nil
} }
defer f.Close() defer f.Close()
d, err1 := f.Stat() d, err1 := f.Stat()
if err1 != nil { if err1 != nil {
// TODO expose actual error? if os.IsPermission(err) {
http.NotFound(w, r) return http.StatusForbidden, err
return }
return http.StatusNotFound, nil
} }
// use contents of an index file, if present, for directory // use contents of an index file, if present, for directory
...@@ -69,10 +73,14 @@ func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name ...@@ -69,10 +73,14 @@ func serveFile(w http.ResponseWriter, r *http.Request, fs http.FileSystem, name
} }
// Still a directory? (we didn't find an index file) // Still a directory? (we didn't find an index file)
// Return 404 to hide the fact that the folder exists
if d.IsDir() { if d.IsDir() {
http.NotFound(w, r) // 404 instead of 403 to hide the fact that the folder exists return http.StatusNotFound, nil
return
} }
// Note: Errors generated by ServeContent are written immediately
// to the response. This usually only happens if seeking fails (rare).
http.ServeContent(w, r, d.Name(), d.ModTime(), f) http.ServeContent(w, r, d.Name(), d.ModTime(), f)
return http.StatusOK, nil
} }
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