distribution/urls.go
Stephen J Day 5b13e95511 Porting registry to use urls package
This simply moves the registry app to be using the urls package and its
exported route names. This supports locking down exported route definitions for
use in client packages.
2014-12-12 15:36:15 -08:00

170 lines
3.7 KiB
Go

package registry
import (
"net/http"
"net/url"
"github.com/docker/docker-registry/api/urls"
"github.com/docker/docker-registry/digest"
"github.com/docker/docker-registry/storage"
"github.com/gorilla/mux"
)
type urlBuilder struct {
url *url.URL // url root (ie http://localhost/)
router *mux.Router
}
func newURLBuilder(root *url.URL) *urlBuilder {
return &urlBuilder{
url: root,
router: urls.Router(),
}
}
func newURLBuilderFromRequest(r *http.Request) *urlBuilder {
u := &url.URL{
Scheme: r.URL.Scheme,
Host: r.Host,
}
return newURLBuilder(u)
}
func newURLBuilderFromString(root string) (*urlBuilder, error) {
u, err := url.Parse(root)
if err != nil {
return nil, err
}
return newURLBuilder(u), nil
}
func (ub *urlBuilder) buildBaseURL() (string, error) {
route := clonedRoute(ub.router, urls.RouteNameBase)
baseURL, err := route.
Schemes(ub.url.Scheme).
Host(ub.url.Host).
URL()
if err != nil {
return "", err
}
return baseURL.String(), nil
}
func (ub *urlBuilder) buildTagsURL(name string) (string, error) {
route := clonedRoute(ub.router, urls.RouteNameTags)
tagsURL, err := route.
Schemes(ub.url.Scheme).
Host(ub.url.Host).
URL("name", name)
if err != nil {
return "", err
}
return tagsURL.String(), nil
}
func (ub *urlBuilder) forManifest(m *storage.Manifest) (string, error) {
return ub.buildManifestURL(m.Name, m.Tag)
}
func (ub *urlBuilder) buildManifestURL(name, tag string) (string, error) {
route := clonedRoute(ub.router, urls.RouteNameManifest)
manifestURL, err := route.
Schemes(ub.url.Scheme).
Host(ub.url.Host).
URL("name", name, "tag", tag)
if err != nil {
return "", err
}
return manifestURL.String(), nil
}
func (ub *urlBuilder) forLayer(l storage.Layer) (string, error) {
return ub.buildLayerURL(l.Name(), l.Digest())
}
func (ub *urlBuilder) buildLayerURL(name string, dgst digest.Digest) (string, error) {
route := clonedRoute(ub.router, urls.RouteNameBlob)
layerURL, err := route.
Schemes(ub.url.Scheme).
Host(ub.url.Host).
URL("name", name, "digest", dgst.String())
if err != nil {
return "", err
}
return layerURL.String(), nil
}
func (ub *urlBuilder) buildLayerUploadURL(name string) (string, error) {
route := clonedRoute(ub.router, urls.RouteNameBlobUpload)
uploadURL, err := route.
Schemes(ub.url.Scheme).
Host(ub.url.Host).
URL("name", name)
if err != nil {
return "", err
}
return uploadURL.String(), nil
}
func (ub *urlBuilder) forLayerUpload(layerUpload storage.LayerUpload) (string, error) {
return ub.buildLayerUploadResumeURL(layerUpload.Name(), layerUpload.UUID())
}
func (ub *urlBuilder) buildLayerUploadResumeURL(name, uuid string, values ...url.Values) (string, error) {
route := clonedRoute(ub.router, urls.RouteNameBlobUploadChunk)
uploadURL, err := route.
Schemes(ub.url.Scheme).
Host(ub.url.Host).
URL("name", name, "uuid", uuid)
if err != nil {
return "", err
}
return appendValuesURL(uploadURL, values...).String(), nil
}
// appendValuesURL appends the parameters to the url.
func appendValuesURL(u *url.URL, values ...url.Values) *url.URL {
merged := u.Query()
for _, v := range values {
for k, vv := range v {
merged[k] = append(merged[k], vv...)
}
}
u.RawQuery = merged.Encode()
return u
}
// appendValues appends the parameters to the url. Panics if the string is not
// a url.
func appendValues(u string, values ...url.Values) string {
up, err := url.Parse(u)
if err != nil {
panic(err) // should never happen
}
return appendValuesURL(up, values...).String()
}
// clondedRoute returns a clone of the named route from the router.
func clonedRoute(router *mux.Router, name string) *mux.Route {
route := new(mux.Route)
*route = *router.GetRoute(name) // clone the route
return route
}