github.com/rawahars/moby@v24.0.4+incompatible/distribution/registry.go (about)

     1  package distribution // import "github.com/docker/docker/distribution"
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"net"
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/docker/distribution"
    11  	"github.com/docker/distribution/manifest/schema2"
    12  	"github.com/docker/distribution/reference"
    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/docker/docker/api/types/registry"
    17  	"github.com/docker/docker/dockerversion"
    18  	"github.com/docker/docker/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/docker/docker/issues/22378,
    45  		// https://github.com/docker/docker/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  ) (repo distribution.Repository, err 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  		passThruTokenHandler := &existingTokenHandler{token: authConfig.RegistryToken}
   118  		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, passThruTokenHandler))
   119  	} else {
   120  		scope := auth.RepositoryScope{
   121  			Repository: repoName,
   122  			Actions:    actions,
   123  			Class:      repoInfo.Class,
   124  		}
   125  
   126  		creds := registry.NewStaticCredentialStore(authConfig)
   127  		tokenHandlerOptions := auth.TokenHandlerOptions{
   128  			Transport:   authTransport,
   129  			Credentials: creds,
   130  			Scopes:      []auth.Scope{scope},
   131  			ClientID:    registry.AuthClientID,
   132  		}
   133  		tokenHandler := auth.NewTokenHandlerWithOptions(tokenHandlerOptions)
   134  		basicHandler := auth.NewBasicHandler(creds)
   135  		modifiers = append(modifiers, auth.NewAuthorizer(challengeManager, tokenHandler, basicHandler))
   136  	}
   137  	tr := transport.NewTransport(base, modifiers...)
   138  
   139  	repoNameRef, err := reference.WithName(repoName)
   140  	if err != nil {
   141  		return nil, fallbackError{
   142  			err:         err,
   143  			transportOK: true,
   144  		}
   145  	}
   146  
   147  	repo, err = client.NewRepository(repoNameRef, endpoint.URL.String(), tr)
   148  	if err != nil {
   149  		err = fallbackError{
   150  			err:         err,
   151  			transportOK: true,
   152  		}
   153  	}
   154  	return
   155  }
   156  
   157  type existingTokenHandler struct {
   158  	token string
   159  }
   160  
   161  func (th *existingTokenHandler) Scheme() string {
   162  	return "bearer"
   163  }
   164  
   165  func (th *existingTokenHandler) AuthorizeRequest(req *http.Request, params map[string]string) error {
   166  	req.Header.Set("Authorization", fmt.Sprintf("Bearer %s", th.token))
   167  	return nil
   168  }