@marcel91200 / caddy Mirror · read-only / commits / 45132c5b
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 12, 14:30 UTC

caddyhttp: Add plaintext response to `file_server browse` (#6093)

* Added plaintext support to file_server browser This commit is twofold: First it adds a new optional field, `return_type`, to `browser` for setting the default format of the returned index (html, json or plaintext). This is used when the `Accept` header is set to `/*`. Second, it adds a preliminary `text/plain` support to the `file_server` browser that returns a text representation of the file system, when an `Accept: text/plain` header is present, with the behavior discussed above. * Added more details and better formatting to plaintext browser * Replaced returnType conditions with a switch statement * Simplify --------- Co-authored-by: Matt Holt <mholt@users.noreply.github.com>

kylosus committed Apr 1, 2024 at 21:12 UTC 45132c5b24b411afbf90e8f897a1598d4eca790f
2 files changed +40 -8
modules/caddyhttp/fileserver/browse.go
+33 -3
@@ -28,6 +28,7 @@ import (
28 "path"
29 "strings"
30 "sync"
31 + "text/tabwriter"
32 "text/template"
33
34 "go.uber.org/zap"
@@ -111,13 +112,42 @@ func (fsrv *FileServer) serveBrowse(fileSystem fs.FS, root, dirPath string, w ht
112
113 acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ","))
114
114 - // write response as either JSON or HTML
115 - if strings.Contains(acceptHeader, "application/json") {
115 + switch {
116 + case strings.Contains(acceptHeader, "application/json"):
117 if err := json.NewEncoder(buf).Encode(listing.Items); err != nil {
118 return caddyhttp.Error(http.StatusInternalServerError, err)
119 }
120 w.Header().Set("Content-Type", "application/json; charset=utf-8")
120 - } else {
121 +
122 + case strings.Contains(acceptHeader, "text/plain"):
123 + writer := tabwriter.NewWriter(buf, 0, 8, 1, '\t', tabwriter.AlignRight)
124 +
125 + // Header on top
126 + if _, err := fmt.Fprintln(writer, "Name\tSize\tModified"); err != nil {
127 + return caddyhttp.Error(http.StatusInternalServerError, err)
128 + }
129 +
130 + // Lines to separate the header
131 + if _, err := fmt.Fprintln(writer, "----\t----\t--------"); err != nil {
132 + return caddyhttp.Error(http.StatusInternalServerError, err)
133 + }
134 +
135 + // Actual files
136 + for _, item := range listing.Items {
137 + if _, err := fmt.Fprintf(writer, "%s\t%s\t%s\n",
138 + item.Name, item.HumanSize(), item.HumanModTime("January 2, 2006 at 15:04:05"),
139 + ); err != nil {
140 + return caddyhttp.Error(http.StatusInternalServerError, err)
141 + }
142 + }
143 +
144 + if err := writer.Flush(); err != nil {
145 + return caddyhttp.Error(http.StatusInternalServerError, err)
146 + }
147 +
148 + w.Header().Set("Content-Type", "text/plain; charset=utf-8")
149 +
150 + default:
151 var fs http.FileSystem
152 if fsrv.Root != "" {
153 fs = http.Dir(repl.ReplaceAll(fsrv.Root, "."))
modules/caddyhttp/fileserver/caddyfile.go
+7 -5
@@ -113,13 +113,15 @@ func (fsrv *FileServer) UnmarshalCaddyfile(d *caddyfile.Dispenser) error {
113 fsrv.Browse = new(Browse)
114 d.Args(&fsrv.Browse.TemplateFile)
115 for nesting := d.Nesting(); d.NextBlock(nesting); {
116 - if d.Val() != "reveal_symlinks" {
116 + switch d.Val() {
117 + case "reveal_symlinks":
118 + if fsrv.Browse.RevealSymlinks {
119 + return d.Err("Symlinks path reveal is already enabled")
120 + }
121 + fsrv.Browse.RevealSymlinks = true
122 + default:
123 return d.Errf("unknown subdirective '%s'", d.Val())
124 }
119 - if fsrv.Browse.RevealSymlinks {
120 - return d.Err("Symlinks path reveal is already enabled")
121 - }
122 - fsrv.Browse.RevealSymlinks = true
125 }
126
127 case "precompressed":