b7e26bac74
This change removes the Catalog Service and replaces it with a more simplistic Repositories() method for obtaining a catalog of all repositories. The Repositories method takes a pre-allocated slice and fills it up to the size of the slice and returns the amount filled. The catalog is returned lexicographically and will start being filled from the last entry passed to Repositories(). If there are no more entries to fill, io.EOF will be returned. Signed-off-by: Patrick Devine <patrick.devine@docker.com> Conflicts: registry/client/repository.go registry/handlers/api_test.go
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
|
|
}
|