github.com/Prakhar-Agarwal-byte/moby@v0.0.0-20231027092010-a14e3e8ab87e/distribution/registry.go (about) 1 package distribution // import "github.com/Prakhar-Agarwal-byte/moby/distribution" 2 3 import ( 4 "context" 5 "fmt" 6 "net" 7 "net/http" 8 "time" 9 10 "github.com/distribution/reference" 11 "github.com/docker/distribution" 12 "github.com/docker/distribution/manifest/schema2" 13 "github.com/docker/distribution/registry/client" 14 "github.com/docker/distribution/registry/client/auth" 15 "github.com/docker/distribution/registry/client/transport" 16 registrytypes "github.com/Prakhar-Agarwal-byte/moby/api/types/registry" 17 "github.com/Prakhar-Agarwal-byte/moby/dockerversion" 18 "github.com/Prakhar-Agarwal-byte/moby/registry" 19 ocispec "github.com/opencontainers/image-spec/specs-go/v1" 20 ) 21 22 var ( 23 // supportedMediaTypes represents acceptable media-type(-prefixes) 24 // we use this list to prevent obscure errors when trying to pull 25 // OCI artifacts. 26 supportedMediaTypes = []string{ 27 // valid prefixes 28 "application/vnd.oci.image", 29 "application/vnd.docker", 30 31 // these types may occur on old images, and are copied from 32 // defaultImageTypes below. 33 "application/octet-stream", 34 "application/json", 35 "text/html", 36 "", 37 } 38 39 // defaultImageTypes represents the schema2 config types for images 40 defaultImageTypes = []string{ 41 schema2.MediaTypeImageConfig, 42 ocispec.MediaTypeImageConfig, 43 // Handle unexpected values from https://github.com/docker/distribution/issues/1621 44 // (see also https://github.com/Prakhar-Agarwal-byte/moby/issues/22378, 45 // https://github.com/Prakhar-Agarwal-byte/moby/issues/30083) 46 "application/octet-stream", 47 "application/json", 48 "text/html", 49 // Treat defaulted values as images, newer types cannot be implied 50 "", 51 } 52 53 // pluginTypes represents the schema2 config types for plugins 54 pluginTypes = []string{ 55 schema2.MediaTypePluginConfig, 56 } 57 58 mediaTypeClasses map[string]string 59 ) 60 61 func init() { 62 // initialize media type classes with all know types for images and plugins. 63 mediaTypeClasses = map[string]string{} 64 for _, t := range defaultImageTypes { 65 mediaTypeClasses[t] = "image" 66 } 67 for _, t := range pluginTypes { 68 mediaTypeClasses[t] = "plugin" 69 } 70 } 71 72 // newRepository returns a repository (v2 only). It creates an HTTP transport 73 // providing timeout settings and authentication support, and also verifies the 74 // remote API version. 75 func newRepository( 76 ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, 77 metaHeaders http.Header, authConfig *registrytypes.AuthConfig, actions ...string, 78 ) (distribution.Repository, error) { 79 repoName := repoInfo.Name.Name() 80 // If endpoint does not support CanonicalName, use the RemoteName instead 81 if endpoint.TrimHostname { 82 repoName = reference.Path(repoInfo.Name) 83 } 84 85 direct := &net.Dialer{ 86 Timeout: 30 * time.Second, 87 KeepAlive: 30 * time.Second, 88 } 89 90 // TODO(dmcgowan): Call close idle connections when complete, use keep alive 91 base := &http.Transport{ 92 Proxy: http.ProxyFromEnvironment, 93 DialContext: direct.DialContext, 94 TLSHandshakeTimeout: 10 * time.Second, 95 TLSClientConfig: endpoint.TLSConfig, 96 // TODO(dmcgowan): Call close idle connections when complete and use keep alive 97 DisableKeepAlives: true, 98 } 99 100 modifiers := registry.Headers(dockerversion.DockerUserAgent(ctx), metaHeaders) 101 authTransport := transport.NewTransport(base, modifiers...) 102 103 challengeManager, err := registry.PingV2Registry(endpoint.URL, authTransport) 104 if err != nil { 105 transportOK := false 106 if responseErr, ok := err.(registry.PingResponseError); ok { 107 transportOK = true 108 err = responseErr.Err 109 } 110 return nil, fallbackError{ 111 err: err, 112 transportOK: transportOK, 113 } 114 } 115 116 if authConfig.RegistryToken != "" { 117 modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, &passThruTokenHandler{token: authConfig.RegistryToken})) 118 } else { 119 creds := registry.NewStaticCredentialStore(authConfig) 120 tokenHandler := auth.NewTokenHandlerWithOptions(auth.TokenHandlerOptions{ 121 Transport: authTransport, 122 Credentials: creds, 123 Scopes: []auth.Scope{auth.RepositoryScope{ 124 Repository: repoName, 125 Actions: actions, 126 Class: repoInfo.Class, 127 }}, 128 ClientID: registry.AuthClientID, 129 }) 130 basicHandler := auth.NewBasicHandler(creds) 131 modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)) 132 } 133 tr := transport.NewTransport(base, modifiers...) 134 135 repoNameRef, err := reference.WithName(repoName) 136 if err != nil { 137 return nil, fallbackError{ 138 err: err, 139 transportOK: true, 140 } 141 } 142 143 repo, err := client.NewRepository(repoNameRef, endpoint.URL.String(), tr) 144 if err != nil { 145 return nil, fallbackError{ 146 err: err, 147 transportOK: true, 148 } 149 } 150 151 return repo, nil 152 } 153 154 type passThruTokenHandler struct { 155 token string 156 } 157 158 func (th *passThruTokenHandler) Scheme() string { 159 return "bearer" 160 } 161 162 func (th *passThruTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error { 163 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token)) 164 return nil 165 }