1d33874951
Go 1.13 and up enforce import paths to be versioned if a project contains a go.mod and has released v2 or up. The current v2.x branches (and releases) do not yet have a go.mod, and therefore are still allowed to be imported with a non-versioned import path (go modules add a `+incompatible` annotation in that case). However, now that this project has a `go.mod` file, incompatible import paths will not be accepted by go modules, and attempting to use code from this repository will fail. This patch uses `v3` for the import-paths (not `v2`), because changing import paths itself is a breaking change, which means that the next release should increment the "major" version to comply with SemVer (as go modules dictate). Signed-off-by: Sebastiaan van Stijn <github@gone.nl>
99 lines
2.7 KiB
Go
99 lines
2.7 KiB
Go
package handlers
|
|
|
|
import (
|
|
"net/http"
|
|
|
|
"github.com/distribution/distribution/v3"
|
|
"github.com/distribution/distribution/v3/context"
|
|
"github.com/distribution/distribution/v3/registry/api/errcode"
|
|
v2 "github.com/distribution/distribution/v3/registry/api/v2"
|
|
"github.com/gorilla/handlers"
|
|
"github.com/opencontainers/go-digest"
|
|
)
|
|
|
|
// blobDispatcher uses the request context to build a blobHandler.
|
|
func blobDispatcher(ctx *Context, r *http.Request) http.Handler {
|
|
dgst, err := getDigest(ctx)
|
|
if err != nil {
|
|
|
|
if err == errDigestNotAvailable {
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx.Errors = append(ctx.Errors, v2.ErrorCodeDigestInvalid.WithDetail(err))
|
|
})
|
|
}
|
|
|
|
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
ctx.Errors = append(ctx.Errors, v2.ErrorCodeDigestInvalid.WithDetail(err))
|
|
})
|
|
}
|
|
|
|
blobHandler := &blobHandler{
|
|
Context: ctx,
|
|
Digest: dgst,
|
|
}
|
|
|
|
mhandler := handlers.MethodHandler{
|
|
"GET": http.HandlerFunc(blobHandler.GetBlob),
|
|
"HEAD": http.HandlerFunc(blobHandler.GetBlob),
|
|
}
|
|
|
|
if !ctx.readOnly {
|
|
mhandler["DELETE"] = http.HandlerFunc(blobHandler.DeleteBlob)
|
|
}
|
|
|
|
return mhandler
|
|
}
|
|
|
|
// blobHandler serves http blob requests.
|
|
type blobHandler struct {
|
|
*Context
|
|
|
|
Digest digest.Digest
|
|
}
|
|
|
|
// GetBlob fetches the binary data from backend storage returns it in the
|
|
// response.
|
|
func (bh *blobHandler) GetBlob(w http.ResponseWriter, r *http.Request) {
|
|
context.GetLogger(bh).Debug("GetBlob")
|
|
blobs := bh.Repository.Blobs(bh)
|
|
desc, err := blobs.Stat(bh, bh.Digest)
|
|
if err != nil {
|
|
if err == distribution.ErrBlobUnknown {
|
|
bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown.WithDetail(bh.Digest))
|
|
} else {
|
|
bh.Errors = append(bh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
|
}
|
|
return
|
|
}
|
|
|
|
if err := blobs.ServeBlob(bh, w, r, desc.Digest); err != nil {
|
|
context.GetLogger(bh).Debugf("unexpected error getting blob HTTP handler: %v", err)
|
|
bh.Errors = append(bh.Errors, errcode.ErrorCodeUnknown.WithDetail(err))
|
|
return
|
|
}
|
|
}
|
|
|
|
// DeleteBlob deletes a layer blob
|
|
func (bh *blobHandler) DeleteBlob(w http.ResponseWriter, r *http.Request) {
|
|
context.GetLogger(bh).Debug("DeleteBlob")
|
|
|
|
blobs := bh.Repository.Blobs(bh)
|
|
err := blobs.Delete(bh, bh.Digest)
|
|
if err != nil {
|
|
switch err {
|
|
case distribution.ErrUnsupported:
|
|
bh.Errors = append(bh.Errors, errcode.ErrorCodeUnsupported)
|
|
return
|
|
case distribution.ErrBlobUnknown:
|
|
bh.Errors = append(bh.Errors, v2.ErrorCodeBlobUnknown)
|
|
return
|
|
default:
|
|
bh.Errors = append(bh.Errors, err)
|
|
context.GetLogger(bh).Errorf("Unknown error deleting blob: %s", err.Error())
|
|
return
|
|
}
|
|
}
|
|
|
|
w.Header().Set("Content-Length", "0")
|
|
w.WriteHeader(http.StatusAccepted)
|
|
}
|