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  }