mirror of
https://github.com/sky22333/hubproxy.git
synced 2026-08-09 13:51:46 +08:00
fix
This commit is contained in:
@@ -49,8 +49,7 @@ var forwardedRequestHeaders = []string{
|
|||||||
"If-Unmodified-Since",
|
"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 InitDockerProxy() {}
|
||||||
|
|
||||||
func defaultRegistryTarget() registryTarget {
|
func defaultRegistryTarget() registryTarget {
|
||||||
@@ -136,12 +135,13 @@ func resolveTokenTarget(c *gin.Context) (registryTarget, bool) {
|
|||||||
return registryTarget{}, false
|
return registryTarget{}, false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyDockerRegistryGin proxies Docker Registry API v2 requests transparently.
|
// 透明代理 Docker Registry API v2 请求。
|
||||||
func ProxyDockerRegistryGin(c *gin.Context) {
|
func ProxyDockerRegistryGin(c *gin.Context) {
|
||||||
path := c.Request.URL.Path
|
path := c.Request.URL.Path
|
||||||
|
|
||||||
if path == "/v2/" {
|
if path == "/v2/" {
|
||||||
c.JSON(http.StatusOK, gin.H{})
|
target, _ := resolveRegistryTarget(c, "")
|
||||||
|
proxyRegistryHTTP(c, target, "/v2/")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,7 +182,7 @@ func handleRegistryRequest(c *gin.Context, path string) {
|
|||||||
proxyRegistryHTTP(c, target, "/v2/"+targetPath)
|
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) {
|
func parseRegistryPath(path string) (imageName, apiType, reference string) {
|
||||||
if idx := strings.Index(path, "/manifests/"); idx != -1 {
|
if idx := strings.Index(path, "/manifests/"); idx != -1 {
|
||||||
return path[:idx], "manifests", path[idx+len("/manifests/"):]
|
return path[:idx], "manifests", path[idx+len("/manifests/"):]
|
||||||
@@ -196,8 +196,7 @@ func parseRegistryPath(path string) (imageName, apiType, reference string) {
|
|||||||
return "", "", ""
|
return "", "", ""
|
||||||
}
|
}
|
||||||
|
|
||||||
// ProxyDockerAuthGin forwards Docker token requests, including client Basic
|
// 代理 Docker token 请求,并透传客户端认证头。
|
||||||
// credentials, to the selected upstream auth service.
|
|
||||||
func ProxyDockerAuthGin(c *gin.Context) {
|
func ProxyDockerAuthGin(c *gin.Context) {
|
||||||
target, ok := resolveTokenTarget(c)
|
target, ok := resolveTokenTarget(c)
|
||||||
if !ok {
|
if !ok {
|
||||||
|
|||||||
@@ -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) {
|
func TestProxyDockerAuthForwardsBasicCredentials(t *testing.T) {
|
||||||
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
authServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||||
if got := r.Header.Get("Authorization"); got != "Basic dXNlcjpwYXNz" {
|
if got := r.Header.Get("Authorization"); got != "Basic dXNlcjpwYXNz" {
|
||||||
|
|||||||
@@ -140,15 +140,10 @@ func TestGitHubNoRouteRejectsUnsupportedHost(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestDockerV2PingAndInvalidPath(t *testing.T) {
|
func TestDockerV2InvalidPath(t *testing.T) {
|
||||||
router := newTestRouter(t, "")
|
router := newTestRouter(t, "")
|
||||||
|
|
||||||
w := performRequest(router, http.MethodGet, "/v2/", "")
|
w := performRequest(router, http.MethodGet, "/v2/library/nginx/unknown/latest", "")
|
||||||
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", "")
|
|
||||||
if w.Code != http.StatusBadRequest {
|
if w.Code != http.StatusBadRequest {
|
||||||
t.Fatalf("invalid v2 status = %d, want 400; body=%s", w.Code, w.Body.String())
|
t.Fatalf("invalid v2 status = %d, want 400; body=%s", w.Code, w.Body.String())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user