ENH: Add support for returning missing images as HTTP 404 instead of blank PNGs (#177)

This commit is contained in:
Brendan Ward 2024-01-17 09:51:41 -08:00 committed by GitHub
parent 8403335a48
commit 04d08f1258
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 91 additions and 59 deletions

View File

@ -2,6 +2,10 @@
## 0.11.0 (in development)
- support returning missing image tiles as HTTP 404 instead of blank tiles using
the `--missing-image-tile-404` option (#177).
## 0.10.0
- supports GCC11 on Ubuntu 22.04 (#166)

View File

@ -53,14 +53,16 @@ From within the repository root ($GOPATH/bin needs to be in your $PATH):
```
$ mbtileserver --help
Serve tiles from mbtiles files.
Serve tiles from mbtiles files
Usage:
mbtileserver [flags]
Flags:
--basemap-style-url string Basemap style URL for preview endpoint (can include authorization token parameter if required by host)
--basemap-tiles-url string Basemap raster tiles URL pattern for preview endpoint (can include authorization token parameter if required by host): https://some.host/{z}/{x}/{y}.png
-c, --cert string X.509 TLS certificate filename. If present, will be used to enable SSL on the server.
-d, --dir string Directory containing mbtiles files. Directory containing mbtiles files. Can be a comma-delimited list of directories. (default "./tilesets")
-d, --dir string Directory containing mbtiles files. Can be a comma-delimited list of directories. (default "./tilesets")
--disable-preview Disable map preview for each tileset (enabled by default)
--disable-svc-list Disable services list endpoint (enabled by default)
--disable-tilejson Disable TileJSON endpoint for each tileset (enabled by default)
@ -71,7 +73,9 @@ Flags:
--enable-reload-signal Enable graceful reload using HUP signal to the server process
--generate-ids Automatically generate tileset IDs instead of using relative path
-h, --help help for mbtileserver
--host string IP address to listen on. Default is all interfaces. (default "0.0.0.0")
-k, --key string TLS private key
--missing-image-tile-404 Return HTTP 404 error code when image tile is misssing instead of default behavior to return blank PNG
-p, --port int Server port. Default is 443 if --cert or --tls options are used, otherwise 8000. (default -1)
-r, --redirect Redirect HTTP to HTTPS
--root-url string Root URL of services endpoint (default "/services")
@ -306,6 +310,18 @@ These are provided at:
where `<format>` is one of `png`, `jpg`, `webp`, `pbf` depending on the type of data in the tileset.
### Missing tiles
Missing vector tiles are always returned as HTTP 204.
Missing image tiles are returned as blank PNGs with the same dimensions as the tileset to give seamless display of
these tiles in interactive maps.
When serving image tiles that encode data (e.g., terrain) instead of purely for display, this can cause issues. In
this case, you can use the `--missing-image-tile-404` option. This behavior will be applied to all image tilesets.
## TileJSON API
`mbtileserver` automatically creates a TileJSON endpoint for each service at `/services/<tileset_id>`.

View File

@ -19,6 +19,7 @@ type ServiceSetConfig struct {
EnableArcGIS bool
BasemapStyleURL string
BasemapTilesURL string
ReturnMissingImageTile404 bool
RootURL *url.URL
ErrorWriter io.Writer
}
@ -34,6 +35,7 @@ type ServiceSet struct {
enableArcGIS bool
basemapStyleURL string
basemapTilesURL string
returnMissingImageTile404 bool
rootURL *url.URL
errorWriter io.Writer
@ -55,6 +57,7 @@ func New(cfg *ServiceSetConfig) (*ServiceSet, error) {
enableArcGIS: cfg.EnableArcGIS,
basemapStyleURL: cfg.BasemapStyleURL,
basemapTilesURL: cfg.BasemapTilesURL,
returnMissingImageTile404: cfg.ReturnMissingImageTile404,
rootURL: cfg.RootURL,
errorWriter: cfg.ErrorWriter,
}

View File

@ -219,7 +219,7 @@ func (ts *Tileset) tileHandler(w http.ResponseWriter, r *http.Request) {
if ts == nil || !ts.published {
// In order to not break any requests from when this tileset was published
// return the appropriate not found handler for the original tile format.
tileNotFoundHandler(w, r, ts.tileformat, ts.tilesize)
tileNotFoundHandler(w, r, ts.tileformat, ts.tilesize, ts.svc.returnMissingImageTile404)
return
}
@ -255,7 +255,7 @@ func (ts *Tileset) tileHandler(w http.ResponseWriter, r *http.Request) {
return
}
if data == nil || len(data) <= 1 {
tileNotFoundHandler(w, r, ts.tileformat, ts.tilesize)
tileNotFoundHandler(w, r, ts.tileformat, ts.tilesize, ts.svc.returnMissingImageTile404)
return
}
@ -327,13 +327,18 @@ func (ts *Tileset) previewHandler(w http.ResponseWriter, r *http.Request) {
// tileNotFoundHandler is an http.HandlerFunc that writes the default response
// for a non-existing tile of type f to w
func tileNotFoundHandler(w http.ResponseWriter, r *http.Request, f mbtiles.TileFormat, tilesize uint32) {
func tileNotFoundHandler(w http.ResponseWriter, r *http.Request, f mbtiles.TileFormat, tilesize uint32, returnMissingImageTile404 bool) {
switch f {
case mbtiles.PNG, mbtiles.JPG, mbtiles.WEBP:
if returnMissingImageTile404 {
// Return 404
w.WriteHeader(http.StatusNotFound)
} else {
// Return blank PNG for all image types
w.Header().Set("Content-Type", "image/png")
w.WriteHeader(http.StatusOK)
w.Write(BlankPNG(tilesize))
}
case mbtiles.PBF:
// Return 204
w.WriteHeader(http.StatusNoContent)

View File

@ -82,6 +82,7 @@ var (
tilesOnly bool
basemapStyleURL string
basemapTilesURL string
missingImageTile404 bool
)
func init() {
@ -112,6 +113,8 @@ func init() {
flags.StringVar(&basemapStyleURL, "basemap-style-url", "", "Basemap style URL for preview endpoint (can include authorization token parameter if required by host)")
flags.StringVar(&basemapTilesURL, "basemap-tiles-url", "", "Basemap raster tiles URL pattern for preview endpoint (can include authorization token parameter if required by host): https://some.host/{z}/{x}/{y}.png")
flags.BoolVarP(&missingImageTile404, "missing-image-tile-404", "", false, "Return HTTP 404 error code when image tile is misssing instead of default behavior to return blank PNG")
flags.BoolVarP(&verbose, "verbose", "v", false, "Verbose logging")
if env := os.Getenv("HOST"); env != "" {
@ -300,6 +303,7 @@ func serve() {
EnableArcGIS: enableArcGIS,
BasemapStyleURL: basemapStyleURL,
BasemapTilesURL: basemapTilesURL,
ReturnMissingImageTile404: missingImageTile404,
})
if err != nil {
log.Fatalln("Could not construct ServiceSet")