mirror of
https://github.com/git-pkgs/proxy.git
synced 2026-11-09 15:49:16 -05:00
Conan, CRAN, Conda, RPM, the main Debian archive and the default Maven repository keyed cached metadata by the request path with '/' replaced by '_'. Names and versions may contain '_', so foo/bar_1.0 and foo_bar/1.0 shared an entry, and with cache_metadata one reference's recipe files were served for the other. Conan also appended the query with '_', so a path without a query could collide with a shorter path plus one. Hash the upstream URL, the path and, for Conan, the query instead, as the APK, Arch, generic and Helm handlers already do. Each part is length-prefixed so no two inputs share a key.
74 lines
2.6 KiB
Go
74 lines
2.6 KiB
Go
package handler
|
|
|
|
import (
|
|
"io"
|
|
"net/http"
|
|
"net/http/httptest"
|
|
"strings"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
// TestConanMetadataKeysKeepReferencesApart checks that Conan references whose
|
|
// paths only differ in where '/' and '_' fall, or in a query, are cached
|
|
// apart. Names and versions may contain '_'.
|
|
func TestConanMetadataKeysKeepReferencesApart(t *testing.T) {
|
|
upstream := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
|
_, _ = io.WriteString(w, r.URL.Path+"?"+r.URL.RawQuery)
|
|
}))
|
|
defer upstream.Close()
|
|
|
|
proxy, _, _, _ := setupTestProxy(t)
|
|
proxy.CacheMetadata = true
|
|
proxy.MetadataTTL = time.Hour
|
|
proxy.HTTPClient = upstream.Client()
|
|
srv := httptest.NewServer(NewConanHandlerWithUpstream(proxy, testProxyURL, upstream.URL).Routes())
|
|
defer srv.Close()
|
|
|
|
for _, pair := range [][2]string{
|
|
{"/v2/conans/foo/bar_1.0/_/_/latest", "/v2/conans/foo_bar/1.0/_/_/latest"},
|
|
{"/v2/conans/foo/bar_1.0/_/_/revisions/r1/files/conanfile.py", "/v2/conans/foo_bar/1.0/_/_/revisions/r1/files/conanfile.py"},
|
|
{"/v2/conans/search?q=zlib", "/v2/conans/search_q=zlib"},
|
|
} {
|
|
for _, target := range pair {
|
|
resp, err := http.Get(srv.URL + target)
|
|
if err != nil {
|
|
t.Fatal(err)
|
|
}
|
|
body, _ := io.ReadAll(resp.Body)
|
|
_ = resp.Body.Close()
|
|
want := target
|
|
if !strings.Contains(want, "?") {
|
|
want += "?"
|
|
}
|
|
if string(body) != want {
|
|
t.Errorf("GET %s served %q, want %q", target, body, want)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// TestMetadataCacheKeysUnambiguous checks that the path-based metadata cache
|
|
// keys of the other ecosystems keep paths apart that differ only in where
|
|
// '/' and '_' fall.
|
|
func TestMetadataCacheKeysUnambiguous(t *testing.T) {
|
|
const a, b = "x/foo/bar_1.0/file", "x/foo_bar/1.0/file"
|
|
|
|
maven := mavenSource{upstreamURL: "https://repo.test"}
|
|
debian := NewDebianHandler(nil, "http://proxy.test", "https://deb.test", nil)
|
|
rpm := NewRPMHandlerWithUpstream(nil, "http://proxy.test", "https://rpm.test")
|
|
cran := NewCRANHandlerWithUpstream(nil, "http://proxy.test", "https://cran.test")
|
|
conda := NewCondaHandlerWithUpstream(nil, "http://proxy.test", "https://conda.test")
|
|
|
|
for name, key := range map[string]func(string) string{
|
|
"maven": maven.metadataCacheKey,
|
|
"debian": func(p string) string { return debian.metadataCacheKeyFor("", debian.upstreamURL, p) },
|
|
"rpm": func(p string) string { return rpm.metadataCacheKey(p) },
|
|
"cran": func(p string) string { return cran.metadataCacheKey("/" + p) },
|
|
"conda": func(p string) string { return conda.metadataCacheKey("/" + p) },
|
|
} {
|
|
if key(a) == key(b) {
|
|
t.Errorf("%s: %s and %s share metadata cache key %q", name, a, b, key(a))
|
|
}
|
|
}
|
|
}
|