package registry import ( "net/http" "github.com/docker/distribution/api/v2" "github.com/docker/distribution/digest" "github.com/docker/distribution/storage" "github.com/gorilla/handlers" ) // layerDispatcher uses the request context to build a layerHandler. func layerDispatcher(ctx *Context, r *http.Request) http.Handler { dgst, err := digest.ParseDigest(ctx.vars["digest"]) if err != nil { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ctx.Errors.Push(v2.ErrorCodeDigestInvalid, err) }) } layerHandler := &layerHandler{ Context: ctx, Digest: dgst, } layerHandler.log = layerHandler.log.WithField("digest", dgst) return handlers.MethodHandler{ "GET": http.HandlerFunc(layerHandler.GetLayer), "HEAD": http.HandlerFunc(layerHandler.GetLayer), } } // layerHandler serves http layer requests. type layerHandler struct { *Context Digest digest.Digest } // GetLayer fetches the binary data from backend storage returns it in the // response. func (lh *layerHandler) GetLayer(w http.ResponseWriter, r *http.Request) { layers := lh.Repository.Layers() layer, err := layers.Fetch(lh.Digest) if err != nil { switch err := err.(type) { case storage.ErrUnknownLayer: w.WriteHeader(http.StatusNotFound) lh.Errors.Push(v2.ErrorCodeBlobUnknown, err.FSLayer) default: lh.Errors.Push(v2.ErrorCodeUnknown, err) } return } defer layer.Close() if lh.layerHandler != nil { handler, _ := lh.layerHandler.Resolve(layer) if handler != nil { handler.ServeHTTP(w, r) return } } http.ServeContent(w, r, layer.Digest().String(), layer.CreatedAt(), layer) }