diff --git a/cmd/check-ip/main.go b/cmd/check-ip/main.go
index 8e57410..7adf74a 100644
--- a/cmd/check-ip/main.go
+++ b/cmd/check-ip/main.go
@@ -155,13 +155,13 @@ func main() {
geoSet := dataset.NewSet(
&httpcache.Cacher{
URL: geoip.DownloadBase + "/GeoLite2-City/download?suffix=tar.gz",
- Path: filepath.Join(maxmindDir, "GeoLite2-City.tar.gz"),
+ Path: filepath.Join(maxmindDir, geoip.TarGzName(geoip.CityEdition)),
MaxAge: 3 * 24 * time.Hour,
Header: authHeader,
},
&httpcache.Cacher{
URL: geoip.DownloadBase + "/GeoLite2-ASN/download?suffix=tar.gz",
- Path: filepath.Join(maxmindDir, "GeoLite2-ASN.tar.gz"),
+ Path: filepath.Join(maxmindDir, geoip.TarGzName(geoip.ASNEdition)),
MaxAge: 3 * 24 * time.Hour,
Header: authHeader,
},
diff --git a/net/geoip/cmd/geoip-update/main.go b/net/geoip/cmd/geoip-update/main.go
index f848160..79e4451 100644
--- a/net/geoip/cmd/geoip-update/main.go
+++ b/net/geoip/cmd/geoip-update/main.go
@@ -51,7 +51,7 @@ func main() {
exitCode := 0
for _, edition := range cfg.EditionIDs {
- path := filepath.Join(outDir, edition+".tar.gz")
+ path := filepath.Join(outDir, geoip.TarGzName(edition))
cacher := &httpcache.Cacher{
URL: geoip.DownloadBase + "/" + edition + "/download?suffix=tar.gz",
Path: path,
diff --git a/net/geoip/databases.go b/net/geoip/databases.go
index fac14ee..7a918a3 100644
--- a/net/geoip/databases.go
+++ b/net/geoip/databases.go
@@ -20,15 +20,15 @@ type Databases struct {
ASN *geoip2.Reader
}
-// Open reads
/GeoLite2-City.tar.gz and /GeoLite2-ASN.tar.gz,
+// Open reads /_LATEST.tar.gz for City and ASN editions,
// extracts the .mmdb entry from each archive in memory, and returns open
// readers. No .mmdb files are written to disk.
func Open(dir string) (*Databases, error) {
- city, err := openMMDBTarGz(filepath.Join(dir, "GeoLite2-City.tar.gz"))
+ city, err := openMMDBTarGz(filepath.Join(dir, TarGzName(CityEdition)))
if err != nil {
return nil, fmt.Errorf("city: %w", err)
}
- asn, err := openMMDBTarGz(filepath.Join(dir, "GeoLite2-ASN.tar.gz"))
+ asn, err := openMMDBTarGz(filepath.Join(dir, TarGzName(ASNEdition)))
if err != nil {
_ = city.Close()
return nil, fmt.Errorf("asn: %w", err)
diff --git a/net/geoip/geoip.go b/net/geoip/geoip.go
index 8756edb..fe8df2e 100644
--- a/net/geoip/geoip.go
+++ b/net/geoip/geoip.go
@@ -15,6 +15,14 @@ const (
DownloadBase = "https://download.maxmind.com/geoip/databases"
)
+// TarGzName returns the cache filename for edition's tar.gz archive.
+// MaxMind's Content-Disposition names include a release date
+// (e.g. GeoLite2-ASN_20260101.tar.gz); we use _LATEST so httpcache's
+// ETag sidecar stays tied to a stable path across releases.
+func TarGzName(edition string) string {
+ return edition + "_LATEST.tar.gz"
+}
+
// DefaultConfPaths returns the standard locations where GeoIP.conf is looked
// up: ./GeoIP.conf, then ~/.config/maxmind/GeoIP.conf.
func DefaultConfPaths() []string {
diff --git a/net/geoip/geoip_integration_test.go b/net/geoip/geoip_integration_test.go
index ff155c0..55a9893 100644
--- a/net/geoip/geoip_integration_test.go
+++ b/net/geoip/geoip_integration_test.go
@@ -64,7 +64,7 @@ func TestDownload_CityAndASN(t *testing.T) {
td := testdataDir(t)
for _, edition := range []string{geoip.CityEdition, geoip.ASNEdition} {
- path := filepath.Join(td, edition+".tar.gz")
+ path := filepath.Join(td, geoip.TarGzName(edition))
os.Remove(path)
os.Remove(path + ".meta")
@@ -96,7 +96,7 @@ func TestDownload_ConditionalGet_FreshCacher(t *testing.T) {
td := testdataDir(t)
for _, edition := range []string{geoip.CityEdition, geoip.ASNEdition} {
- path := filepath.Join(td, edition+".tar.gz")
+ path := filepath.Join(td, geoip.TarGzName(edition))
if _, err := newCacher(cfg, edition, path).Fetch(); err != nil {
t.Fatalf("%s initial Fetch: %v", edition, err)