Help us shape the future of Go! Take the 2026 Go Developer Survey

docker

package
v0.1.0 Latest Latest
Warning

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

Go to latest
Published: Oct 19, 2026 License: MIT Imports: 32 Imported by: 0

Documentation

Overview

Package docker serves the registry protocol, the OCI Distribution Specification v1.1 with Docker's extensions, for docker, oci and helmoci repositories (decisions 0003 and 0031). It answers three addressing forms:

  • the repository path, /v2/<repo>/<image>/..., the native default, which needs no reverse proxy;
  • Artifactory's own prefix, /artifactory/api/docker/<repo>/v2/<image>/...;
  • the subdomain, <repo>.<base_url host>/v2/<image>/..., when docker.subdomain_match is on.

The router is hand-written and mounted before the generated servers (decision 0002). It parses each path into a Request and hands it to the endpoint a feature registered for its kind and method; an operation the specification defines that no feature has registered yet answers 405 UNSUPPORTED. This package never imports internal/server.

Index

Constants

View Source
const (
	CodeBlobUnknown         = "BLOB_UNKNOWN"
	CodeBlobUploadInvalid   = "BLOB_UPLOAD_INVALID"
	CodeBlobUploadUnknown   = "BLOB_UPLOAD_UNKNOWN"
	CodeDigestInvalid       = "DIGEST_INVALID"
	CodeManifestBlobUnknown = "MANIFEST_BLOB_UNKNOWN"
	CodeManifestInvalid     = "MANIFEST_INVALID"
	CodeManifestUnknown     = "MANIFEST_UNKNOWN"
	CodeNameInvalid         = "NAME_INVALID"
	CodeNameUnknown         = "NAME_UNKNOWN"
	CodeSizeInvalid         = "SIZE_INVALID"
	CodeUnauthorized        = "UNAUTHORIZED"
	CodeDenied              = "DENIED"
	CodeUnsupported         = "UNSUPPORTED"
	CodeTooManyRequests     = "TOOMANYREQUESTS"
	// CodeTagInvalid is the one code outside the specification's list: a
	// push to a tag that would collide with the layout's own folders
	// (decision 0031).
	CodeTagInvalid = "TAG_INVALID"
)

The error codes of the OCI Distribution Specification v1.1 (code-1 to code-14). Docker clients branch on the code, not the message, so every registry error carries one of these.

View Source
const (
	APIVersionHeader = "Docker-Distribution-API-Version"
)

APIVersionHeader is the header every registry response carries. Docker clients read it from the /v2/ probe, the 401 included, to know that they reached a v2 registry.

View Source
const RegistryHeader = "X-Artifactory-Docker-Registry"

RegistryHeader names, on a manifest read, the repository that holds the manifest, by its stored key. jf docker push and pull HEAD the manifest through the registry after the docker client finishes and read the key from here; without it they fail before collecting build-info (jfrog-cli-artifactory ocicontainer/image.go, GetRemoteRepo).

Variables

This section is empty.

Functions

func APIVersion

func APIVersion(next http.Handler) http.Handler

APIVersion sets the version header on every registry response, before authentication can answer one.

func ChallengesAnonymous

func ChallengesAnonymous(path string) bool

ChallengesAnonymous reports whether a request to path without credentials is challenged even while anonymous access is on: every registry path but the token endpoint, from which an anonymous client fetches the anonymous token it then pulls with (decision 0031).

func Errorf

func Errorf(status int, code, format string, args ...any) *apierror.Error

Errorf builds a registry error: the status, the specification's code and a message for people. Write renders it in the OCI envelope.

func GrantsCatalog

func GrantsCatalog(r *http.Request) bool

GrantsCatalog reports whether the request's credential may list the catalog: any but a registry token without registry:catalog:*.

func IsRegistryPath

func IsRegistryPath(path string) bool

IsRegistryPath reports whether path is under /v2 or a repository's /artifactory/api/docker/<repo>/v2.

func Lookup

func Lookup(ctx context.Context, st store.Store, key string) (repo.Config, bool, error)

Lookup finds the Docker, OCI or Helm OCI repository key names in st, compared without regard to case: keys are unique that way, and Docker clients send references in lower case only (decision 0003). found is false for a missing repository and for one of another package type.

func Serves

func Serves(t repo.PackageType) bool

Serves reports whether the registry serves repositories of package type t: docker, and the oci and helmoci types that share its protocol (research 04).

func ValidName

func ValidName(name string) bool

ValidName reports whether name is a valid image name.

func Write

func Write(w http.ResponseWriter, err error)

Write renders err in the OCI envelope. An error that is not an *apierror.Error becomes a 500 without its detail, as everywhere else.

func WriteAll

func WriteAll(w http.ResponseWriter, status int, errs ...*apierror.Error)

WriteAll renders several errors in one OCI envelope with status, as for a manifest that references more than one unknown blob: clients report each code and detail.

Types

type Endpoint

type Endpoint func(w http.ResponseWriter, r *http.Request, q Request)

Endpoint serves one registry operation for a parsed request.

type Kind

type Kind int

Kind is the registry operation a path addresses, before its method picks the endpoint.

