Files
mstore/app/handler/blob.go
T
2026-02-07 14:10:54 +02:00

185 lines
4.8 KiB
Go

/*
* Copyright 2026 Oleg Borodin <onborodin@gmail.com>
*
* This work is published and licensed under a Creative Commons
* Attribution-NonCommercial-NoDerivatives 4.0 International License.
*
* Distribution of this work is permitted, but commercial use and
* modifications are strictly prohibited.
*/
package handler
import (
"io"
"net/http"
"mstore/app/operator"
"mstore/app/router"
)
// HEAD /v2/<name>/blobs/<digest> 200 404
func (hand *Handler) BlobExists(rctx *router.Context) {
name, _ := rctx.GetSubpath("name")
digest, _ := rctx.GetSubpath("digest")
hand.DumpHeaders("BlobExists", rctx)
params := &operator.BlobExistsParams{
Name: name,
Digest: digest,
}
ctx := rctx.GetContext()
res, code, err := hand.oper.BlobExists(ctx, params)
if err != nil {
hand.logg.Errorf("BlobExist error: %v", err)
}
if code == http.StatusOK {
rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest)
rctx.SetHeader("Content-Length", res.ContentLength)
rctx.SetHeader("Content-Type", res.ContentType)
}
rctx.SetStatus(code)
}
// POST /v2/<name>/blobs/uploads/ 202 404
func (hand *Handler) PostUpload(rctx *router.Context) {
name, _ := rctx.GetSubpath("name")
digest := rctx.GetQuery("digest")
mount := rctx.GetQuery("mount")
from := rctx.GetQuery("from")
params := &operator.PostUploadParams{
Name: name,
Digest: digest,
Mount: mount,
From: from,
}
res, code, err := hand.oper.PostUpload(rctx.Ctx, params)
if err != nil {
hand.logg.Errorf("PostUpload error: %v", err)
} else {
rctx.SetHeader("Location", res.Location)
rctx.SetHeader("Content-Length", res.ContentLength)
rctx.SetHeader("Docker-Upload-UUID", res.DockerUploadUUID)
}
rctx.SetStatus(code)
}
// POST /v2/<name>/blobs/uploads/?digest=<digest> 201/202 404/400
// POST /v2/<name>/blobs/uploads/?mount=<digest>&from=<other_name> 201 404
// PATCH /v2/<name>/blobs/uploads/<reference> 202 404/416
func (hand *Handler) PatchUpload(rctx *router.Context) {
contentLength := rctx.GetHeader("Content-Length")
contentType := rctx.GetHeader("Content-Type")
contentRange := rctx.GetHeader("Content-Range")
name, _ := rctx.GetSubpath("name")
reference, _ := rctx.GetSubpath("reference")
reader := rctx.Request.Body
params := &operator.PatchUploadParams{
ContentLength: contentLength,
ContentType: contentType,
ContentRange: contentRange,
Name: name,
Reference: reference,
Reader: reader,
}
ctx := rctx.GetContext()
res, code, err := hand.oper.PatchUpload(ctx, params)
if err != nil {
hand.logg.Errorf("PatchUpload error: %v", err)
}
rctx.SetHeader("Location", res.Location)
rctx.SetHeader("Range", res.Range)
rctx.SetStatus(code)
}
// PUT /v2/<name>/blobs/uploads/<reference>?digest=<digest> 202 404/416
// PUT /v2/<name>/uploads/<reference>?digest=<digest> 202 404/416
func (hand *Handler) PutUpload(rctx *router.Context) {
contentType := rctx.GetHeader("Content-Type")
contentLength := rctx.GetHeader("Content-Length")
contentRange := rctx.GetHeader("Content-Range")
name, _ := rctx.GetSubpath("name")
reference, _ := rctx.GetSubpath("reference")
digest := rctx.GetQuery("digest")
params := &operator.PutUploadParams{
ContentLength: contentLength,
ContentType: contentType,
ContentRange: contentRange,
Name: name,
Reference: reference,
Digest: digest,
}
res, code, err := hand.oper.PutUpload(rctx.Ctx, params)
if err != nil {
hand.logg.Errorf("PutUpload error: %v", err)
}
rctx.SetHeader("Location", res.Location)
rctx.SetStatus(code)
}
// GET /v2/<name>/blobs/<digest> 200 404
func (hand *Handler) GetBlob(rctx *router.Context) {
name, _ := rctx.GetSubpath("name")
digest, _ := rctx.GetSubpath("digest")
params := &operator.GetBlobParams{
Name: name,
Digest: digest,
}
ctx := rctx.GetContext()
res, code, err := hand.oper.GetBlob(ctx, params)
if err != nil {
hand.logg.Errorf("GetBlob error: %v", err)
}
if code == http.StatusOK {
rctx.SetHeader("Content-Length", res.ContentLength)
rctx.SetHeader("Content-Type", res.ContentType)
rctx.SetHeader("Docker-Content-Digest", res.DockerContentDigest)
rctx.SetStatus(code)
defer res.ReadCloser.Close()
_, err = io.Copy(rctx.Writer, res.ReadCloser)
if err != nil {
hand.logg.Errorf("GetFile error: %v", err)
rctx.SetStatus(http.StatusInternalServerError)
return
}
return
}
rctx.SetStatus(code)
}
// DELETE /v2/<name>/blobs/<digest> 202 404/405
func (hand *Handler) DeleteBlob(rctx *router.Context) {
name, _ := rctx.GetSubpath("name")
digest, _ := rctx.GetSubpath("digest")
params := &operator.DeleteBlobParams{
Name: name,
Digest: digest,
}
ctx := rctx.GetContext()
_, code, err := hand.oper.DeleteBlob(ctx, params)
if err != nil {
hand.logg.Errorf("DeleteBlob error: %v", err)
}
rctx.SetStatus(code)
}