| package handlers |
| |
| import ( |
| "net/http" |
| |
| "github.com/docker/distribution" |
| "github.com/docker/distribution/context" |
| "github.com/docker/distribution/registry/api/errcode" |
| "github.com/docker/distribution/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) |
| } |