github.com/portworx/docker@v1.12.1/distribution/registry.go (about) 1 package distribution 2 3 import ( 4 "fmt" 5 "net" 6 "net/http" 7 "time" 8 9 "github.com/docker/distribution" 10 distreference "github.com/docker/distribution/reference" 11 "github.com/docker/distribution/registry/client" 12 "github.com/docker/distribution/registry/client/auth" 13 "github.com/docker/distribution/registry/client/transport" 14 "github.com/docker/docker/dockerversion" 15 "github.com/docker/docker/registry" 16 "github.com/docker/engine-api/types" 17 "github.com/docker/go-connections/sockets" 18 "golang.org/x/net/context" 19 ) 20 21 // NewV2Repository returns a repository (v2 only). It creates an HTTP transport 22 // providing timeout settings and authentication support, and also verifies the 23 // remote API version. 24 func NewV2Repository(ctx context.Context, repoInfo *registry.RepositoryInfo, endpoint registry.APIEndpoint, metaHeaders http.Header, authConfig *types.AuthConfig, actions ...string) (repo distribution.Repository, foundVersion bool, err error) { 25 repoName := repoInfo.FullName() 26 // If endpoint does not support CanonicalName, use the RemoteName instead 27 if endpoint.TrimHostname { 28 repoName = repoInfo.RemoteName() 29 } 30 31 direct := &net.Dialer{ 32 Timeout: 30 * time.Second, 33 KeepAlive: 30 * time.Second, 34 DualStack: true, 35 } 36 37 // TODO(dmcgowan): Call close idle connections when complete, use keep alive 38 base := &http.Transport{ 39 Proxy: http.ProxyFromEnvironment, 40 Dial: direct.Dial, 41 TLSHandshakeTimeout: 10 * time.Second, 42 TLSClientConfig: endpoint.TLSConfig, 43 // TODO(dmcgowan): Call close idle connections when complete and use keep alive 44 DisableKeepAlives: true, 45 } 46 47 proxyDialer, err := sockets.DialerFromEnvironment(direct) 48 if err == nil { 49 base.Dial = proxyDialer.Dial 50 } 51 52 modifiers := registry.DockerHeaders(dockerversion.DockerUserAgent(ctx), metaHeaders) 53 authTransport := transport.NewTransport(base, modifiers...) 54 55 challengeManager, foundVersion, err := registry.PingV2Registry(endpoint.URL, authTransport) 56 if err != nil { 57 transportOK := false 58 if responseErr, ok := err.(registry.PingResponseError); ok { 59 transportOK = true 60 err = responseErr.Err 61 } 62 return nil, foundVersion, fallbackError{ 63 err: err, 64 confirmedV2: foundVersion, 65 transportOK: transportOK, 66 } 67 } 68 69 if authConfig.RegistryToken != "" { 70 passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken} 71 modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler)) 72 } else { 73 creds := registry.NewStaticCredentialStore(authConfig) 74 tokenHandlerOptions := auth.TokenHandlerOptions{ 75 Transport: authTransport, 76 Credentials: creds, 77 Scopes: []auth.Scope{ 78 auth.RepositoryScope{ 79 Repository: repoName, 80 Actions: actions, 81 }, 82 }, 83 ClientID: registry.AuthClientID, 84 } 85 tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions) 86 basicHandler := auth.NewBasicHandler(creds) 87 modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler)) 88 } 89 tr := transport.NewTransport(base, modifiers...) 90 91 repoNameRef, err := distreference.ParseNamed(repoName) 92 if err != nil { 93 return nil, foundVersion, fallbackError{ 94 err: err, 95 confirmedV2: foundVersion, 96 transportOK: true, 97 } 98 } 99 100 repo, err = client.NewRepository(ctx, repoNameRef, endpoint.URL.String(), tr) 101 if err != nil { 102 err = fallbackError{ 103 err: err, 104 confirmedV2: foundVersion, 105 transportOK: true, 106 } 107 } 108 return 109 } 110 111 type existingTokenHandler struct { 112 token string 113 } 114 115 func (th *existingTokenHandler) Scheme() string { 116 return "bearer" 117 } 118 119 func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error { 120 req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token)) 121 return nil 122 }