diff --git a/caddy/setup/browse.go b/caddy/setup/browse.go index 28cb2582..ff921b9b 100644 --- a/caddy/setup/browse.go +++ b/caddy/setup/browse.go @@ -309,6 +309,9 @@ footer {
{{.NumDirs}} director{{if eq 1 .NumDirs}}y{{else}}ies{{end}} {{.NumFiles}} file{{if ne 1 .NumFiles}}s{{end}} + {{- if ne 0 .ItemsLimitedTo}} + (of which only {{.ItemsLimitedTo}} are displayed) + {{- end}}
@@ -316,29 +319,29 @@ footer { {{if and (eq .Sort "name") (ne .Order "desc")}} - Name + Name {{else if and (eq .Sort "name") (ne .Order "asc")}} - Name + Name {{else}} - Name + Name {{end}} {{if and (eq .Sort "size") (ne .Order "desc")}} - Size + Size {{else if and (eq .Sort "size") (ne .Order "asc")}} - Size + Size {{else}} - Size + Size {{end}} {{if and (eq .Sort "time") (ne .Order "desc")}} - Modified + Modified {{else if and (eq .Sort "time") (ne .Order "asc")}} - Modified + Modified {{else}} - Modified + Modified {{end}} diff --git a/middleware/browse/browse.go b/middleware/browse/browse.go index 3a727d96..e350c07a 100644 --- a/middleware/browse/browse.go +++ b/middleware/browse/browse.go @@ -62,6 +62,9 @@ type Listing struct { // And which order Order string + // If ≠0 then Items have been limited to that many elements + ItemsLimitedTo int + // Optional custom variables for use in browse templates User interface{} @@ -298,32 +301,42 @@ func (b Browse) loadDirectoryContents(requestedFilepath, urlPath string) (*Listi return &listing, hasIndex, nil } -// handleSortOrder gets and stores for a Listing the 'sort' and 'order'. +// handleSortOrder gets and stores for a Listing the 'sort' and 'order', +// and reads 'limit' if given. The latter is 0 if not given. // // This sets Cookies. -func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (string, string) { - sort, order := r.URL.Query().Get("sort"), r.URL.Query().Get("order") +func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (sort string, order string, limit int, err error) { + sort, order, limitQuery := r.URL.Query().Get("sort"), r.URL.Query().Get("order"), r.URL.Query().Get("limit") // If the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies - if sort == "" { + switch sort { + case "": sort = "name" if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil { sort = sortCookie.Value } - } else { + case "name", "size", "type": http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil}) } - if order == "" { + switch order { + case "": order = "asc" if orderCookie, orderErr := r.Cookie("order"); orderErr == nil { order = orderCookie.Value } - } else { + case "asc", "desc": http.SetCookie(w, &http.Cookie{Name: "order", Value: order, Path: scope, Secure: r.TLS != nil}) } - return sort, order + if limitQuery != "" { + limit, err = strconv.Atoi(limitQuery) + if err != nil { // if the 'limit' query can't be interpreted as a number, return err + return + } + } + + return } // ServeListing returns a formatted view of 'requestedFilepath' contents'. @@ -350,23 +363,24 @@ func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFi listing.User = bc.Variables // Copy the query values into the Listing struct - listing.Sort, listing.Order = b.handleSortOrder(w, r, bc.PathScope) + var limit int + listing.Sort, listing.Order, limit, err = b.handleSortOrder(w, r, bc.PathScope) + if err != nil { + return http.StatusBadRequest, err + } listing.applySort() + if limit > 0 && limit <= len(listing.Items) { + listing.Items = listing.Items[:limit] + listing.ItemsLimitedTo = limit + } + var buf *bytes.Buffer acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ",")) switch { case strings.Contains(acceptHeader, "application/json"): - var limit int - if limitQuery := r.URL.Query().Get("limit"); limitQuery != "" { - limit, err = strconv.Atoi(limitQuery) - if err != nil { // if the 'limit' query can't be interpreted as a number, return err - return http.StatusBadRequest, err - } - } - - if buf, err = b.formatAsJSON(listing, bc, limit); err != nil { + if buf, err = b.formatAsJSON(listing, bc); err != nil { return http.StatusInternalServerError, err } w.Header().Set("Content-Type", "application/json; charset=utf-8") @@ -384,32 +398,14 @@ func (b Browse) ServeListing(w http.ResponseWriter, r *http.Request, requestedFi return http.StatusOK, nil } -func (b Browse) formatAsJSON(listing *Listing, bc *Config, limit int) (*bytes.Buffer, error) { - buf := new(bytes.Buffer) - var marsh []byte - var err error - - // Check if we are limited - if limit > 0 { - // if `limit` is equal or less than len(listing.Items) and bigger than 0, list them - if limit <= len(listing.Items) { - marsh, err = json.Marshal(listing.Items[:limit]) - } else { // if the 'limit' query is empty, or has the wrong value, list everything - marsh, err = json.Marshal(listing.Items) - } - if err != nil { - return nil, err - } - } else { // There's no 'limit' query; list them all - marsh, err = json.Marshal(listing.Items) - if err != nil { - return nil, err - } +func (b Browse) formatAsJSON(listing *Listing, bc *Config) (*bytes.Buffer, error) { + marsh, err := json.Marshal(listing.Items) + if err != nil { + return nil, err } - // Write the marshaled json to buf + buf := new(bytes.Buffer) _, err = buf.Write(marsh) - return buf, err }