registry

package
v0.1.2 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 17, 2026 License: BSD-3-Clause Imports: 28 Imported by: 0

Documentation

Overview

Package registry implements an OCI Distribution Specification v1.1 compliant registry.

The registry supports the full OCI Distribution Spec including:

  • Pull workflow (required)
  • Push workflow
  • Content management
  • Manifest and blob storage
  • OCI-compliant error responses
  • HTTP compression for data transfer (zstd, gzip, deflate)

Compression Support

The registry supports bidirectional compression for both requests and responses.

## Response Compression (Downloads)

The registry automatically compresses blob and manifest responses when clients include an Accept-Encoding header. Supported compression algorithms:

  • zstd (Zstandard) - preferred for best compression ratio
  • gzip - widely supported, good compression
  • deflate - basic compression support

The registry negotiates compression based on client preferences expressed via quality values in the Accept-Encoding header. When multiple encodings are acceptable, the registry prefers zstd > gzip > deflate.

Examples:

Accept-Encoding: gzip
Accept-Encoding: zstd, gzip;q=0.9, deflate;q=0.8
Accept-Encoding: *

Compression is applied transparently to GET requests for:

  • Manifests (/v2/<repo>/manifests/<reference>)
  • Blobs (/v2/<repo>/blobs/<digest>)

When compression is used, the response includes:

  • Content-Encoding header indicating the algorithm
  • Vary: Accept-Encoding header for cache control
  • Content-Length header is removed (chunked transfer encoding used)

## Request Decompression (Uploads)

The registry automatically decompresses incoming request bodies when clients send a Content-Encoding header. This is useful for reducing upload bandwidth.

Supported encodings for uploads:

  • zstd, gzip, deflate

Example:

Content-Encoding: gzip

Request decompression is supported for:

  • Manifest uploads (PUT /v2/<repo>/manifests/<reference>)
  • Blob chunk uploads (PATCH /v2/<repo>/blobs/uploads/<uuid>)
  • Blob upload completion (PUT /v2/<repo>/blobs/uploads/<uuid>)

Spec: https://github.com/opencontainers/distribution-spec/blob/main/spec.md

Index

Constants

View Source
const (
	// ErrCodeBlobUnknown indicates blob is unknown to the registry
	ErrCodeBlobUnknown = "BLOB_UNKNOWN"
	// ErrCodeBlobUploadInvalid indicates blob upload is invalid
	ErrCodeBlobUploadInvalid = "BLOB_UPLOAD_INVALID"
	// ErrCodeBlobUploadUnknown indicates blob upload session is unknown
	ErrCodeBlobUploadUnknown = "BLOB_UPLOAD_UNKNOWN"
	// ErrCodeDigestInvalid indicates provided digest did not match uploaded content
	ErrCodeDigestInvalid = "DIGEST_INVALID"
	// ErrCodeManifestBlobUnknown indicates blob unknown to registry
	ErrCodeManifestBlobUnknown = "MANIFEST_BLOB_UNKNOWN"
	// ErrCodeManifestInvalid indicates manifest is invalid
	ErrCodeManifestInvalid = "MANIFEST_INVALID"
	// ErrCodeManifestUnknown indicates manifest is unknown
	ErrCodeManifestUnknown = "MANIFEST_UNKNOWN"
	// ErrCodeNameInvalid indicates invalid repository name
	ErrCodeNameInvalid = "NAME_INVALID"
	// ErrCodeNameUnknown indicates repository name not known
	ErrCodeNameUnknown = "NAME_UNKNOWN"
	// ErrCodeSizeInvalid indicates provided length did not match content length
	ErrCodeSizeInvalid = "SIZE_INVALID"
	// ErrCodeUnauthorized indicates authentication required
	ErrCodeUnauthorized = "UNAUTHORIZED"
	// ErrCodeDenied indicates requested access denied
	ErrCodeDenied = "DENIED"
	// ErrCodeUnsupported indicates operation is unsupported
	ErrCodeUnsupported = "UNSUPPORTED"
	// ErrCodeTooManyRequests indicates too many requests
	ErrCodeTooManyRequests = "TOOMANYREQUESTS"
)

Error codes defined by OCI Distribution Specification

Variables

View Source
var (
	// ErrBlobNotFound indicates the blob was not found in storage
	ErrBlobNotFound = errors.New("blob not found")
	// ErrManifestNotFound indicates the manifest was not found
	ErrManifestNotFound = errors.New("manifest not found")
	// ErrDigestMismatch indicates the digest does not match the content
	ErrDigestMismatch = errors.New("digest mismatch")
)

Functions

func BasePath

func BasePath() string

BasePath returns the base path for registry URLs.

func BlobPath

func BlobPath(repo, digest string) string

BlobPath returns the path for a blob.

func ListenAndServe

func ListenAndServe(addr string, storage Storage) error

ListenAndServe starts the registry HTTP server.

func ManifestPath

func ManifestPath(repo, reference string) string

ManifestPath returns the path for a manifest.

func NewHandler

func NewHandler(storage Storage) http.Handler

NewHandler creates a new HTTP handler for the registry.

