96 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			96 lines
		
	
	
		
			2.1 KiB
		
	
	
	
		
			Go
		
	
	
package handlers
 | 
						|
 | 
						|
import (
 | 
						|
	"encoding/json"
 | 
						|
	"fmt"
 | 
						|
	"io"
 | 
						|
	"net/http"
 | 
						|
	"net/url"
 | 
						|
	"strconv"
 | 
						|
 | 
						|
	"github.com/docker/distribution/registry/api/errcode"
 | 
						|
	"github.com/gorilla/handlers"
 | 
						|
)
 | 
						|
 | 
						|
const maximumReturnedEntries = 100
 | 
						|
 | 
						|
func catalogDispatcher(ctx *Context, r *http.Request) http.Handler {
 | 
						|
	catalogHandler := &catalogHandler{
 | 
						|
		Context: ctx,
 | 
						|
	}
 | 
						|
 | 
						|
	return handlers.MethodHandler{
 | 
						|
		"GET": http.HandlerFunc(catalogHandler.GetCatalog),
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
type catalogHandler struct {
 | 
						|
	*Context
 | 
						|
}
 | 
						|
 | 
						|
type catalogAPIResponse struct {
 | 
						|
	Repositories []string `json:"repositories"`
 | 
						|
}
 | 
						|
 | 
						|
func (ch *catalogHandler) GetCatalog(w http.ResponseWriter, r *http.Request) {
 | 
						|
	var moreEntries = true
 | 
						|
 | 
						|
	q := r.URL.Query()
 | 
						|
	lastEntry := q.Get("last")
 | 
						|
	maxEntries, err := strconv.Atoi(q.Get("n"))
 | 
						|
	if err != nil || maxEntries < 0 {
 | 
						|
		maxEntries = maximumReturnedEntries
 | 
						|
	}
 | 
						|
 | 
						|
	repos := make([]string, maxEntries)
 | 
						|
 | 
						|
	filled, err := ch.App.registry.Repositories(ch.Context, repos, lastEntry)
 | 
						|
	if err == io.EOF {
 | 
						|
		moreEntries = false
 | 
						|
	} else if err != nil {
 | 
						|
		ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
 | 
						|
		return
 | 
						|
	}
 | 
						|
 | 
						|
	w.Header().Set("Content-Type", "application/json; charset=utf-8")
 | 
						|
 | 
						|
	// Add a link header if there are more entries to retrieve
 | 
						|
	if moreEntries {
 | 
						|
		lastEntry = repos[len(repos)-1]
 | 
						|
		urlStr, err := createLinkEntry(r.URL.String(), maxEntries, lastEntry)
 | 
						|
		if err != nil {
 | 
						|
			ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
 | 
						|
			return
 | 
						|
		}
 | 
						|
		w.Header().Set("Link", urlStr)
 | 
						|
	}
 | 
						|
 | 
						|
	enc := json.NewEncoder(w)
 | 
						|
	if err := enc.Encode(catalogAPIResponse{
 | 
						|
		Repositories: repos[0:filled],
 | 
						|
	}); err != nil {
 | 
						|
		ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
 | 
						|
		return
 | 
						|
	}
 | 
						|
}
 | 
						|
 | 
						|
// Use the original URL from the request to create a new URL for
 | 
						|
// the link header
 | 
						|
func createLinkEntry(origURL string, maxEntries int, lastEntry string) (string, error) {
 | 
						|
	calledURL, err := url.Parse(origURL)
 | 
						|
	if err != nil {
 | 
						|
		return "", err
 | 
						|
	}
 | 
						|
 | 
						|
	v := url.Values{}
 | 
						|
	v.Add("n", strconv.Itoa(maxEntries))
 | 
						|
	v.Add("last", lastEntry)
 | 
						|
 | 
						|
	calledURL.RawQuery = v.Encode()
 | 
						|
 | 
						|
	calledURL.Fragment = ""
 | 
						|
	urlStr := fmt.Sprintf("<%s>; rel=\"next\"", calledURL.String())
 | 
						|
 | 
						|
	return urlStr, nil
 | 
						|
}
 |