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  }