mirror of
				https://github.com/caddyserver/caddy.git
				synced 2025-10-30 18:22:49 -04:00 
			
		
		
		
	browse: Move predicate 'limit' to ServeListing
This keeps the interface of all available formatters honest, and allows for truncated listings all formats.
This commit is contained in:
		
							parent
							
								
									6908136092
								
							
						
					
					
						commit
						1d38d113f8
					
				| @ -309,6 +309,9 @@ footer { | |||||||
| 				<div class="content"> | 				<div class="content"> | ||||||
| 					<span class="meta-item"><b>{{.NumDirs}}</b> director{{if eq 1 .NumDirs}}y{{else}}ies{{end}}</span> | 					<span class="meta-item"><b>{{.NumDirs}}</b> director{{if eq 1 .NumDirs}}y{{else}}ies{{end}}</span> | ||||||
| 					<span class="meta-item"><b>{{.NumFiles}}</b> file{{if ne 1 .NumFiles}}s{{end}}</span> | 					<span class="meta-item"><b>{{.NumFiles}}</b> file{{if ne 1 .NumFiles}}s{{end}}</span> | ||||||
|  | 					{{- if ne 0 .ItemsLimitedTo}} | ||||||
|  | 					<span class="meta-item">(of which only <b>{{.ItemsLimitedTo}}</b> are displayed)</span> | ||||||
|  | 					{{- end}} | ||||||
| 				</div> | 				</div> | ||||||
| 			</div> | 			</div> | ||||||
| 			<div class="listing"> | 			<div class="listing"> | ||||||
| @ -316,29 +319,29 @@ footer { | |||||||
| 					<tr> | 					<tr> | ||||||
| 						<th> | 						<th> | ||||||
| 							{{if and (eq .Sort "name") (ne .Order "desc")}} | 							{{if and (eq .Sort "name") (ne .Order "desc")}} | ||||||
| 							<a href="?sort=name&order=desc">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a> | 							<a href="?sort=name&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a> | ||||||
| 							{{else if and (eq .Sort "name") (ne .Order "asc")}} | 							{{else if and (eq .Sort "name") (ne .Order "asc")}} | ||||||
| 							<a href="?sort=name&order=asc">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a> | 							<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a> | ||||||
| 							{{else}} | 							{{else}} | ||||||
| 							<a href="?sort=name&order=asc">Name</a> | 							<a href="?sort=name&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Name</a> | ||||||
| 							{{end}} | 							{{end}} | ||||||
| 						</th> | 						</th> | ||||||
| 						<th> | 						<th> | ||||||
| 							{{if and (eq .Sort "size") (ne .Order "desc")}} | 							{{if and (eq .Sort "size") (ne .Order "desc")}} | ||||||
| 							<a href="?sort=size&order=desc">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a> | 							<a href="?sort=size&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a> | ||||||
| 							{{else if and (eq .Sort "size") (ne .Order "asc")}} | 							{{else if and (eq .Sort "size") (ne .Order "asc")}} | ||||||
| 							<a href="?sort=size&order=asc">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a> | 							<a href="?sort=size&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Size <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a> | ||||||
| 							{{else}} | 							{{else}} | ||||||
| 							<a href="?sort=size&order=asc">Size</a> | 							<a href="?sort=size&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Size</a> | ||||||
| 							{{end}} | 							{{end}} | ||||||
| 						</th> | 						</th> | ||||||
| 						<th class="hideable"> | 						<th class="hideable"> | ||||||
| 							{{if and (eq .Sort "time") (ne .Order "desc")}} | 							{{if and (eq .Sort "time") (ne .Order "desc")}} | ||||||
| 							<a href="?sort=time&order=desc">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a> | 							<a href="?sort=time&order=desc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#up-arrow"></use></svg></a></a> | ||||||
| 							{{else if and (eq .Sort "time") (ne .Order "asc")}} | 							{{else if and (eq .Sort "time") (ne .Order "asc")}} | ||||||
| 							<a href="?sort=time&order=asc">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a> | 							<a href="?sort=time&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Modified <svg width="1em" height=".4em" version="1.1" viewBox="0 0 12.922194 6.0358899"><use xlink:href="#down-arrow"></use></svg></a></a> | ||||||
| 							{{else}} | 							{{else}} | ||||||
| 							<a href="?sort=time&order=asc">Modified</a> | 							<a href="?sort=time&order=asc{{if ne 0 .ItemsLimitedTo}}&limit={{.ItemsLimitedTo}}{{end}}">Modified</a> | ||||||
| 							{{end}} | 							{{end}} | ||||||
| 						</th> | 						</th> | ||||||
| 					</tr> | 					</tr> | ||||||
|  | |||||||
| @ -62,6 +62,9 @@ type Listing struct { | |||||||
| 	// And which order | 	// And which order | ||||||
| 	Order string | 	Order string | ||||||
| 
 | 
 | ||||||
|  | 	// If ≠0 then Items have been limited to that many elements | ||||||
|  | 	ItemsLimitedTo int | ||||||
|  | 
 | ||||||
| 	// Optional custom variables for use in browse templates | 	// Optional custom variables for use in browse templates | ||||||
| 	User interface{} | 	User interface{} | ||||||
| 
 | 
 | ||||||
| @ -298,32 +301,42 @@ func (b Browse) loadDirectoryContents(requestedFilepath, urlPath string) (*Listi | |||||||
| 	return &listing, hasIndex, nil | 	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. | // This sets Cookies. | ||||||
| func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (string, string) { | func (b Browse) handleSortOrder(w http.ResponseWriter, r *http.Request, scope string) (sort string, order string, limit int, err error) { | ||||||
| 	sort, order := r.URL.Query().Get("sort"), r.URL.Query().Get("order") | 	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 the query 'sort' or 'order' is empty, use defaults or any values previously saved in Cookies | ||||||
| 	if sort == "" { | 	switch sort { | ||||||
|  | 	case "": | ||||||
| 		sort = "name" | 		sort = "name" | ||||||
| 		if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil { | 		if sortCookie, sortErr := r.Cookie("sort"); sortErr == nil { | ||||||
| 			sort = sortCookie.Value | 			sort = sortCookie.Value | ||||||
| 		} | 		} | ||||||
| 	} else { | 	case "name", "size", "type": | ||||||
| 		http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil}) | 		http.SetCookie(w, &http.Cookie{Name: "sort", Value: sort, Path: scope, Secure: r.TLS != nil}) | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	if order == "" { | 	switch order { | ||||||
|  | 	case "": | ||||||
| 		order = "asc" | 		order = "asc" | ||||||
| 		if orderCookie, orderErr := r.Cookie("order"); orderErr == nil { | 		if orderCookie, orderErr := r.Cookie("order"); orderErr == nil { | ||||||
| 			order = orderCookie.Value | 			order = orderCookie.Value | ||||||
| 		} | 		} | ||||||
| 	} else { | 	case "asc", "desc": | ||||||
| 		http.SetCookie(w, &http.Cookie{Name: "order", Value: order, Path: scope, Secure: r.TLS != nil}) | 		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'. | // 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 | 	listing.User = bc.Variables | ||||||
| 
 | 
 | ||||||
| 	// Copy the query values into the Listing struct | 	// 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() | 	listing.applySort() | ||||||
| 
 | 
 | ||||||
|  | 	if limit > 0 && limit <= len(listing.Items) { | ||||||
|  | 		listing.Items = listing.Items[:limit] | ||||||
|  | 		listing.ItemsLimitedTo = limit | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
| 	var buf *bytes.Buffer | 	var buf *bytes.Buffer | ||||||
| 	acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ",")) | 	acceptHeader := strings.ToLower(strings.Join(r.Header["Accept"], ",")) | ||||||
| 	switch { | 	switch { | ||||||
| 	case strings.Contains(acceptHeader, "application/json"): | 	case strings.Contains(acceptHeader, "application/json"): | ||||||
| 		var limit int | 		if buf, err = b.formatAsJSON(listing, bc); err != nil { | ||||||
| 		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 { |  | ||||||
| 			return http.StatusInternalServerError, err | 			return http.StatusInternalServerError, err | ||||||
| 		} | 		} | ||||||
| 		w.Header().Set("Content-Type", "application/json; charset=utf-8") | 		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 | 	return http.StatusOK, nil | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| func (b Browse) formatAsJSON(listing *Listing, bc *Config, limit int) (*bytes.Buffer, error) { | func (b Browse) formatAsJSON(listing *Listing, bc *Config) (*bytes.Buffer, error) { | ||||||
| 	buf := new(bytes.Buffer) | 	marsh, err := json.Marshal(listing.Items) | ||||||
| 	var marsh []byte | 	if err != nil { | ||||||
| 	var err error | 		return nil, err | ||||||
| 
 |  | ||||||
| 	// 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 |  | ||||||
| 		} |  | ||||||
| 	} | 	} | ||||||
| 
 | 
 | ||||||
| 	// Write the marshaled json to buf | 	buf := new(bytes.Buffer) | ||||||
| 	_, err = buf.Write(marsh) | 	_, err = buf.Write(marsh) | ||||||
| 
 |  | ||||||
| 	return buf, err | 	return buf, err | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user