100 lines
		
	
	
		
			2.7 KiB
		
	
	
	
		
			Go
		
	
	
			
		
		
	
	
			100 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)
 | |
| }
 |