func ParseRepositoryName

func ParseRepositoryName(repo string) (domain, path string)

ParseRepositoryName parses a repository name and returns the normalized domain and path. It handles Docker Hub conventions and various repository name formats.

Examples:

  • "nginx" -> "docker.io", "library/nginx"
  • "user/app" -> "docker.io", "user/app"
  • "registry.example.com/user/app" -> "registry.example.com", "user/app"
  • "registry.example.com/app" -> "registry.example.com", "app"

func WriteError

func WriteError(w http.ResponseWriter, statusCode int, code, message string, detail any)

WriteError writes an OCI-compliant error response.

Types

type ContainerdCacheStorage

type ContainerdCacheStorage struct {
	// contains filtered or unexported fields
}

ContainerdCacheStorage implements Storage using containerd's content and metadata stores. It works with Docker daemons configured with the containerd snapshotter. All blobs (layers, configs, manifests) are stored in containerd's content store, and images are registered in containerd's metadata store so they appear in `docker images` and `ctr images list`.

This storage backend requires a running containerd daemon and registers all pushed images in the "moby" namespace (Docker's default namespace).

func NewContainerdCacheStorage

func NewContainerdCacheStorage(containerdSocket string) (*ContainerdCacheStorage, error)

NewContainerdCacheStorage creates a new Docker cache-based storage. containerdSocket is the path to containerd's socket (e.g., /run/containerd/containerd.sock).

This requires a running containerd daemon. Images pushed to the registry will be automatically registered in containerd's metadata and will appear in `docker images` and `ctr -n moby images list`.

func (*ContainerdCacheStorage) AbortUpload

func (s *ContainerdCacheStorage) AbortUpload(ctx context.Context, uuid string) error

AbortUpload removes an upload session.

func (*ContainerdCacheStorage) BlobExists

func (s *ContainerdCacheStorage) BlobExists(ctx context.Context, dg string) bool

BlobExists checks if a blob exists in Docker's cache.

func (*ContainerdCacheStorage) BlobSize

func (s *ContainerdCacheStorage) BlobSize(ctx context.Context, dg string) (int64, error)

BlobSize returns the size of a blob by digest.

func (*ContainerdCacheStorage) Close

func (s *ContainerdCacheStorage) Close() error

Close closes the containerd client connection.

func (*ContainerdCacheStorage) CompleteUpload

func (s *ContainerdCacheStorage) CompleteUpload(ctx context.Context, uuid, expectedDigest string) (dg string, err error)

CompleteUpload saves an upload session.

func (*ContainerdCacheStorage) CopyChunk

func (s *ContainerdCacheStorage) CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)

CopyChunk copies a chunk to an upload session.

func (*ContainerdCacheStorage) DeleteBlob

func (s *ContainerdCacheStorage) DeleteBlob(ctx context.Context, dg string) error

DeleteBlob removes a blob from Docker's image cache.

func (*ContainerdCacheStorage) DeleteManifest

func (s *ContainerdCacheStorage) DeleteManifest(ctx context.Context, repo, reference string) error

DeleteManifest removes a manifest from containerd.

func (*ContainerdCacheStorage) GetBlob

GetBlob retrieves a blob by digest from Docker's image cache as a stream.

func (*ContainerdCacheStorage) GetManifest

func (s *ContainerdCacheStorage) GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)

GetManifest retrieves a manifest from containerd's metadata store.

func (*ContainerdCacheStorage) GetUpload

func (s *ContainerdCacheStorage) GetUpload(_ context.Context, uuid string) (*UploadSession, error)

GetUpload retrieves an upload session.

func (*ContainerdCacheStorage) ManifestExists

func (s *ContainerdCacheStorage) ManifestExists(ctx context.Context, repo, reference string) bool

ManifestExists checks if a manifest exists in containerd's metadata.

func (*ContainerdCacheStorage) NewUpload

NewUpload creates a new upload session.

func (*ContainerdCacheStorage) PutManifest

func (s *ContainerdCacheStorage) PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (_ string, err error)

PutManifest stores a manifest in containerd's content store and registers the image.

type ErrorDescriptor

type ErrorDescriptor struct {
	Code    string `json:"code"`
	Message string `json:"message"`
	Detail  any    `json:"detail,omitempty"`
}

ErrorDescriptor represents an OCI registry error.

func NewError

func NewError(code, message string) ErrorDescriptor

NewError creates a new error descriptor.

func (ErrorDescriptor) Error

func (e ErrorDescriptor) Error() string

Error implements the error interface.

type ErrorResponse

type ErrorResponse struct {
	Errors []ErrorDescriptor `json:"errors"`
}

ErrorResponse represents the OCI-compliant error response format.

type FilesystemStorage

type FilesystemStorage struct {
	// contains filtered or unexported fields
}

FilesystemStorage implements Storage using the filesystem.

func NewFilesystemStorage

func NewFilesystemStorage(rootDir string) (*FilesystemStorage, error)

NewFilesystemStorage creates a new filesystem-based storage.

func (*FilesystemStorage) AbortUpload

func (s *FilesystemStorage) AbortUpload(ctx context.Context, uuid string) error

