github.com/containerd/containerd@v22.0.0-20200918172823-438c87b8e050+incompatible/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 Header http.Header 74 } 75 76 func (h RegistryHost) isProxy(refhost string) bool { 77 if refhost != h.Host { 78 if refhost != "docker.io" || h.Host != "registry-1.docker.io" { 79 return true 80 } 81 } 82 return false 83 } 84 85 // RegistryHosts fetches the registry hosts for a given namespace, 86 // provided by the host component of an distribution image reference. 87 type RegistryHosts func(string) ([]RegistryHost, error) 88 89 // Registries joins multiple registry configuration functions, using the same 90 // order as provided within the arguments. When an empty registry configuration 91 // is returned with a nil error, the next function will be called. 92 // NOTE: This function will not join configurations, as soon as a non-empty 93 // configuration is returned from a configuration function, it will be returned 94 // to the caller. 95 func Registries(registries ...RegistryHosts) RegistryHosts { 96 return func(host string) ([]RegistryHost, error) { 97 for _, registry := range registries { 98 config, err := registry(host) 99 if err != nil { 100 return config, err 101 } 102 if len(config) > 0 { 103 return config, nil 104 } 105 } 106 return nil, nil 107 } 108 } 109 110 type registryOpts struct { 111 authorizer Authorizer 112 plainHTTP func(string) (bool, error) 113 host func(string) (string, error) 114 client *http.Client 115 } 116 117 // RegistryOpt defines a registry default option 118 type RegistryOpt func(*registryOpts) 119 120 // WithPlainHTTP configures registries to use plaintext http scheme 121 // for the provided host match function. 122 func WithPlainHTTP(f func(string) (bool, error)) RegistryOpt { 123 return func(opts *registryOpts) { 124 opts.plainHTTP = f 125 } 126 } 127 128 // WithAuthorizer configures the default authorizer for a registry 129 func WithAuthorizer(a Authorizer) RegistryOpt { 130 return func(opts *registryOpts) { 131 opts.authorizer = a 132 } 133 } 134 135 // WithHostTranslator defines the default translator to use for registry hosts 136 func WithHostTranslator(h func(string) (string, error)) RegistryOpt { 137 return func(opts *registryOpts) { 138 opts.host = h 139 } 140 } 141 142 // WithClient configures the default http client for a registry 143 func WithClient(c *http.Client) RegistryOpt { 144 return func(opts *registryOpts) { 145 opts.client = c 146 } 147 } 148 149 // ConfigureDefaultRegistries is used to create a default configuration for 150 // registries. For more advanced configurations or per-domain setups, 151 // the RegistryHosts interface should be used directly. 152 // NOTE: This function will always return a non-empty value or error 153 func ConfigureDefaultRegistries(ropts ...RegistryOpt) RegistryHosts { 154 var opts registryOpts 155 for _, opt := range ropts { 156 opt(&opts) 157 } 158 159 return func(host string) ([]RegistryHost, error) { 160 config := RegistryHost{ 161 Client: opts.client, 162 Authorizer: opts.authorizer, 163 Host: host, 164 Scheme: "https", 165 Path: "/v2", 166 Capabilities: HostCapabilityPull | HostCapabilityResolve | HostCapabilityPush, 167 } 168 169 if config.Client == nil { 170 config.Client = http.DefaultClient 171 } 172 173 if opts.plainHTTP != nil { 174 match, err := opts.plainHTTP(host) 175 if err != nil { 176 return nil, err 177 } 178 if match { 179 config.Scheme = "http" 180 } 181 } 182 183 if opts.host != nil { 184 var err error 185 config.Host, err = opts.host(config.Host) 186 if err != nil { 187 return nil, err 188 } 189 } else if host == "docker.io" { 190 config.Host = "registry-1.docker.io" 191 } 192 193 return []RegistryHost{config}, nil 194 } 195 } 196 197 // MatchAllHosts is a host match function which is always true. 198 func MatchAllHosts(string) (bool, error) { 199 return true, nil 200 } 201 202 // MatchLocalhost is a host match function which returns true for 203 // localhost. 204 func MatchLocalhost(host string) (bool, error) { 205 for _, s := range []string{"localhost", "127.0.0.1", "[::1]"} { 206 if len(host) >= len(s) && host[0:len(s)] == s && (len(host) == len(s) || host[len(s)] == ':') { 207 return true, nil 208 } 209 } 210 return host == "::1", nil 211 212 }