github.com/mika/distribution@v2.2.2-0.20160108133430-a75790e3d8e0+incompatible/registry/handlers/catalog.go (about) 1 package handlers 2 3 import ( 4 "encoding/json" 5 "fmt" 6 "io" 7 "net/http" 8 "net/url" 9 "strconv" 10 11 "github.com/docker/distribution/registry/api/errcode" 12 "github.com/gorilla/handlers" 13 ) 14 15 const maximumReturnedEntries = 100 16 17 func catalogDispatcher(ctx *Context, r *http.Request) http.Handler { 18 catalogHandler := &catalogHandler{ 19 Context: ctx, 20 } 21 22 return handlers.MethodHandler{ 23 "GET": http.HandlerFunc(catalogHandler.GetCatalog), 24 } 25 } 26 27 type catalogHandler struct { 28 *Context 29 } 30 31 type catalogAPIResponse struct { 32 Repositories []string `json:"repositories"` 33 } 34 35 func (ch *catalogHandler) GetCatalog(w http.ResponseWriter, r *http.Request) { 36 var moreEntries = true 37 38 q := r.URL.Query() 39 lastEntry := q.Get("last") 40 maxEntries, err := strconv.Atoi(q.Get("n")) 41 if err != nil || maxEntries < 0 { 42 maxEntries = maximumReturnedEntries 43 } 44 45 repos := make([]string, maxEntries) 46 47 filled, err := ch.App.registry.Repositories(ch.Context, repos, lastEntry) 48 if err == io.EOF { 49 moreEntries = false 50 } else if err != nil { 51 ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) 52 return 53 } 54 55 w.Header().Set("Content-Type", "application/json; charset=utf-8") 56 57 // Add a link header if there are more entries to retrieve 58 if moreEntries { 59 lastEntry = repos[len(repos)-1] 60 urlStr, err := createLinkEntry(r.URL.String(), maxEntries, lastEntry) 61 if err != nil { 62 ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) 63 return 64 } 65 w.Header().Set("Link", urlStr) 66 } 67 68 enc := json.NewEncoder(w) 69 if err := enc.Encode(catalogAPIResponse{ 70 Repositories: repos[0:filled], 71 }); err != nil { 72 ch.Errors = append(ch.Errors, errcode.ErrorCodeUnknown.WithDetail(err)) 73 return 74 } 75 } 76 77 // Use the original URL from the request to create a new URL for 78 // the link header 79 func createLinkEntry(origURL string, maxEntries int, lastEntry string) (string, error) { 80 calledURL, err := url.Parse(origURL) 81 if err != nil { 82 return "", err 83 } 84 85 v := url.Values{} 86 v.Add("n", strconv.Itoa(maxEntries)) 87 v.Add("last", lastEntry) 88 89 calledURL.RawQuery = v.Encode() 90 91 calledURL.Fragment = "" 92 urlStr := fmt.Sprintf("<%s>; rel=\"next\"", calledURL.String()) 93 94 return urlStr, nil 95 }