...

Source file src/github.com/google/go-containerregistry/pkg/registry/registry.go

Documentation: github.com/google/go-containerregistry/pkg/registry

     1  // Copyright 2018 Google LLC All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  // Package registry implements a docker V2 registry and the OCI distribution specification.
    16  //
    17  // It is designed to be used anywhere a low dependency container registry is needed, with an
    18  // initial focus on tests.
    19  //
    20  // Its goal is to be standards compliant and its strictness will increase over time.
    21  //
    22  // This is currently a low flightmiles system. It's likely quite safe to use in tests; If you're using it
    23  // in production, please let us know how and send us CL's for integration tests.
    24  package registry
    25  
    26  import (
    27  	"fmt"
    28  	"log"
    29  	"math/rand"
    30  	"net/http"
    31  	"os"
    32  )
    33  
    34  type registry struct {
    35  	log              *log.Logger
    36  	blobs            blobs
    37  	manifests        manifests
    38  	referrersEnabled bool
    39  	warnings         map[float64]string
    40  }
    41  
    42  // https://docs.docker.com/registry/spec/api/#api-version-check
    43  // https://github.com/opencontainers/distribution-spec/blob/master/spec.md#api-version-check
    44  func (r *registry) v2(resp http.ResponseWriter, req *http.Request) *regError {
    45  	if r.warnings != nil {
    46  		rnd := rand.Float64()
    47  		for prob, msg := range r.warnings {
    48  			if prob > rnd {
    49  				resp.Header().Add("Warning", fmt.Sprintf(`299 - "%s"`, msg))
    50  			}
    51  		}
    52  	}
    53  
    54  	if isBlob(req) {
    55  		return r.blobs.handle(resp, req)
    56  	}
    57  	if isManifest(req) {
    58  		return r.manifests.handle(resp, req)
    59  	}
    60  	if isTags(req) {
    61  		return r.manifests.handleTags(resp, req)
    62  	}
    63  	if isCatalog(req) {
    64  		return r.manifests.handleCatalog(resp, req)
    65  	}
    66  	if r.referrersEnabled && isReferrers(req) {
    67  		return r.manifests.handleReferrers(resp, req)
    68  	}
    69  	resp.Header().Set("Docker-Distribution-API-Version", "registry/2.0")
    70  	if req.URL.Path != "/v2/" && req.URL.Path != "/v2" {
    71  		return &regError{
    72  			Status:  http.StatusNotFound,
    73  			Code:    "METHOD_UNKNOWN",
    74  			Message: "We don't understand your method + url",
    75  		}
    76  	}
    77  	resp.WriteHeader(200)
    78  	return nil
    79  }
    80  
    81  func (r *registry) root(resp http.ResponseWriter, req *http.Request) {
    82  	if rerr := r.v2(resp, req); rerr != nil {
    83  		r.log.Printf("%s %s %d %s %s", req.Method, req.URL, rerr.Status, rerr.Code, rerr.Message)
    84  		rerr.Write(resp)
    85  		return
    86  	}
    87  	r.log.Printf("%s %s", req.Method, req.URL)
    88  }
    89  
    90  // New returns a handler which implements the docker registry protocol.
    91  // It should be registered at the site root.
    92  func New(opts ...Option) http.Handler {
    93  	r := &registry{
    94  		log: log.New(os.Stderr, "", log.LstdFlags),
    95  		blobs: blobs{
    96  			blobHandler: &memHandler{m: map[string][]byte{}},
    97  			uploads:     map[string][]byte{},
    98  			log:         log.New(os.Stderr, "", log.LstdFlags),
    99  		},
   100  		manifests: manifests{
   101  			manifests: map[string]map[string]manifest{},
   102  			log:       log.New(os.Stderr, "", log.LstdFlags),
   103  		},
   104  	}
   105  	for _, o := range opts {
   106  		o(r)
   107  	}
   108  	return http.HandlerFunc(r.root)
   109  }
   110  
   111  // Option describes the available options
   112  // for creating the registry.
   113  type Option func(r *registry)
   114  
   115  // Logger overrides the logger used to record requests to the registry.
   116  func Logger(l *log.Logger) Option {
   117  	return func(r *registry) {
   118  		r.log = l
   119  		r.manifests.log = l
   120  		r.blobs.log = l
   121  	}
   122  }
   123  
   124  // WithReferrersSupport enables the referrers API endpoint (OCI 1.1+)
   125  func WithReferrersSupport(enabled bool) Option {
   126  	return func(r *registry) {
   127  		r.referrersEnabled = enabled
   128  	}
   129  }
   130  
   131  func WithWarning(prob float64, msg string) Option {
   132  	return func(r *registry) {
   133  		if r.warnings == nil {
   134  			r.warnings = map[float64]string{}
   135  		}
   136  		r.warnings[prob] = msg
   137  	}
   138  }
   139  
   140  func WithBlobHandler(h BlobHandler) Option {
   141  	return func(r *registry) {
   142  		r.blobs.blobHandler = h
   143  	}
   144  }
   145  

View as plain text