search_endpoint_v1_test.go 7.2 KB

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