summaryrefslogtreecommitdiff
path: root/modules/caddyhttp
diff options
context:
space:
mode:
authorMatthew Holt <mholt@users.noreply.github.com>2019-11-15 17:32:13 -0700
committerMatthew Holt <mholt@users.noreply.github.com>2019-11-15 17:32:13 -0700
commitb43e986a526c9de83c04c29bc530f1d711a40997 (patch)
tree26c4e943c1423a0f98b4de9fad655602e7c567b7 /modules/caddyhttp
parent1228dd7d93b59409fd844400b9c114be267df3a3 (diff)
file_server: Optional pass_thru mode
If enabled, will call the next handler in the chain instead of returning a 404.
Diffstat (limited to 'modules/caddyhttp')
-rw-r--r--modules/caddyhttp/fileserver/browse.go4
-rw-r--r--modules/caddyhttp/fileserver/staticfiles.go27
2 files changed, 24 insertions, 7 deletions
diff --git a/modules/caddyhttp/fileserver/browse.go b/modules/caddyhttp/fileserver/browse.go
index 91ebcd5..48f2cc7 100644
--- a/modules/caddyhttp/fileserver/browse.go
+++ b/modules/caddyhttp/fileserver/browse.go
@@ -34,7 +34,7 @@ type Browse struct {
template *template.Template
}
-func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *http.Request) error {
+func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
// navigation on the client-side gets messed up if the
// URL doesn't end in a trailing slash because hrefs like
// "/b/c" on a path like "/a" end up going to "/b/c" instead
@@ -59,7 +59,7 @@ func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *ht
case os.IsPermission(err):
return caddyhttp.Error(http.StatusForbidden, err)
case os.IsNotExist(err):
- return caddyhttp.Error(http.StatusNotFound, err)
+ return fsrv.notFound(w, r, next)
case err != nil:
return caddyhttp.Error(http.StatusInternalServerError, err)
}
diff --git a/modules/caddyhttp/fileserver/staticfiles.go b/modules/caddyhttp/fileserver/staticfiles.go
index 26c0efe..d1791db 100644
--- a/modules/caddyhttp/fileserver/staticfiles.go
+++ b/modules/caddyhttp/fileserver/staticfiles.go
@@ -47,6 +47,7 @@ type FileServer struct {
IndexNames []string `json:"index_names,omitempty"`
Browse *Browse `json:"browse,omitempty"`
CanonicalURIs *bool `json:"canonical_uris,omitempty"`
+ PassThru bool `json:"pass_thru,omitempty"` // if 404, call next handler instead
}
// CaddyModule returns the Caddy module information.
@@ -87,7 +88,7 @@ func (fsrv *FileServer) Provision(ctx caddy.Context) error {
return nil
}
-func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, _ caddyhttp.Handler) error {
+func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
repl := r.Context().Value(caddy.ReplacerCtxKey).(caddy.Replacer)
filesToHide := fsrv.transformHidePaths(repl)
@@ -101,7 +102,7 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, _ cadd
if err != nil {
err = mapDirOpenError(err, filename)
if os.IsNotExist(err) {
- return caddyhttp.Error(http.StatusNotFound, err)
+ return fsrv.notFound(w, r, next)
} else if os.IsPermission(err) {
return caddyhttp.Error(http.StatusForbidden, err)
}
@@ -144,17 +145,20 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, _ cadd
// to browse or return an error
if info.IsDir() {
if fsrv.Browse != nil && !fileHidden(filename, filesToHide) {
- return fsrv.serveBrowse(filename, w, r)
+ return fsrv.serveBrowse(filename, w, r, next)
}
- return caddyhttp.Error(http.StatusNotFound, nil)
+ return fsrv.notFound(w, r, next)
}
+ // TODO: maybe there should be a way to serve the next handler
+ // instead of returning 404 if a file is not found?
+
// TODO: content negotiation (brotli sidecar files, etc...)
// one last check to ensure the file isn't hidden (we might
// have changed the filename from when we last checked)
if fileHidden(filename, filesToHide) {
- return caddyhttp.Error(http.StatusNotFound, nil)
+ return fsrv.notFound(w, r, next)
}
// if URL canonicalization is enabled, we need to enforce trailing
@@ -172,6 +176,10 @@ func (fsrv *FileServer) ServeHTTP(w http.ResponseWriter, r *http.Request, _ cadd
// open the file
file, err := fsrv.openFile(filename, w)
if err != nil {
+ if herr, ok := err.(caddyhttp.HandlerError); ok &&
+ herr.StatusCode == http.StatusNotFound {
+ return fsrv.notFound(w, r, next)
+ }
return err // error is already structured
}
defer file.Close()
@@ -336,6 +344,15 @@ func fileHidden(filename string, hide []string) bool {
return false
}
+// notFound returns a 404 error or, if pass-thru is enabled,
+// it calls the next handler in the chain.
+func (fsrv *FileServer) notFound(w http.ResponseWriter, r *http.Request, next caddyhttp.Handler) error {
+ if fsrv.PassThru {
+ return next.ServeHTTP(w, r)
+ }
+ return caddyhttp.Error(http.StatusNotFound, nil)
+}
+
// calculateEtag produces a strong etag by default, although, for
// efficiency reasons, it does not actually consume the contents
// of the file to make a hash of all the bytes. ¯\_(ツ)_/¯