const (
	// KindBase is the empty path, the version probe clients send first.
	KindBase Kind = iota + 1
	// KindCatalog is _catalog, Docker's listing of image names: of every
	// repository the caller can read on the repository path, of one
	// repository under a subdomain, as <repo>/_catalog or under the
	// Artifactory prefix (decision 0003).
	KindCatalog
	// KindToken is token, the registry token endpoint.
	KindToken
	// KindAuth is auth under the Artifactory prefix, which answers the
	// config.json entry.
	KindAuth
	// KindBlob is <name>/blobs/<digest>.
	KindBlob
	// KindUploads is <name>/blobs/uploads/, which starts an upload.
	KindUploads
	// KindUpload is <name>/blobs/uploads/<session>, one upload in progress.
	KindUpload
	// KindManifest is <name>/manifests/<tag or digest>.
	KindManifest
	// KindTags is <name>/tags/list.
	KindTags
	// KindReferrers is <name>/referrers/<digest>.
	KindReferrers
)

The kinds of registry path. Their comments show the path below /v2/, where <name> is the image name and, on the repository-path method, begins with the repository key.

func (Kind) String

func (k Kind) String() string

String names the kind as an operation, for messages.

type Options

type Options struct {
	// Store resolves repositories. Nil serves no repository, for tests of
	// the router alone.
	Store store.Store
	// SubdomainMatch turns on the subdomain method. BaseURL must then be
	// set: its host is the parent the repository subdomains sit under.
	SubdomainMatch bool
	BaseURL        string
	// Fault records an unexpected error for the access log, as the server's
	// handlers do; nil drops it.
	Fault func(*http.Request, error)
	// Blobs is the blob store behind Store. Nil leaves blobs and uploads
	// unimplemented, for tests of the router alone.
	Blobs blob.Store
	// ServeBlob answers a GET of a blob's item in a repository with the
	// server's download, which applies the download redirect policy
	// (decision 0029) and counts the download. Nil streams it from Blobs.
	ServeBlob func(w http.ResponseWriter, r *http.Request, c repo.Config, it types.Item)
	// RedirectManifest answers a GET of a manifest's item, whose media type
	// is mediaType, with the server's download redirect when the policy says
	// so (decision 0029), and reports whether it wrote a response. Nil
	// streams every manifest.
	RedirectManifest func(
		w http.ResponseWriter, r *http.Request, c repo.Config, it types.Item, mediaType string,
	) bool
	// Now supplies the time to upload sessions; nil means time.Now.
	Now func() time.Time
	// Tokens signs registry tokens; nil leaves the token endpoint
	// unimplemented.
	Tokens TokenIssuer
}

Options configures a Registry.

type Registry

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

Registry routes registry requests to the endpoints features register.

func New

func New(o Options) *Registry

New returns the registry with every implemented endpoint registered.

func (*Registry) Challenge

func (g *Registry) Challenge(next http.Handler) http.Handler

Challenge gives every 401 from the registry the Bearer challenge Docker clients follow to the token endpoint (decision 0005), whoever wrote it: the authentication middleware, a handler's Require, or a later feature. A 401 written with apierror's default Basic challenge, or none, gets the registry's; one a handler challenged itself (a mount's second scope) keeps its own. It must run after the base-URL middleware.

func (*Registry) Register

func (g *Registry) Register(r chi.Router)

Register mounts the registry on r for every method, so that the registry answers 405 itself, in its own envelope. Under the Artifactory prefix chi prefers the generated JFrog operations' literal segments (POST parentManifests, POST promote, DELETE delete) to these catch-alls, so those keep their generated handlers (decision 0003). The JFrog catalog and tags list are the registry's own operations, marked x-handwritten in the specification; they are registered under the patterns the specification gives them as well, so that the server's stubs for unimplemented hand-written operations never claim them.

type Request

type Request struct {
	Kind Kind
	// RepoKey is the repository the request addressed: the subdomain, or
	// the key in /artifactory/api/docker/<key>/v2. It is empty for /v2/,
	// /v2/_catalog and /v2/token on the repository path, which address no
	// repository, and may be "null", which the token realm uses for that
	// (research 17). Only an operation on an image resolves it into Repo.
	RepoKey string
	// Repo is the resolved repository, set when Kind is an image operation.
	Repo repo.Config
	// Name is the image name inside the repository.
	Name string
	// Reference is the digest, tag or upload session the path ends in.
	Reference string
	// contains filtered or unexported fields
}

Request is a registry request with its operation parsed and, for an operation on an image, its repository resolved and its name validated.

func (Request) Path

func (q Request) Path(segments ...string) string

Path returns the absolute path of an operation on the request's image in the addressing form the client used, for Location headers: the client may only know the registry by that form. Path("blobs", "uploads", id) is .../<name>/blobs/uploads/<id>.

func (Request) Require

func (q Request) Require(r *http.Request, path string, want types.Actions) error

Require answers nil when the caller holds every action in want on path, a path inside the repository. Otherwise it answers what the registry tells a client: UNAUTHORIZED to an anonymous caller, so that it sends credentials, and DENIED to anyone else. A registry token must also grant the actions for the image as this request names it; one that does not gets UNAUTHORIZED, whose challenge (Challenge) names the scope the client then fetches a token for, as Docker's registry answers an insufficient scope. A request without a principal reached the handler only on a server built without authentication, which only tests build, and is allowed.

type TokenIssuer

type TokenIssuer interface {
	IssueRegistry(ctx context.Context, r token.RegistryRequest) (token.Issued, error)
}

TokenIssuer signs registry tokens; internal/auth/token implements it.

Jump to

Keyboard shortcuts

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