@marcel91200 / caddy Mirror · read-only / commits / 9d54f655
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 14, 05:15 UTC

Take care of remaining TODOs in the browse responder

Matthew Holt committed May 21, 2019 at 13:03 UTC 9d54f655aa7698ce683786dfc31b6f11df3c89d2
5 files changed +31 -41
modules/caddyhttp/fileserver/browse.go
+24 -32
@@ -21,6 +21,16 @@ type Browse struct {
21 }
22
23 func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *http.Request) error {
24 + // navigation on the client-side gets messed up if the
25 + // URL doesn't end in a trailing slash because hrefs like
26 + // "/b/c" on a path like "/a" end up going to "/b/c" instead
27 + // of "/a/b/c" - so we have to redirect in this case
28 + if !strings.HasSuffix(r.URL.Path, "/") {
29 + r.URL.Path += "/"
30 + http.Redirect(w, r, r.URL.String(), http.StatusMovedPermanently)
31 + return nil
32 + }
33 +
34 dir, err := fsrv.openFile(dirPath, w)
35 if err != nil {
36 return err
@@ -29,7 +39,8 @@ func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *ht
39
40 repl := r.Context().Value(caddy2.ReplacerCtxKey).(caddy2.Replacer)
41
32 - listing, err := fsrv.loadDirectoryContents(dir, r.URL.Path, repl)
42 + // calling path.Clean here prevents weird breadcrumbs when URL paths are sketchy like /%2e%2e%2f
43 + listing, err := fsrv.loadDirectoryContents(dir, path.Clean(r.URL.Path), repl)
44 switch {
45 case os.IsPermission(err):
46 return caddyhttp.Error(http.StatusForbidden, err)
@@ -58,21 +69,6 @@ func (fsrv *FileServer) serveBrowse(dirPath string, w http.ResponseWriter, r *ht
69 buf.WriteTo(w)
70
71 return nil
61 -
62 - // TODO: Sigh... do we have to put this here?
63 - // // Browsing navigation gets messed up if browsing a directory
64 - // // that doesn't end in "/" (which it should, anyway)
65 - // u := *r.URL
66 - // if u.Path == "" {
67 - // u.Path = "/"
68 - // }
69 - // if u.Path[len(u.Path)-1] != '/' {
70 - // u.Path += "/"
71 - // http.Redirect(w, r, u.String(), http.StatusMovedPermanently)
72 - // return http.StatusMovedPermanently, nil
73 - // }
74 -
75 - // return b.ServeListing(w, r, requestedFilepath, bc)
72 }
73
74 func (fsrv *FileServer) loadDirectoryContents(dir *os.File, urlPath string, repl caddy2.Replacer) (browseListing, error) {
@@ -138,20 +134,16 @@ func isSymlink(f os.FileInfo) bool {
134 return f.Mode()&os.ModeSymlink != 0
135 }
136
141 -// isSymlinkTargetDir return true if f's symbolic link target
142 -// is a directory. Return false if not a symbolic link.
143 -// TODO: Re-implement
144 -func isSymlinkTargetDir(f os.FileInfo, urlPath string) bool {
145 - // if !isSymlink(f) {
146 - // return false
147 - // }
148 -
149 - // // TODO: Ensure path is sanitized
150 - // target:= path.Join(root, urlPath, f.Name()))
151 - // targetInfo, err := os.Stat(target)
152 - // if err != nil {
153 - // return false
154 - // }
155 - // return targetInfo.IsDir()
156 - return false
137 +// isSymlinkTargetDir returns true if f's symbolic link target
138 +// is a directory.
139 +func isSymlinkTargetDir(f os.FileInfo, root, urlPath string) bool {
140 + if !isSymlink(f) {
141 + return false
142 + }
143 + target := sanitizedPathJoin(root, path.Join(urlPath, f.Name()))
144 + targetInfo, err := os.Stat(target)
145 + if err != nil {
146 + return false
147 + }
148 + return targetInfo.IsDir()
149 }
modules/caddyhttp/fileserver/browselisting.go
+1 -1
@@ -28,7 +28,7 @@ func (fsrv *FileServer) directoryListing(files []os.FileInfo, canGoUp bool, urlP
28 continue
29 }
30
31 - isDir := f.IsDir() || isSymlinkTargetDir(f, urlPath)
31 + isDir := f.IsDir() || isSymlinkTargetDir(f, fsrv.Root, urlPath)
32
33 if isDir {
34 name += "/"
modules/caddyhttp/fileserver/matcher.go
+1 -3
@@ -3,7 +3,6 @@ package fileserver
3 import (
4 "net/http"
5 "os"
6 - "path/filepath"
6
7 "bitbucket.org/lightcodelabs/caddy2"
8 "bitbucket.org/lightcodelabs/caddy2/modules/caddyhttp"
@@ -33,8 +32,7 @@ type FileMatcher struct {
32
33 // Match matches the request r against m.
34 func (m FileMatcher) Match(r *http.Request) bool {
36 - // TODO: sanitize path
37 - fullPath := filepath.Join(m.Root, m.Path)
35 + fullPath := sanitizedPathJoin(m.Root, m.Path)
36 var match bool
37 if len(m.Flags) > 0 {
38 match = true
modules/caddyhttp/fileserver/staticfiles.go
+2 -2
@@ -30,9 +30,9 @@ type FileServer struct {
30 Root string `json:"root"` // default is current directory
31 Hide []string `json:"hide"`
32 IndexNames []string `json:"index_names"`
33 - Files []string `json:"files"` // all relative to the root; default is request URI path
34 - Rehandle bool `json:"rehandle"` // issue a rehandle (internal redirect) if request is rewritten
33 + Files []string `json:"files"` // all relative to the root; default is request URI path
34 SelectionPolicy string `json:"selection_policy"`
35 + Rehandle bool `json:"rehandle"` // issue a rehandle (internal redirect) if request is rewritten
36 Fallback caddyhttp.RouteList `json:"fallback"`
37 Browse *Browse `json:"browse"`
38 // TODO: Etag
modules/caddyhttp/matchers.go
+3 -3
@@ -26,7 +26,7 @@ type (
26 matchHeaderRE map[string]*matchRegexp
27 matchProtocol string
28 matchStarlarkExpr string
29 - matchTable string
29 + matchTable string // TODO: finish implementing
30 )
31
32 func init() {
@@ -245,14 +245,14 @@ func (mre *matchRegexp) match(input string, repl caddy2.Replacer, scope string)
245
246 // save all capture groups, first by index
247 for i, match := range matches {
248 - key := fmt.Sprintf("matchers.%s.%s.%d", scope, mre.Name, i)
248 + key := fmt.Sprintf("http.matchers.%s.%s.%d", scope, mre.Name, i)
249 repl.Set(key, match)
250 }
251
252 // then by name
253 for i, name := range mre.compiled.SubexpNames() {
254 if i != 0 && name != "" {
255 - key := fmt.Sprintf("matchers.%s.%s.%s", scope, mre.Name, name)
255 + key := fmt.Sprintf("http.matchers.%s.%s.%s", scope, mre.Name, name)
256 repl.Set(key, matches[i])
257 }
258 }