diff --git a/server/fileserver.go b/server/fileserver.go index 88df75641..2339db593 100644 --- a/server/fileserver.go +++ b/server/fileserver.go @@ -2,9 +2,11 @@ package server import ( "net/http" + "os" "path" "strings" + "github.com/mholt/caddy/middleware" "github.com/mholt/caddy/middleware/browse" ) @@ -16,7 +18,7 @@ import ( // Copyright 2009 The Go Authors. All rights reserved. // Use of this source code is governed by a BSD-style // 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} } @@ -24,30 +26,32 @@ type fileHandler struct { 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 if !strings.HasPrefix(upath, "/") { upath = "/" + 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. -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) if err != nil { - // TODO expose actual error? - http.NotFound(w, r) - return + if os.IsPermission(err) { + return http.StatusForbidden, err + } + return http.StatusNotFound, nil } defer f.Close() d, err1 := f.Stat() if err1 != nil { - // TODO expose actual error? - http.NotFound(w, r) - return + if os.IsPermission(err) { + return http.StatusForbidden, err + } + return http.StatusNotFound, nil } // 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 } // Still a directory? (we didn't find an index file) + // Return 404 to hide the fact that the folder exists if d.IsDir() { - http.NotFound(w, r) // 404 instead of 403 to hide the fact that the folder exists - return + return http.StatusNotFound, nil } + // 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) + + return http.StatusOK, nil }