fix: apt cache
This commit is contained in:
@@ -64,11 +64,11 @@ func isAptIndexPath(p string) bool {
|
||||
if isByHashPath(clean) {
|
||||
return false
|
||||
}
|
||||
if strings.HasPrefix(clean, "/dists/") {
|
||||
if strings.HasSuffix(clean, "/release") || strings.HasSuffix(clean, "/inrelease") || strings.HasSuffix(clean, "/release.gpg") {
|
||||
return true
|
||||
}
|
||||
if strings.Contains(clean, "/packages") {
|
||||
|
||||
if strings.Contains(clean, "/dists/") {
|
||||
if strings.HasSuffix(clean, "/release") ||
|
||||
strings.HasSuffix(clean, "/inrelease") ||
|
||||
strings.HasSuffix(clean, "/release.gpg") {
|
||||
return true
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ func isAptImmutablePath(p string) bool {
|
||||
if isByHashPath(clean) {
|
||||
return true
|
||||
}
|
||||
if strings.HasPrefix(clean, "/pool/") {
|
||||
if strings.Contains(clean, "/pool/") {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@@ -88,9 +88,10 @@ func isAptImmutablePath(p string) bool {
|
||||
|
||||
func isByHashPath(p string) bool {
|
||||
clean := canonicalPath(p)
|
||||
if !strings.HasPrefix(clean, "/dists/") {
|
||||
if strings.Contains(clean, "/dists/") {
|
||||
return false
|
||||
}
|
||||
|
||||
return strings.Contains(clean, "/by-hash/")
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,14 @@ func TestCachePolicyIndexesRevalidate(t *testing.T) {
|
||||
if !current.AllowCache || !current.AllowStore || !current.RequireRevalidate {
|
||||
t.Fatalf("expected packages index to revalidate")
|
||||
}
|
||||
current = cachePolicy(nil, "/dists/bookworm/main/Contents-amd64.gz", hooks.CachePolicy{})
|
||||
if !current.AllowCache || !current.AllowStore || !current.RequireRevalidate {
|
||||
t.Fatalf("expected contents index to revalidate")
|
||||
}
|
||||
current = cachePolicy(nil, "/debian-security/dists/trixie/Contents-amd64.gz", hooks.CachePolicy{})
|
||||
if !current.AllowCache || !current.AllowStore || !current.RequireRevalidate {
|
||||
t.Fatalf("expected prefixed contents index to revalidate")
|
||||
}
|
||||
}
|
||||
|
||||
func TestCachePolicyImmutable(t *testing.T) {
|
||||
@@ -26,6 +34,7 @@ func TestCachePolicyImmutable(t *testing.T) {
|
||||
{name: "by-hash nested", path: "/dists/bookworm/main/binary-amd64/by-hash/SHA256/def"},
|
||||
{name: "pool package", path: "/pool/main/h/hello.deb"},
|
||||
{name: "pool canonicalized", path: " /PoOl/main/../main/h/hello_1.0_amd64.DeB "},
|
||||
{name: "mirror prefix pool", path: "/debian/pool/main/h/hello.deb"},
|
||||
}
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
|
||||
@@ -77,6 +77,7 @@ func TestAptUpdateCachesIndexes(t *testing.T) {
|
||||
|
||||
releasePath := "/dists/bookworm/Release"
|
||||
packagesPath := "/dists/bookworm/main/binary-amd64/Packages.gz"
|
||||
contentsPath := "/dists/bookworm/main/Contents-amd64.gz"
|
||||
|
||||
resp := doRequest(releasePath)
|
||||
if resp.StatusCode != fiber.StatusOK {
|
||||
@@ -114,6 +115,24 @@ func TestAptUpdateCachesIndexes(t *testing.T) {
|
||||
}
|
||||
pkgResp2.Body.Close()
|
||||
|
||||
contentsResp := doRequest(contentsPath)
|
||||
if contentsResp.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 for contents, got %d", contentsResp.StatusCode)
|
||||
}
|
||||
if contentsResp.Header.Get("X-Any-Hub-Cache-Hit") != "false" {
|
||||
t.Fatalf("expected cache miss for contents")
|
||||
}
|
||||
contentsResp.Body.Close()
|
||||
|
||||
contentsResp2 := doRequest(contentsPath)
|
||||
if contentsResp2.StatusCode != fiber.StatusOK {
|
||||
t.Fatalf("expected 200 for cached contents, got %d", contentsResp2.StatusCode)
|
||||
}
|
||||
if contentsResp2.Header.Get("X-Any-Hub-Cache-Hit") != "true" {
|
||||
t.Fatalf("expected cache hit for contents")
|
||||
}
|
||||
contentsResp2.Body.Close()
|
||||
|
||||
if stub.ReleaseGets() != 1 {
|
||||
t.Fatalf("expected single release GET, got %d", stub.ReleaseGets())
|
||||
}
|
||||
@@ -126,6 +145,12 @@ func TestAptUpdateCachesIndexes(t *testing.T) {
|
||||
if stub.PackagesHeads() != 1 {
|
||||
t.Fatalf("expected single packages HEAD revalidate, got %d", stub.PackagesHeads())
|
||||
}
|
||||
if stub.ContentsGets() != 1 {
|
||||
t.Fatalf("expected single contents GET, got %d", stub.ContentsGets())
|
||||
}
|
||||
if stub.ContentsHeads() != 1 {
|
||||
t.Fatalf("expected single contents HEAD revalidate, got %d", stub.ContentsHeads())
|
||||
}
|
||||
}
|
||||
|
||||
type aptStub struct {
|
||||
@@ -135,14 +160,19 @@ type aptStub struct {
|
||||
mu sync.Mutex
|
||||
releaseBody string
|
||||
packagesBody string
|
||||
contentsBody string
|
||||
releaseETag string
|
||||
packagesETag string
|
||||
contentsETag string
|
||||
releaseGets int
|
||||
releaseHeads int
|
||||
packagesGets int
|
||||
packagesHeads int
|
||||
contentsGets int
|
||||
contentsHeads int
|
||||
releasePath string
|
||||
packagesPath string
|
||||
contentsPath string
|
||||
}
|
||||
|
||||
func newAptStub(t *testing.T) *aptStub {
|
||||
@@ -150,15 +180,19 @@ func newAptStub(t *testing.T) *aptStub {
|
||||
stub := &aptStub{
|
||||
releaseBody: "Release-body",
|
||||
packagesBody: "Packages-body",
|
||||
contentsBody: "Contents-body",
|
||||
releaseETag: "r1",
|
||||
packagesETag: "p1",
|
||||
contentsETag: "c1",
|
||||
releasePath: "/dists/bookworm/Release",
|
||||
packagesPath: "/dists/bookworm/main/binary-amd64/Packages.gz",
|
||||
contentsPath: "/dists/bookworm/main/Contents-amd64.gz",
|
||||
}
|
||||
|
||||
mux := http.NewServeMux()
|
||||
mux.HandleFunc(stub.releasePath, stub.handleRelease)
|
||||
mux.HandleFunc(stub.packagesPath, stub.handlePackages)
|
||||
mux.HandleFunc(stub.contentsPath, stub.handleContents)
|
||||
|
||||
listener, err := net.Listen("tcp", "127.0.0.1:0")
|
||||
if err != nil {
|
||||
@@ -212,6 +246,25 @@ func (s *aptStub) handlePackages(w http.ResponseWriter, r *http.Request) {
|
||||
_, _ = w.Write([]byte(s.packagesBody))
|
||||
}
|
||||
|
||||
func (s *aptStub) handleContents(w http.ResponseWriter, r *http.Request) {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
if r.Method == http.MethodHead {
|
||||
s.contentsHeads++
|
||||
if matchETag(r, s.contentsETag) {
|
||||
w.WriteHeader(http.StatusNotModified)
|
||||
return
|
||||
}
|
||||
writeHeaders(w, s.contentsETag)
|
||||
w.Header().Set("Content-Type", "application/gzip")
|
||||
return
|
||||
}
|
||||
s.contentsGets++
|
||||
writeHeaders(w, s.contentsETag)
|
||||
w.Header().Set("Content-Type", "application/gzip")
|
||||
_, _ = w.Write([]byte(s.contentsBody))
|
||||
}
|
||||
|
||||
func matchETag(r *http.Request, etag string) bool {
|
||||
for _, candidate := range r.Header.Values("If-None-Match") {
|
||||
c := strings.Trim(candidate, "\"")
|
||||
@@ -251,6 +304,18 @@ func (s *aptStub) PackagesHeads() int {
|
||||
return s.packagesHeads
|
||||
}
|
||||
|
||||
func (s *aptStub) ContentsGets() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.contentsGets
|
||||
}
|
||||
|
||||
func (s *aptStub) ContentsHeads() int {
|
||||
s.mu.Lock()
|
||||
defer s.mu.Unlock()
|
||||
return s.contentsHeads
|
||||
}
|
||||
|
||||
func (s *aptStub) Close() {
|
||||
if s == nil {
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user