@@ -76,6 +76,13 @@ type blobPutHandler interface {
7676 Put (ctx context.Context , repo string , h v1.Hash , rc io.ReadCloser ) error
7777}
7878
79+ // blobDeleteHandler is an extension interface representing a blob storage
80+ // backend that can delete blob contents.
81+ type blobDeleteHandler interface {
82+ // Delete the blob contents.
83+ Delete (ctx context.Context , repo string , h v1.Hash ) error
84+ }
85+
7986// redirectError represents a signal that the blob handler doesn't have the blob
8087// contents, but that those contents are at another location which registry
8188// clients should redirect to.
@@ -129,6 +136,17 @@ func (m *memHandler) Put(_ context.Context, _ string, h v1.Hash, rc io.ReadClose
129136 m .m [h .String ()] = all
130137 return nil
131138}
139+ func (m * memHandler ) Delete (_ context.Context , _ string , h v1.Hash ) error {
140+ m .lock .Lock ()
141+ defer m .lock .Unlock ()
142+
143+ if _ , found := m .m [h .String ()]; ! found {
144+ return errNotFound
145+ }
146+
147+ delete (m .m , h .String ())
148+ return nil
149+ }
132150
133151// blobs
134152type blobs struct {
@@ -435,6 +453,26 @@ func (b *blobs) handle(resp http.ResponseWriter, req *http.Request) *regError {
435453 resp .WriteHeader (http .StatusCreated )
436454 return nil
437455
456+ case http .MethodDelete :
457+ bdh , ok := b .blobHandler .(blobDeleteHandler )
458+ if ! ok {
459+ return regErrUnsupported
460+ }
461+
462+ h , err := v1 .NewHash (target )
463+ if err != nil {
464+ return & regError {
465+ Status : http .StatusBadRequest ,
466+ Code : "NAME_INVALID" ,
467+ Message : "invalid digest" ,
468+ }
469+ }
470+ if err := bdh .Delete (req .Context (), repo , h ); err != nil {
471+ return regErrInternal (err )
472+ }
473+ resp .WriteHeader (http .StatusAccepted )
474+ return nil
475+
438476 default :
439477 return & regError {
440478 Status : http .StatusBadRequest ,
0 commit comments