update
This commit is contained in:
105
internal/hubmodule/docker/hooks.go
Normal file
105
internal/hubmodule/docker/hooks.go
Normal file
@@ -0,0 +1,105 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"strings"
|
||||
|
||||
"github.com/any-hub/any-hub/internal/proxy/hooks"
|
||||
)
|
||||
|
||||
func init() {
|
||||
hooks.MustRegister("docker", hooks.Hooks{
|
||||
NormalizePath: normalizePath,
|
||||
CachePolicy: cachePolicy,
|
||||
ContentType: contentType,
|
||||
})
|
||||
}
|
||||
|
||||
func normalizePath(ctx *hooks.RequestContext, clean string, rawQuery []byte) (string, []byte) {
|
||||
if !isDockerHubHost(ctx.UpstreamHost) {
|
||||
return clean, rawQuery
|
||||
}
|
||||
repo, rest, ok := splitDockerRepoPath(clean)
|
||||
if !ok || repo == "" || strings.Contains(repo, "/") || repo == "library" {
|
||||
return clean, rawQuery
|
||||
}
|
||||
return "/v2/library/" + repo + rest, rawQuery
|
||||
}
|
||||
|
||||
func cachePolicy(_ *hooks.RequestContext, locatorPath string, current hooks.CachePolicy) hooks.CachePolicy {
|
||||
clean := locatorPath
|
||||
if clean == "/v2" || clean == "v2" || clean == "/v2/" {
|
||||
return hooks.CachePolicy{}
|
||||
}
|
||||
if strings.Contains(clean, "/_catalog") {
|
||||
return hooks.CachePolicy{}
|
||||
}
|
||||
if isDockerImmutablePath(clean) {
|
||||
current.AllowCache = true
|
||||
current.AllowStore = true
|
||||
current.RequireRevalidate = false
|
||||
return current
|
||||
}
|
||||
current.AllowCache = true
|
||||
current.AllowStore = true
|
||||
current.RequireRevalidate = true
|
||||
return current
|
||||
}
|
||||
|
||||
func contentType(_ *hooks.RequestContext, locatorPath string) string {
|
||||
switch {
|
||||
case strings.Contains(locatorPath, "/tags/list"):
|
||||
return "application/json"
|
||||
case strings.Contains(locatorPath, "/blobs/"):
|
||||
return "application/octet-stream"
|
||||
default:
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func isDockerHubHost(host string) bool {
|
||||
switch strings.ToLower(host) {
|
||||
case "registry-1.docker.io", "docker.io", "index.docker.io":
|
||||
return true
|
||||
default:
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
func splitDockerRepoPath(path string) (string, string, bool) {
|
||||
if !strings.HasPrefix(path, "/v2/") {
|
||||
return "", "", false
|
||||
}
|
||||
suffix := strings.TrimPrefix(path, "/v2/")
|
||||
if suffix == "" || suffix == "/" {
|
||||
return "", "", false
|
||||
}
|
||||
segments := strings.Split(suffix, "/")
|
||||
var repoSegments []string
|
||||
for i, seg := range segments {
|
||||
if seg == "" {
|
||||
return "", "", false
|
||||
}
|
||||
switch seg {
|
||||
case "manifests", "blobs", "tags", "referrers":
|
||||
if len(repoSegments) == 0 {
|
||||
return "", "", false
|
||||
}
|
||||
rest := "/" + strings.Join(segments[i:], "/")
|
||||
return strings.Join(repoSegments, "/"), rest, true
|
||||
case "_catalog":
|
||||
return "", "", false
|
||||
}
|
||||
repoSegments = append(repoSegments, seg)
|
||||
}
|
||||
return "", "", false
|
||||
}
|
||||
|
||||
func isDockerImmutablePath(path string) bool {
|
||||
if strings.Contains(path, "/blobs/sha256:") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(path, "/manifests/sha256:") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
31
internal/hubmodule/docker/hooks_test.go
Normal file
31
internal/hubmodule/docker/hooks_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package docker
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/any-hub/any-hub/internal/proxy/hooks"
|
||||
)
|
||||
|
||||
func TestNormalizePathAddsLibraryForDockerHub(t *testing.T) {
|
||||
ctx := &hooks.RequestContext{UpstreamHost: "registry-1.docker.io"}
|
||||
path, _ := normalizePath(ctx, "/v2/nginx/manifests/latest", nil)
|
||||
if path != "/v2/library/nginx/manifests/latest" {
|
||||
t.Fatalf("expected library namespace, got %s", path)
|
||||
}
|
||||
|
||||
path, _ = normalizePath(ctx, "/v2/library/nginx/manifests/latest", nil)
|
||||
if path != "/v2/library/nginx/manifests/latest" {
|
||||
t.Fatalf("unexpected rewrite for existing namespace")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSplitDockerRepoPath(t *testing.T) {
|
||||
repo, rest, ok := splitDockerRepoPath("/v2/library/nginx/manifests/latest")
|
||||
if !ok || repo != "library/nginx" || rest != "/manifests/latest" {
|
||||
t.Fatalf("unexpected split result repo=%s rest=%s ok=%v", repo, rest, ok)
|
||||
}
|
||||
|
||||
if _, _, ok := splitDockerRepoPath("/v2/_catalog"); ok {
|
||||
t.Fatalf("expected catalog path to be ignored")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user