diff --git a/atlas/atlas.go b/atlas/atlas.go index 06677c651..5ea55e0a5 100644 --- a/atlas/atlas.go +++ b/atlas/atlas.go @@ -121,6 +121,10 @@ func (a *Atlas) SeedMapTile(ctx context.Context, m Map, z, x, y uint) error { return defaultAtlas.SeedMapTile(ctx, m, z, x, y) } + if len(m.Params) > 0 { + return nil + } + ctx = context.WithValue(ctx, observability.ObserveVarMapName, m.Name) // confirm we have a cache backend if a.cacher == nil { @@ -154,6 +158,10 @@ func (a *Atlas) PurgeMapTile(m Map, tile *tegola.Tile) error { return defaultAtlas.PurgeMapTile(m, tile) } + if len(m.Params) > 0 { + return nil + } + if a.cacher == nil { return ErrMissingCache } diff --git a/cache/cache.go b/cache/cache.go index d5d7609b6..9e7548270 100644 --- a/cache/cache.go +++ b/cache/cache.go @@ -38,6 +38,12 @@ func ParseKey(str string) (*Key, error) { // remove the base-path and the first slash, then split the parts keyParts := strings.Split(strings.TrimLeft(str, "/"), "/") + + // ignore /:map/:layer/:z/:x/:y?param=value queries + if len(keyParts) > 0 && strings.Contains(keyParts[len(keyParts)-1], "?") { + return nil, ErrParamsNotSupported{} + } + // we're expecting a z/x/y scheme if len(keyParts) < 3 || len(keyParts) > 5 { err = ErrInvalidFileKeyParts{ diff --git a/cache/cache_test.go b/cache/cache_test.go index b38175fb5..0bfa1de4a 100644 --- a/cache/cache_test.go +++ b/cache/cache_test.go @@ -11,6 +11,7 @@ func TestParseKey(t *testing.T) { testcases := []struct { input string expected *cache.Key + err error }{ { input: "/12/11/123", @@ -19,6 +20,7 @@ func TestParseKey(t *testing.T) { X: 11, Y: 123, }, + err: nil, }, { input: "/osm/12/11/123", @@ -28,6 +30,7 @@ func TestParseKey(t *testing.T) { Y: 123, MapName: "osm", }, + err: nil, }, { input: "/osm/buildings/12/11/123", @@ -38,13 +41,19 @@ func TestParseKey(t *testing.T) { MapName: "osm", LayerName: "buildings", }, + err: nil, + }, + { + input: "/osm/buildings/12/11/123?param=value", + expected: nil, + err: cache.ErrParamsNotSupported{}, }, } for i, tc := range testcases { output, err := cache.ParseKey(tc.input) - if err != nil { - t.Errorf("testcase (%v) failed. err: %v", i, err) + if err != tc.err { + t.Errorf("testcase (%v) failed. expected err (%+v) does not match error (%+v)", i, tc.err, err) continue } diff --git a/cache/errors.go b/cache/errors.go index 5bc91a7f5..17eca472f 100644 --- a/cache/errors.go +++ b/cache/errors.go @@ -47,3 +47,10 @@ type ErrPurgingCache struct { func (e ErrPurgingCache) Error() string { return fmt.Sprintf("cache: error purging (%v) cache: %v", e.CacheType, e.Err) } + +// This error should never be printed to a user, the config validator already warns about this +type ErrParamsNotSupported struct{} + +func (e ErrParamsNotSupported) Error() string { + return "cache: caching is disabled for maps with custom parameters" +} diff --git a/config/config.go b/config/config.go index e4dd0ca48..aef1a70fa 100644 --- a/config/config.go +++ b/config/config.go @@ -196,6 +196,8 @@ func (c *Config) Validate() error { // check for map layer name / zoom collisions // map of layers to providers mapLayers := map[string]map[string]provider.MapLayer{} + // maps with configured parameters for logging + mapsWithCustomParams := []string{} for mapKey, m := range c.Maps { // validate any declared query parameters @@ -203,6 +205,10 @@ func (c *Config) Validate() error { return err } + if len(m.Parameters) > 0 { + mapsWithCustomParams = append(mapsWithCustomParams, string(m.Name)) + } + if _, ok := mapLayers[string(m.Name)]; !ok { mapLayers[string(m.Name)] = map[string]provider.MapLayer{} } @@ -300,6 +306,13 @@ func (c *Config) Validate() error { } } + if len(mapsWithCustomParams) > 0 { + log.Infof( + "Caching is disabled for these maps, since they have configured custom parameters: %s", + strings.Join(mapsWithCustomParams, ", "), + ) + } + // check for blacklisted headers for k := range c.Webserver.Headers { for _, v := range blacklistHeaders { diff --git a/server/middleware_tile_cache.go b/server/middleware_tile_cache.go index a187da91d..8b85a45e4 100644 --- a/server/middleware_tile_cache.go +++ b/server/middleware_tile_cache.go @@ -2,6 +2,7 @@ package server import ( "bytes" + "errors" "fmt" "io" "net/http" @@ -30,7 +31,10 @@ func TileCacheHandler(a *atlas.Atlas, next http.Handler) http.Handler { // parse our URI into a cache key structure (remove any configured URIPrefix + "maps/" ) key, err := cache.ParseKey(strings.TrimPrefix(r.URL.Path, path.Join(URIPrefix, "maps"))) - if err != nil { + if errors.Is(err, cache.ErrParamsNotSupported{}) { + next.ServeHTTP(w, r) + return + } else if err != nil { log.Errorf("cache middleware: ParseKey err: %v", err) next.ServeHTTP(w, r) return