github.com/demonoid81/containerd@v1.3.4/remotes/docker/registry.go (about)

     1  /*
     2     Copyright The containerd Authors.
     3  
     4     Licensed under the Apache License, Version 2.0 (the "License");
     5     you may not use this file except in compliance with the License.
     6     You may obtain a copy of the License at
     7  
     8         http://www.apache.org/licenses/LICENSE-2.0
     9  
    10     Unless required by applicable law or agreed to in writing, software
    11     distributed under the License is distributed on an "AS IS" BASIS,
    12     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13     See the License for the specific language governing permissions and
    14     limitations under the License.
    15  */
    16  
    17  package docker
    18  
    19  import (
    20  	"net/http"
    21  )
    22  
    23  // HostCapabilities represent the capabilities of the registry
    24  // host. This also represents the set of operations for which
    25  // the registry host may be trusted to perform.
    26  //
    27  // For example pushing is a capability which should only be
    28  // performed on an upstream source, not a mirror.
    29  // Resolving (the process of converting a name into a digest)
    30  // must be considered a trusted operation and only done by
    31  // a host which is trusted (or more preferably by secure process
    32  // which can prove the provenance of the mapping). A public
    33  // mirror should never be trusted to do a resolve action.
    34  //
    35  // | Registry Type    | Pull | Resolve | Push |
    36  // |------------------|------|---------|------|
    37  // | Public Registry  | yes  | yes     | yes  |
    38  // | Private Registry | yes  | yes     | yes  |
    39  // | Public Mirror    | yes  | no      | no   |
    40  // | Private Mirror   | yes  | yes     | no   |
    41  type HostCapabilities uint8
    42  
    43  const (
    44  	// HostCapabilityPull represents the capability to fetch manifests
    45  	// and blobs by digest
    46  	HostCapabilityPull HostCapabilities = 1 << iota
    47  
    48  	// HostCapabilityResolve represents the capability to fetch manifests
    49  	// by name
    50  	HostCapabilityResolve
    51  
    52  	// HostCapabilityPush represents the capability to push blobs and
    53  	// manifests
    54  	HostCapabilityPush
    55  
    56  	// Reserved for future capabilities (i.e. search, catalog, remove)
    57  )
    58  
    59  func (c HostCapabilities) Has(t HostCapabilities) bool {
    60  	return c&t == t
    61  }
    62  
    63  // RegistryHost represents a complete configuration for a registry
    64  // host, representing the capabilities, authorizations, connection
    65  // configuration, and location.
    66  type RegistryHost struct {
    67  	Client       *http.Client
    68  	Authorizer   Authorizer
    69  	Host         string
    70  	Scheme       string
    71  	Path         string
    72  	Capabilities HostCapabilities
    73  }
    74  
    75  // RegistryHosts fetches the registry hosts for a given namespace,
    76  // provided by the host component of an distribution image reference.
    77  type RegistryHosts func(string) ([]RegistryHost, error)
    78  
    79  // Registries joins multiple registry configuration functions, using the same
    80  // order as provided within the arguments. When an empty registry configuration
    81  // is returned with a nil error, the next function will be called.
    82  // NOTE: This function will not join configurations, as soon as a non-empty
    83  // configuration is returned from a configuration function, it will be returned
    84  // to the caller.
    85  func Registries(registries ...RegistryHosts) RegistryHosts {
    86  	return func(host string) ([]RegistryHost, error) {
    87  		for _, registry := range registries {
    88  			config, err := registry(host)
    89  			if err != nil {
    90  				return config, err
    91  			}
    92  			if len(config) > 0 {
    93  				return config, nil
    94  			}
    95  		}
    96  		return nil, nil
    97  	}
    98  }
    99  
   100  type registryOpts struct {
   101  	authorizer Authorizer
   102  	plainHTTP  func(string) (bool, error)
   103  	host       func(string) (string, error)
   104  	client     *http.Client
   105  }
   106  
   107  // RegistryOpt defines a registry default option
   108  type RegistryOpt func(*registryOpts)
   109  
   110  // WithPlainHTTP configures registries to use plaintext http scheme
   111  // for the provided host match function.
   112  func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt {
   113  	return func(opts *registryOpts) {
   114  		opts.plainHTTP = f
   115  	}
   116  }
   117  
   118  // WithAuthorizer configures the default authorizer for a registry
   119  func WithAuthorizer(a Authorizer) RegistryOpt {
   120  	return func(opts *registryOpts) {
   121  		opts.authorizer = a
   122  	}
   123  }
   124  
   125  // WithHostTranslator defines the default translator to use for registry hosts
   126  func WithHostTranslator(h func(string) (string, error)) RegistryOpt {
   127  	return func(opts *registryOpts) {
   128  		opts.host = h
   129  	}
   130  }
   131  
   132  // WithClient configures the default http client for a registry
   133  func WithClient(c *http.Client) RegistryOpt {
   134  	return func(opts *registryOpts) {
   135  		opts.client = c
   136  	}
   137  }
   138  
   139  // ConfigureDefaultRegistries is used to create a default configuration for
   140  // registries. For more advanced configurations or per-domain setups,
   141  // the RegistryHosts interface should be used directly.
   142  // NOTE: This function will always return a non-empty value or error
   143  func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts {
   144  	var opts registryOpts
   145  	for _, opt := range ropts {
   146  		opt(&opts)
   147  	}
   148  
   149  	return func(host string) ([]RegistryHost, error) {
   150  		config := RegistryHost{
   151  			Client:       opts.client,
   152  			Authorizer:   opts.authorizer,
   153  			Host:         host,
   154  			Scheme:       "https",
   155  			Path:         "/v2",
   156  			Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush,
   157  		}
   158  
   159  		if config.Client == nil {
   160  			config.Client = http.DefaultClient
   161  		}
   162  
   163  		if opts.plainHTTP != nil {
   164  			match, err := opts.plainHTTP(host)
   165  			if err != nil {
   166  				return nil, err
   167  			}
   168  			if match {
   169  				config.Scheme = "http"
   170  			}
   171  		}
   172  
   173  		if opts.host != nil {
   174  			var err error
   175  			config.Host, err = opts.host(config.Host)
   176  			if err != nil {
   177  				return nil, err
   178  			}
   179  		} else if host == "docker.io" {
   180  			config.Host = "registry-1.docker.io"
   181  		}
   182  
   183  		return []RegistryHost{config}, nil
   184  	}
   185  }
   186  
   187  // MatchAllHosts is a host match function which is always true.
   188  func MatchAllHosts(string) (bool, error) {
   189  	return true, nil
   190  }
   191  
   192  // MatchLocalhost is a host match function which returns true for
   193  // localhost.
   194  func MatchLocalhost(host string) (bool, error) {
   195  	for _, s := range []string{"localhost", "127.0.0.1", "[::1]"} {
   196  		if len(host) >= len(s) && host[0:len(s)] == s && (len(host) == len(s) || host[len(s)] == ':') {
   197  			return true, nil
   198  		}
   199  	}
   200  	return host == "::1", nil
   201  
   202  }