forked from TrueCloudLab/distribution
Prepare urls.URLBuilder package for export
The URLBuilder is now exported with documentation for its behavior. Its a light wrapper around gorilla mux that avoids one having to remember exact arguments take by each route.
This commit is contained in:
parent
e5b6da80d0
commit
9b872ca150
1 changed files with 70 additions and 75 deletions
145
api/urls/urls.go
145
api/urls/urls.go
|
@ -1,52 +1,61 @@
|
||||||
package registry
|
package urls
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
|
|
||||||
"github.com/docker/docker-registry/api/urls"
|
|
||||||
"github.com/docker/docker-registry/digest"
|
"github.com/docker/docker-registry/digest"
|
||||||
"github.com/docker/docker-registry/storage"
|
|
||||||
"github.com/gorilla/mux"
|
"github.com/gorilla/mux"
|
||||||
)
|
)
|
||||||
|
|
||||||
type urlBuilder struct {
|
// URLBuilder creates registry API urls from a single base endpoint. It can be
|
||||||
url *url.URL // url root (ie http://localhost/)
|
// used to create urls for use in a registry client or server.
|
||||||
|
//
|
||||||
|
// All urls will be created from the given base, including the api version.
|
||||||
|
// For example, if a root of "/foo/" is provided, urls generated will be fall
|
||||||
|
// under "/foo/v2/...". Most application will only provide a schema, host and
|
||||||
|
// port, such as "https://localhost:5000/".
|
||||||
|
type URLBuilder struct {
|
||||||
|
root *url.URL // url root (ie http://localhost/)
|
||||||
router *mux.Router
|
router *mux.Router
|
||||||
}
|
}
|
||||||
|
|
||||||
func newURLBuilder(root *url.URL) *urlBuilder {
|
// NewURLBuilder creates a URLBuilder with provided root url object.
|
||||||
return &urlBuilder{
|
func NewURLBuilder(root *url.URL) *URLBuilder {
|
||||||
url: root,
|
return &URLBuilder{
|
||||||
router: urls.Router(),
|
root: root,
|
||||||
|
router: Router(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func newURLBuilderFromRequest(r *http.Request) *urlBuilder {
|
// NewURLBuilderFromString workes identically to NewURLBuilder except it takes
|
||||||
u := &url.URL{
|
// a string argument for the root, returning an error if it is not a valid
|
||||||
Scheme: r.URL.Scheme,
|
// url.
|
||||||
Host: r.Host,
|
func NewURLBuilderFromString(root string) (*URLBuilder, error) {
|
||||||
}
|
|
||||||
|
|
||||||
return newURLBuilder(u)
|
|
||||||
}
|
|
||||||
|
|
||||||
func newURLBuilderFromString(root string) (*urlBuilder, error) {
|
|
||||||
u, err := url.Parse(root)
|
u, err := url.Parse(root)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
return newURLBuilder(u), nil
|
return NewURLBuilder(u), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ub *urlBuilder) buildBaseURL() (string, error) {
|
// NewURLBuilderFromRequest uses information from an *http.Request to
|
||||||
route := clonedRoute(ub.router, urls.RouteNameBase)
|
// construct the root url.
|
||||||
|
func NewURLBuilderFromRequest(r *http.Request) *URLBuilder {
|
||||||
|
u := &url.URL{
|
||||||
|
Scheme: r.URL.Scheme,
|
||||||
|
Host: r.Host,
|
||||||
|
}
|
||||||
|
|
||||||
baseURL, err := route.
|
return NewURLBuilder(u)
|
||||||
Schemes(ub.url.Scheme).
|
}
|
||||||
Host(ub.url.Host).
|
|
||||||
URL()
|
// BuildBaseURL constructs a base url for the API, typically just "/v2/".
|
||||||
|
func (ub *URLBuilder) BuildBaseURL() (string, error) {
|
||||||
|
route := ub.cloneRoute(RouteNameBase)
|
||||||
|
|
||||||
|
baseURL, err := route.URL()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -54,13 +63,11 @@ func (ub *urlBuilder) buildBaseURL() (string, error) {
|
||||||
return baseURL.String(), nil
|
return baseURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ub *urlBuilder) buildTagsURL(name string) (string, error) {
|
// BuildTagsURL constructs a url to list the tags in the named repository.
|
||||||
route := clonedRoute(ub.router, urls.RouteNameTags)
|
func (ub *URLBuilder) BuildTagsURL(name string) (string, error) {
|
||||||
|
route := ub.cloneRoute(RouteNameTags)
|
||||||
|
|
||||||
tagsURL, err := route.
|
tagsURL, err := route.URL("name", name)
|
||||||
Schemes(ub.url.Scheme).
|
|
||||||
Host(ub.url.Host).
|
|
||||||
URL("name", name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -68,17 +75,11 @@ func (ub *urlBuilder) buildTagsURL(name string) (string, error) {
|
||||||
return tagsURL.String(), nil
|
return tagsURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ub *urlBuilder) forManifest(m *storage.Manifest) (string, error) {
|
// BuildManifestURL constructs a url for the manifest identified by name and tag.
|
||||||
return ub.buildManifestURL(m.Name, m.Tag)
|
func (ub *URLBuilder) BuildManifestURL(name, tag string) (string, error) {
|
||||||
}
|
route := ub.cloneRoute(RouteNameManifest)
|
||||||
|
|
||||||
func (ub *urlBuilder) buildManifestURL(name, tag string) (string, error) {
|
manifestURL, err := route.URL("name", name, "tag", tag)
|
||||||
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -86,17 +87,11 @@ func (ub *urlBuilder) buildManifestURL(name, tag string) (string, error) {
|
||||||
return manifestURL.String(), nil
|
return manifestURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ub *urlBuilder) forLayer(l storage.Layer) (string, error) {
|
// BuildLayerURL constructs the url for the blob identified by name and dgst.
|
||||||
return ub.buildLayerURL(l.Name(), l.Digest())
|
func (ub *URLBuilder) BuildBlobURL(name string, dgst digest.Digest) (string, error) {
|
||||||
}
|
route := ub.cloneRoute(RouteNameBlob)
|
||||||
|
|
||||||
func (ub *urlBuilder) buildLayerURL(name string, dgst digest.Digest) (string, error) {
|
layerURL, err := route.URL("name", name, "digest", dgst.String())
|
||||||
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -104,13 +99,12 @@ func (ub *urlBuilder) buildLayerURL(name string, dgst digest.Digest) (string, er
|
||||||
return layerURL.String(), nil
|
return layerURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ub *urlBuilder) buildLayerUploadURL(name string) (string, error) {
|
// BuildBlobURL constructs a url to begin a blob upload in the repository
|
||||||
route := clonedRoute(ub.router, urls.RouteNameBlobUpload)
|
// identified by name.
|
||||||
|
func (ub *URLBuilder) BuildBlobUploadURL(name string) (string, error) {
|
||||||
|
route := ub.cloneRoute(RouteNameBlobUpload)
|
||||||
|
|
||||||
uploadURL, err := route.
|
uploadURL, err := route.URL("name", name)
|
||||||
Schemes(ub.url.Scheme).
|
|
||||||
Host(ub.url.Host).
|
|
||||||
URL("name", name)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -118,17 +112,14 @@ func (ub *urlBuilder) buildLayerUploadURL(name string) (string, error) {
|
||||||
return uploadURL.String(), nil
|
return uploadURL.String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ub *urlBuilder) forLayerUpload(layerUpload storage.LayerUpload) (string, error) {
|
// BuildBlobUploadChunkURL constructs a url for the upload identified by uuid,
|
||||||
return ub.buildLayerUploadResumeURL(layerUpload.Name(), layerUpload.UUID())
|
// including any url values. This should generally not be used by clients, as
|
||||||
}
|
// this url is provided by server implementations during the blob upload
|
||||||
|
// process.
|
||||||
|
func (ub *URLBuilder) BuildBlobUploadChunkURL(name, uuid string, values ...url.Values) (string, error) {
|
||||||
|
route := ub.cloneRoute(RouteNameBlobUploadChunk)
|
||||||
|
|
||||||
func (ub *urlBuilder) buildLayerUploadResumeURL(name, uuid string, values ...url.Values) (string, error) {
|
uploadURL, err := route.URL("name", name, "uuid", uuid)
|
||||||
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 {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
@ -136,6 +127,17 @@ func (ub *urlBuilder) buildLayerUploadResumeURL(name, uuid string, values ...url
|
||||||
return appendValuesURL(uploadURL, values...).String(), nil
|
return appendValuesURL(uploadURL, values...).String(), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// clondedRoute returns a clone of the named route from the router. Routes
|
||||||
|
// must be cloned to avoid modifying them during url generation.
|
||||||
|
func (ub *URLBuilder) cloneRoute(name string) *mux.Route {
|
||||||
|
route := new(mux.Route)
|
||||||
|
*route = *ub.router.GetRoute(name) // clone the route
|
||||||
|
|
||||||
|
return route.
|
||||||
|
Schemes(ub.root.Scheme).
|
||||||
|
Host(ub.root.Host)
|
||||||
|
}
|
||||||
|
|
||||||
// appendValuesURL appends the parameters to the url.
|
// appendValuesURL appends the parameters to the url.
|
||||||
func appendValuesURL(u *url.URL, values ...url.Values) *url.URL {
|
func appendValuesURL(u *url.URL, values ...url.Values) *url.URL {
|
||||||
merged := u.Query()
|
merged := u.Query()
|
||||||
|
@ -161,10 +163,3 @@ func appendValues(u string, values ...url.Values) string {
|
||||||
|
|
||||||
return appendValuesURL(up, values...).String()
|
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
|
|
||||||
}
|
|
||||||
|
|
Loading…
Reference in a new issue