From 3e8ceb2b32df45e647ba0918eb06cf2f1820f575 Mon Sep 17 00:00:00 2001 From: sky22333 Date: Sat, 16 May 2026 03:56:29 +0800 Subject: [PATCH] fix --- src/handlers/docker.go | 13 ++++++------- src/handlers/docker_test.go | 39 +++++++++++++++++++++++++++++++++++++ src/main_test.go | 9 ++------- 3 files changed, 47 insertions(+), 14 deletions(-) diff --git a/src/handlers/docker.go b/src/handlers/docker.go index a9e0bd2..f5723b1 100644 --- a/src/handlers/docker.go +++ b/src/handlers/docker.go @@ -49,8 +49,7 @@ var forwardedRequestHeaders = []string{ "If-Unmodified-Since", } -// InitDockerProxy is kept as the Docker proxy initialization hook. The online -// registry proxy is intentionally stateless and uses the shared HTTP client. +// 保留初始化入口,在线代理无状态。 func InitDockerProxy() {} func defaultRegistryTarget() registryTarget { @@ -136,12 +135,13 @@ func resolveTokenTarget(c *gin.Context) (registryTarget, bool) { return registryTarget{}, false } -// ProxyDockerRegistryGin proxies Docker Registry API v2 requests transparently. +// 透明代理 Docker Registry API v2 请求。 func ProxyDockerRegistryGin(c *gin.Context) { path := c.Request.URL.Path if path == "/v2/" { - c.JSON(http.StatusOK, gin.H{}) + target, _ := resolveRegistryTarget(c, "") + proxyRegistryHTTP(c, target, "/v2/") return } @@ -182,7 +182,7 @@ func handleRegistryRequest(c *gin.Context, path string) { proxyRegistryHTTP(c, target, "/v2/"+targetPath) } -// parseRegistryPath parses a Docker Registry v2 path without the leading /v2/. +// 解析去掉 /v2/ 前缀后的 Registry 路径。 func parseRegistryPath(path string) (imageName, apiType, reference string) { if idx := strings.Index(path, "/manifests/"); idx != -1 { return path[:idx], "manifests", path[idx+len("/manifests/"):] @@ -196,8 +196,7 @@ func parseRegistryPath(path string) (imageName, apiType, reference string) { return "", "", "" } -// ProxyDockerAuthGin forwards Docker token requests, including client Basic -// credentials, to the selected upstream auth service. +// 代理 Docker token 请求,并透传客户端认证头。 func ProxyDockerAuthGin(c *gin.Context) { target, ok := resolveTokenTarget(c) if !ok { diff --git a/src/handlers/docker_test.go b/src/handlers/docker_test.go index cd3cddf..4faa350 100644 --- a/src/handlers/docker_test.go +++ b/src/handlers/docker_test.go @@ -245,6 +245,45 @@ enabled = true } } +func TestDockerV2BaseProxiesUpstreamChallenge(t *testing.T) { + upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + if r.URL.Path != "/v2/" { + t.Fatalf("upstream path = %q", r.URL.Path) + } + w.Header().Set("WWW-Authenticate", `Bearer realm="https://registry.example/token",service="registry.example"`) + w.WriteHeader(http.StatusUnauthorized) + })) + defer upstream.Close() + + initDockerProxyTest(t, ` +[registries."docker.io"] +upstream = "`+upstream.URL+`" +authHost = "https://auth.example/token" +authType = "docker" +enabled = true +`) + + gin.SetMode(gin.TestMode) + router := gin.New() + router.Any("/v2/", ProxyDockerRegistryGin) + + req := httptest.NewRequest(http.MethodGet, "/v2/", nil) + req.Host = "hub.example.com" + req.Header.Set("X-Forwarded-Proto", "https") + w := httptest.NewRecorder() + + router.ServeHTTP(w, req) + + if w.Code != http.StatusUnauthorized { + t.Fatalf("status = %d, want 401; body=%s", w.Code, w.Body.String()) + } + + wantChallenge := `Bearer realm="https://hub.example.com/token/docker.io",service="registry.docker.io"` + if got := w.Header().Get("WWW-Authenticate"); got != wantChallenge { + t.Fatalf("WWW-Authenticate = %q, want %q", got, wantChallenge) + } +} + func TestProxyDockerAuthForwardsBasicCredentials(t *testing.T) { authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { if got := r.Header.Get("Authorization"); got != "Basic dXNlcjpwYXNz" { diff --git a/src/main_test.go b/src/main_test.go index 0d3df0f..79b0cb8 100644 --- a/src/main_test.go +++ b/src/main_test.go @@ -140,15 +140,10 @@ func TestGitHubNoRouteRejectsUnsupportedHost(t *testing.T) { } } -func TestDockerV2PingAndInvalidPath(t *testing.T) { +func TestDockerV2InvalidPath(t *testing.T) { router := newTestRouter(t, "") - w := performRequest(router, http.MethodGet, "/v2/", "") - if w.Code != http.StatusOK { - t.Fatalf("/v2/ status = %d, want 200; body=%s", w.Code, w.Body.String()) - } - - w = performRequest(router, http.MethodGet, "/v2/library/nginx/unknown/latest", "") + w := performRequest(router, http.MethodGet, "/v2/library/nginx/unknown/latest", "") if w.Code != http.StatusBadRequest { t.Fatalf("invalid v2 status = %d, want 400; body=%s", w.Code, w.Body.String()) }