Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS
Mirrored from https://github.com/Slazee/caddy.git
Synced Nov 13, 01:45 UTC
fileserver: Use EscapedPath for browse (#5534)
* fileserver: Use EscapedPath for browse Fix #5143 * Fixes if filter element is not present * Remove extraneous line
Matt Holt committed
May 15, 2023 at 10:48 UTC
52d7335c2b1b8424e8971a9b03f51a5f36583535
3 files changed
+47
-7
modules/caddyhttp/fileserver/browse.go
+2
-2
@@ -82,8 +82,8 @@ func (fsrv *FileServer) serveBrowse(root, dirPath string, w http.ResponseWriter,
82
83
repl := r.Context().Value(caddy.ReplacerCtxKey).(*caddy.Replacer)
84
85
- // calling path.Clean here prevents weird breadcrumbs when URL paths are sketchy like /%2e%2e%2f
86
- listing, err := fsrv.loadDirectoryContents(r.Context(), dir.(fs.ReadDirFile), root, path.Clean(r.URL.Path), repl)
85
+ // TODO: not entirely sure if path.Clean() is necessary here but seems like a safe plan (i.e. /%2e%2e%2f) - someone could verify this
86
+ listing, err := fsrv.loadDirectoryContents(r.Context(), dir.(fs.ReadDirFile), root, path.Clean(r.URL.EscapedPath()), repl)
87
switch {
88
case os.IsPermission(err):
89
return caddyhttp.Error(http.StatusForbidden, err)
modules/caddyhttp/fileserver/browse.html
+3
-2
@@ -850,11 +850,11 @@ footer {
850
851
<script>
852
const filterEl = document.getElementById('filter');
853
- filterEl.focus({ preventScroll: true });
853
+ filterEl?.focus({ preventScroll: true });
854
855
function initPage() {
856
// populate and evaluate filter
857
- if (!filterEl.value) {
857
+ if (!filterEl?.value) {
858
const filterParam = new URL(window.location.href).searchParams.get('filter');
859
if (filterParam) {
860
filterEl.value = filterParam;
@@ -874,6 +874,7 @@ footer {
874
}
875
876
function filter() {
877
+ if (!filterEl) return;
878
const q = filterEl.value.trim().toLowerCase();
879
document.querySelectorAll('tr.file').forEach(function(el) {
880
if (!q) {
modules/caddyhttp/fileserver/browsetplcontext_test.go
+42
-3
@@ -25,6 +25,45 @@ func TestBreadcrumbs(t *testing.T) {
25
}{
26
{"", []crumb{}},
27
{"/", []crumb{{Text: "/"}}},
28
+ {"/foo/", []crumb{
29
+ {Link: "../", Text: "/"},
30
+ {Link: "", Text: "foo"},
31
+ }},
32
+ {"/foo/bar/", []crumb{
33
+ {Link: "../../", Text: "/"},
34
+ {Link: "../", Text: "foo"},
35
+ {Link: "", Text: "bar"},
36
+ }},
37
+ {"/foo bar/", []crumb{
38
+ {Link: "../", Text: "/"},
39
+ {Link: "", Text: "foo bar"},
40
+ }},
41
+ {"/foo bar/baz/", []crumb{
42
+ {Link: "../../", Text: "/"},
43
+ {Link: "../", Text: "foo bar"},
44
+ {Link: "", Text: "baz"},
45
+ }},
46
+ {"/100%25 test coverage/is a lie/", []crumb{
47
+ {Link: "../../", Text: "/"},
48
+ {Link: "../", Text: "100% test coverage"},
49
+ {Link: "", Text: "is a lie"},
50
+ }},
51
+ {"/AC%2FDC/", []crumb{
52
+ {Link: "../", Text: "/"},
53
+ {Link: "", Text: "AC/DC"},
54
+ }},
55
+ {"/foo/%2e%2e%2f/bar", []crumb{
56
+ {Link: "../../../", Text: "/"},
57
+ {Link: "../../", Text: "foo"},
58
+ {Link: "../", Text: "../"},
59
+ {Link: "", Text: "bar"},
60
+ }},
61
+ {"/foo/../bar", []crumb{
62
+ {Link: "../../../", Text: "/"},
63
+ {Link: "../../", Text: "foo"},
64
+ {Link: "../", Text: ".."},
65
+ {Link: "", Text: "bar"},
66
+ }},
67
{"foo/bar/baz", []crumb{
68
{Link: "../../", Text: "foo"},
69
{Link: "../", Text: "bar"},
@@ -51,16 +90,16 @@ func TestBreadcrumbs(t *testing.T) {
90
}},
91
}
92
54
- for _, d := range testdata {
93
+ for testNum, d := range testdata {
94
l := browseTemplateContext{Path: d.path}
95
actual := l.Breadcrumbs()
96
if len(actual) != len(d.expected) {
58
- t.Errorf("wrong size output, got %d elements but expected %d", len(actual), len(d.expected))
97
+ t.Errorf("Test %d: Got %d components but expected %d; got: %+v", testNum, len(actual), len(d.expected), actual)
98
continue
99
}
100
for i, c := range actual {
101
if c != d.expected[i] {
63
- t.Errorf("got %#v but expected %#v at index %d", c, d.expected[i], i)
102
+ t.Errorf("Test %d crumb %d: got %#v but expected %#v at index %d", testNum, i, c, d.expected[i], i)
103
}
104
}
105
}