AbortUpload removes an upload session.

func (*FilesystemStorage) BlobExists

func (s *FilesystemStorage) BlobExists(ctx context.Context, digest string) bool

BlobExists checks if a blob exists.

func (*FilesystemStorage) BlobSize

func (s *FilesystemStorage) BlobSize(ctx context.Context, digest string) (int64, error)

BlobSize returns the size of a blob by digest.

func (*FilesystemStorage) CompleteUpload

func (s *FilesystemStorage) CompleteUpload(ctx context.Context, uuid, expectedDigest string) (string, error)

func (*FilesystemStorage) CopyChunk

func (s *FilesystemStorage) CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)

func (*FilesystemStorage) DeleteBlob

func (s *FilesystemStorage) DeleteBlob(ctx context.Context, digest string) error

DeleteBlob removes a blob.

func (*FilesystemStorage) DeleteManifest

func (s *FilesystemStorage) DeleteManifest(ctx context.Context, repo, reference string) error

DeleteManifest removes a manifest.

func (*FilesystemStorage) GetBlob

func (s *FilesystemStorage) GetBlob(ctx context.Context, digest string) (io.ReadCloser, error)

GetBlob retrieves a blob by digest as a stream.

func (*FilesystemStorage) GetManifest

func (s *FilesystemStorage) GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)

GetManifest retrieves a manifest for a repository and reference.

func (*FilesystemStorage) GetUpload

func (s *FilesystemStorage) GetUpload(ctx context.Context, uuid string) (*UploadSession, error)

GetUpload retrieves an upload session.

func (*FilesystemStorage) ManifestExists

func (s *FilesystemStorage) ManifestExists(ctx context.Context, repo, reference string) bool

ManifestExists checks if a manifest exists.

func (*FilesystemStorage) NewUpload

func (s *FilesystemStorage) NewUpload(ctx context.Context) (*UploadSession, error)

func (*FilesystemStorage) PutManifest

func (s *FilesystemStorage) PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (string, error)

PutManifest stores a manifest for a repository and reference.

type ManifestMetadata

type ManifestMetadata struct {
	MediaType string
	Digest    string
	Size      int64
	Data      io.ReadCloser
}

type PathType

type PathType int

PathType represents the type of registry operation

const (
	PathTypeUnknown PathType = iota
	PathTypeManifest
	PathTypeBlob
	PathTypeBlobUploadInit
	PathTypeBlobUpload
	PathTypeTagsList
)

func (PathType) String

func (pt PathType) String() string

type Registry

type Registry struct {
	// contains filtered or unexported fields
}

Registry implements an OCI Distribution Specification v1.1 compliant registry.

func New

func New(storage Storage) *Registry

New creates a new OCI-compliant registry with the given storage backend.

func (*Registry) ServeHTTP

func (r *Registry) ServeHTTP(w http.ResponseWriter, req *http.Request)

ServeHTTP implements http.Handler for the registry.

type RegistryPath

type RegistryPath struct {
	Type      PathType
	Repo      string
	Reference string // For manifests: tag or digest; for blobs: digest; for uploads: uuid
}

RegistryPath holds the parsed components of a registry path

func ParseRegistryPath

func ParseRegistryPath(path string) (*RegistryPath, error)

ParseRegistryPath parses a Docker Registry V2 API path

type Storage

type Storage interface {
	// GetBlob retrieves a blob by digest as a stream
	GetBlob(ctx context.Context, digest string) (io.ReadCloser, error)
	// BlobSize returns the size of a blob by digest.
	BlobSize(ctx context.Context, digest string) (int64, error)
	// BlobExists checks if a blob exists
	BlobExists(ctx context.Context, digest string) bool
	// DeleteBlob removes a blob
	DeleteBlob(ctx context.Context, digest string) error

	// GetManifest retrieves a manifest for a repository and reference as a stream
	GetManifest(ctx context.Context, repo, reference string) (*ManifestMetadata, error)
	// PutManifest stores a manifest for a repository and reference
	PutManifest(ctx context.Context, repo, reference string, data []byte, mediaType string) (digest string, err error)
	// ManifestExists checks if a manifest exists
	ManifestExists(ctx context.Context, repo, reference string) bool
	// DeleteManifest removes a manifest
	DeleteManifest(ctx context.Context, repo, reference string) error

	// NewUpload creates a new upload session
	NewUpload(ctx context.Context) (*UploadSession, error)
	// GetUpload retrieves an upload session
	GetUpload(ctx context.Context, uuid string) (*UploadSession, error)
	// CopyChunk copies a chunk to an upload session
	CopyChunk(ctx context.Context, uuid string, r io.Reader) (*UploadSession, error)
	// CompleteUpload saves an upload session
	CompleteUpload(ctx context.Context, uuid, expectedDigest string) (string, error)
	// AbortUpload removes an upload session
	AbortUpload(ctx context.Context, uuid string) error
}

Storage provides content-addressable storage for registry blobs and manifests.

type UploadSession

type UploadSession struct {
	UUID    string
	Written int64
}

UploadSession represents an ongoing blob upload.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL