2014-11-11 02:57:38 +00:00
|
|
|
package registry
|
|
|
|
|
|
|
|
import (
|
|
|
|
"net/http"
|
|
|
|
|
2014-11-21 03:57:01 +00:00
|
|
|
"github.com/docker/docker-registry/digest"
|
|
|
|
"github.com/docker/docker-registry/storage"
|
2014-11-11 02:57:38 +00:00
|
|
|
"github.com/gorilla/handlers"
|
2014-11-21 03:57:01 +00:00
|
|
|
"github.com/gorilla/mux"
|
2014-11-11 02:57:38 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// layerDispatcher uses the request context to build a layerHandler.
|
|
|
|
func layerDispatcher(ctx *Context, r *http.Request) http.Handler {
|
2014-11-21 03:57:01 +00:00
|
|
|
dgst, err := digest.ParseDigest(ctx.vars["digest"])
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
|
|
ctx.Errors.Push(ErrorCodeInvalidDigest, err)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2014-11-11 02:57:38 +00:00
|
|
|
layerHandler := &layerHandler{
|
|
|
|
Context: ctx,
|
2014-11-21 03:57:01 +00:00
|
|
|
Digest: dgst,
|
2014-11-11 02:57:38 +00:00
|
|
|
}
|
|
|
|
|
2014-11-21 03:57:01 +00:00
|
|
|
layerHandler.log = layerHandler.log.WithField("digest", dgst)
|
2014-11-11 02:57:38 +00:00
|
|
|
|
|
|
|
return handlers.MethodHandler{
|
2014-11-19 03:38:14 +00:00
|
|
|
"GET": http.HandlerFunc(layerHandler.GetLayer),
|
|
|
|
"HEAD": http.HandlerFunc(layerHandler.GetLayer),
|
2014-11-11 02:57:38 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// layerHandler serves http layer requests.
|
|
|
|
type layerHandler struct {
|
|
|
|
*Context
|
|
|
|
|
2014-11-21 03:57:01 +00:00
|
|
|
Digest digest.Digest
|
2014-11-11 02:57:38 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// GetLayer fetches the binary data from backend storage returns it in the
|
|
|
|
// response.
|
|
|
|
func (lh *layerHandler) GetLayer(w http.ResponseWriter, r *http.Request) {
|
2014-11-21 03:57:01 +00:00
|
|
|
layers := lh.services.Layers()
|
|
|
|
|
|
|
|
layer, err := layers.Fetch(lh.Name, lh.Digest)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
switch err {
|
|
|
|
case storage.ErrLayerUnknown:
|
|
|
|
w.WriteHeader(http.StatusNotFound)
|
|
|
|
lh.Errors.Push(ErrorCodeUnknownLayer,
|
|
|
|
map[string]interface{}{
|
|
|
|
"unknown": FSLayer{BlobSum: lh.Digest},
|
|
|
|
})
|
|
|
|
return
|
|
|
|
default:
|
|
|
|
lh.Errors.Push(ErrorCodeUnknown, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
defer layer.Close()
|
|
|
|
|
|
|
|
http.ServeContent(w, r, layer.Digest().String(), layer.CreatedAt(), layer)
|
|
|
|
}
|
|
|
|
|
|
|
|
func buildLayerURL(router *mux.Router, r *http.Request, layer storage.Layer) (string, error) {
|
|
|
|
route := clonedRoute(router, routeNameBlob)
|
|
|
|
|
|
|
|
layerURL, err := route.Schemes(r.URL.Scheme).Host(r.Host).
|
|
|
|
URL("name", layer.Name(),
|
|
|
|
"digest", layer.Digest().String())
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
2014-11-11 02:57:38 +00:00
|
|
|
|
2014-11-21 03:57:01 +00:00
|
|
|
return layerURL.String(), nil
|
2014-11-11 02:57:38 +00:00
|
|
|
}
|