github.com/toplink-cn/moby@v0.0.0-20240305205811-460b4aebdf81/registry/search_endpoint_v1_test.go (about)

     1  package registry // import "github.com/docker/docker/registry"
     2  
     3  import (
     4  	"net/http"
     5  	"net/http/httptest"
     6  	"strings"
     7  	"testing"
     8  
     9  	"github.com/docker/docker/api/types/registry"
    10  	"gotest.tools/v3/assert"
    11  	is "gotest.tools/v3/assert/cmp"
    12  )
    13  
    14  func TestV1EndpointPing(t *testing.T) {
    15  	testPing := func(index *registry.IndexInfo, expectedStandalone bool, assertMessage string) {
    16  		ep, err := newV1Endpoint(index, nil)
    17  		if err != nil {
    18  			t.Fatal(err)
    19  		}
    20  		regInfo, err := ep.ping()
    21  		if err != nil {
    22  			t.Fatal(err)
    23  		}
    24  
    25  		assert.Equal(t, regInfo.Standalone, expectedStandalone, assertMessage)
    26  	}
    27  
    28  	testPing(makeIndex("/v1/"), true, "Expected standalone to be true (default)")
    29  	testPing(makeHTTPSIndex("/v1/"), true, "Expected standalone to be true (default)")
    30  	testPing(makePublicIndex(), false, "Expected standalone to be false for public index")
    31  }
    32  
    33  func TestV1Endpoint(t *testing.T) {
    34  	// Simple wrapper to fail test if err != nil
    35  	expandEndpoint := func(index *registry.IndexInfo) *v1Endpoint {
    36  		endpoint, err := newV1Endpoint(index, nil)
    37  		if err != nil {
    38  			t.Fatal(err)
    39  		}
    40  		return endpoint
    41  	}
    42  
    43  	assertInsecureIndex := func(index *registry.IndexInfo) {
    44  		index.Secure = true
    45  		_, err := newV1Endpoint(index, nil)
    46  		assert.ErrorContains(t, err, "insecure-registry", index.Name+": Expected insecure-registry  error for insecure index")
    47  		index.Secure = false
    48  	}
    49  
    50  	assertSecureIndex := func(index *registry.IndexInfo) {
    51  		index.Secure = true
    52  		_, err := newV1Endpoint(index, nil)
    53  		assert.ErrorContains(t, err, "certificate signed by unknown authority", index.Name+": Expected cert error for secure index")
    54  		index.Secure = false
    55  	}
    56  
    57  	index := &registry.IndexInfo{}
    58  	index.Name = makeURL("/v1/")
    59  	endpoint := expandEndpoint(index)
    60  	assert.Equal(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name)
    61  	assertInsecureIndex(index)
    62  
    63  	index.Name = makeURL("")
    64  	endpoint = expandEndpoint(index)
    65  	assert.Equal(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/")
    66  	assertInsecureIndex(index)
    67  
    68  	httpURL := makeURL("")
    69  	index.Name = strings.SplitN(httpURL, "://", 2)[1]
    70  	endpoint = expandEndpoint(index)
    71  	assert.Equal(t, endpoint.String(), httpURL+"/v1/", index.Name+": Expected endpoint to be "+httpURL+"/v1/")
    72  	assertInsecureIndex(index)
    73  
    74  	index.Name = makeHTTPSURL("/v1/")
    75  	endpoint = expandEndpoint(index)
    76  	assert.Equal(t, endpoint.String(), index.Name, "Expected endpoint to be "+index.Name)
    77  	assertSecureIndex(index)
    78  
    79  	index.Name = makeHTTPSURL("")
    80  	endpoint = expandEndpoint(index)
    81  	assert.Equal(t, endpoint.String(), index.Name+"/v1/", index.Name+": Expected endpoint to be "+index.Name+"/v1/")
    82  	assertSecureIndex(index)
    83  
    84  	httpsURL := makeHTTPSURL("")
    85  	index.Name = strings.SplitN(httpsURL, "://", 2)[1]
    86  	endpoint = expandEndpoint(index)
    87  	assert.Equal(t, endpoint.String(), httpsURL+"/v1/", index.Name+": Expected endpoint to be "+httpsURL+"/v1/")
    88  	assertSecureIndex(index)
    89  
    90  	badEndpoints := []string{
    91  		"http://127.0.0.1/v1/",
    92  		"https://127.0.0.1/v1/",
    93  		"http://127.0.0.1",
    94  		"https://127.0.0.1",
    95  		"127.0.0.1",
    96  	}
    97  	for _, address := range badEndpoints {
    98  		index.Name = address
    99  		_, err := newV1Endpoint(index, nil)
   100  		assert.Check(t, err != nil, "Expected error while expanding bad endpoint: %s", address)
   101  	}
   102  }
   103  
   104  func TestV1EndpointParse(t *testing.T) {
   105  	tests := []struct {
   106  		address     string
   107  		expected    string
   108  		expectedErr string
   109  	}{
   110  		{
   111  			address:  IndexServer,
   112  			expected: IndexServer,
   113  		},
   114  		{
   115  			address:  "https://0.0.0.0:5000/v1/",
   116  			expected: "https://0.0.0.0:5000/v1/",
   117  		},
   118  		{
   119  			address:  "https://0.0.0.0:5000",
   120  			expected: "https://0.0.0.0:5000/v1/",
   121  		},
   122  		{
   123  			address:  "0.0.0.0:5000",
   124  			expected: "https://0.0.0.0:5000/v1/",
   125  		},
   126  		{
   127  			address:  "https://0.0.0.0:5000/nonversion/",
   128  			expected: "https://0.0.0.0:5000/nonversion/v1/",
   129  		},
   130  		{
   131  			address:  "https://0.0.0.0:5000/v0/",
   132  			expected: "https://0.0.0.0:5000/v0/v1/",
   133  		},
   134  		{
   135  			address:     "https://0.0.0.0:5000/v2/",
   136  			expectedErr: "search is not supported on v2 endpoints: https://0.0.0.0:5000/v2/",
   137  		},
   138  	}
   139  	for _, tc := range tests {
   140  		tc := tc
   141  		t.Run(tc.address, func(t *testing.T) {
   142  			ep, err := newV1EndpointFromStr(tc.address, nil, nil)
   143  			if tc.expectedErr != "" {
   144  				assert.Check(t, is.Error(err, tc.expectedErr))
   145  				assert.Check(t, is.Nil(ep))
   146  			} else {
   147  				assert.NilError(t, err)
   148  				assert.Check(t, is.Equal(ep.String(), tc.expected))
   149  			}
   150  		})
   151  	}
   152  }
   153  
   154  // Ensure that a registry endpoint that responds with a 401 only is determined
   155  // to be a valid v1 registry endpoint
   156  func TestV1EndpointValidate(t *testing.T) {
   157  	requireBasicAuthHandler := http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   158  		w.Header().Add("WWW-Authenticate", `Basic realm="localhost"`)
   159  		w.WriteHeader(http.StatusUnauthorized)
   160  	})
   161  
   162  	// Make a test server which should validate as a v1 server.
   163  	testServer := httptest.NewServer(requireBasicAuthHandler)
   164  	defer testServer.Close()
   165  
   166  	testEndpoint, err := newV1Endpoint(&registry.IndexInfo{Name: testServer.URL}, nil)
   167  	if err != nil {
   168  		t.Fatal(err)
   169  	}
   170  
   171  	if testEndpoint.URL.Scheme != "http" {
   172  		t.Fatalf("expecting to validate endpoint as http, got url %s", testEndpoint.String())
   173  	}
   174  }
   175  
   176  func TestTrustedLocation(t *testing.T) {
   177  	for _, u := range []string{"http://example.com", "https://example.com:7777", "http://docker.io", "http://test.docker.com", "https://fakedocker.com"} {
   178  		req, _ := http.NewRequest(http.MethodGet, u, nil)
   179  		assert.Check(t, !trustedLocation(req))
   180  	}
   181  
   182  	for _, u := range []string{"https://docker.io", "https://test.docker.com:80"} {
   183  		req, _ := http.NewRequest(http.MethodGet, u, nil)
   184  		assert.Check(t, trustedLocation(req))
   185  	}
   186  }
   187  
   188  func TestAddRequiredHeadersToRedirectedRequests(t *testing.T) {
   189  	for _, urls := range [][]string{
   190  		{"http://docker.io", "https://docker.com"},
   191  		{"https://foo.docker.io:7777", "http://bar.docker.com"},
   192  		{"https://foo.docker.io", "https://example.com"},
   193  	} {
   194  		reqFrom, _ := http.NewRequest(http.MethodGet, urls[0], nil)
   195  		reqFrom.Header.Add("Content-Type", "application/json")
   196  		reqFrom.Header.Add("Authorization", "super_secret")
   197  		reqTo, _ := http.NewRequest(http.MethodGet, urls[1], nil)
   198  
   199  		_ = addRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
   200  
   201  		if len(reqTo.Header) != 1 {
   202  			t.Fatalf("Expected 1 headers, got %d", len(reqTo.Header))
   203  		}
   204  
   205  		if reqTo.Header.Get("Content-Type") != "application/json" {
   206  			t.Fatal("'Content-Type' should be 'application/json'")
   207  		}
   208  
   209  		if reqTo.Header.Get("Authorization") != "" {
   210  			t.Fatal("'Authorization' should be empty")
   211  		}
   212  	}
   213  
   214  	for _, urls := range [][]string{
   215  		{"https://docker.io", "https://docker.com"},
   216  		{"https://foo.docker.io:7777", "https://bar.docker.com"},
   217  	} {
   218  		reqFrom, _ := http.NewRequest(http.MethodGet, urls[0], nil)
   219  		reqFrom.Header.Add("Content-Type", "application/json")
   220  		reqFrom.Header.Add("Authorization", "super_secret")
   221  		reqTo, _ := http.NewRequest(http.MethodGet, urls[1], nil)
   222  
   223  		_ = addRequiredHeadersToRedirectedRequests(reqTo, []*http.Request{reqFrom})
   224  
   225  		if len(reqTo.Header) != 2 {
   226  			t.Fatalf("Expected 2 headers, got %d", len(reqTo.Header))
   227  		}
   228  
   229  		if reqTo.Header.Get("Content-Type") != "application/json" {
   230  			t.Fatal("'Content-Type' should be 'application/json'")
   231  		}
   232  
   233  		if reqTo.Header.Get("Authorization") != "super_secret" {
   234  			t.Fatal("'Authorization' should be 'super_secret'")
   235  		}
   236  	}
   237  }