Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,10 @@ Under the `maps` section, map layers are associated with data provider layers an
[webserver]
port = ":9090" # port to bind the web server to. defaults ":8080"

[webserver.headers]
Access-Control-Allow-Origin = "*"
Cache-Control = "no-cache, no-store, must-revalidate"

[cache] # configure a tile cache
type = "file" # a file cache will cache to the local file system
basepath = "/tmp/tegola" # where to write the file cache
Expand Down
6 changes: 2 additions & 4 deletions cmd/tegola/cmd/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,8 @@ var serverCmd = &cobra.Command{
server.Version = Version
server.HostName = string(conf.Webserver.HostName)

// set the CORSAllowedOrigin if a value is provided
if conf.Webserver.CORSAllowedOrigin != "" {
server.CORSAllowedOrigin = string(conf.Webserver.CORSAllowedOrigin)
}
// set the http reply headers
server.Headers = conf.Webserver.Headers

// set tile buffer
if conf.TileBuffer != nil {
Expand Down
7 changes: 2 additions & 5 deletions cmd/tegola_lambda/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"os"

"github.com/arolek/algnhsa"

"github.com/go-spatial/tegola/atlas"
"github.com/go-spatial/tegola/cmd/internal/register"
"github.com/go-spatial/tegola/config"
Expand Down Expand Up @@ -81,10 +80,8 @@ func main() {
server.HostName = string(conf.Webserver.HostName)
}

// set the CORSAllowedOrigin if a value is provided
if conf.Webserver.CORSAllowedOrigin != "" {
server.CORSAllowedOrigin = string(conf.Webserver.CORSAllowedOrigin)
}
// set the http reply headers
server.Headers = conf.Webserver.Headers

// set tile buffer
if conf.TileBuffer != nil {
Expand Down
18 changes: 14 additions & 4 deletions config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ import (
"time"

"github.com/BurntSushi/toml"

"github.com/go-spatial/tegola"
"github.com/go-spatial/tegola/internal/env"
"github.com/go-spatial/tegola/internal/log"
)

var blacklistHeaders = []string{"content-encoding", "content-length", "content-type"}

// Config represents a tegola config file.
type Config struct {
// the tile buffer to use
Expand All @@ -34,9 +35,9 @@ type Config struct {
}

type Webserver struct {
HostName env.String `toml:"hostname"`
Port env.String `toml:"port"`
CORSAllowedOrigin env.String `toml:"cors_allowed_origin"`
HostName env.String `toml:"hostname"`
Port env.String `toml:"port"`
Headers env.Dict `toml:"headers"`
}

// A Map represents a map in the Tegola Config file.
Expand Down Expand Up @@ -126,6 +127,15 @@ func (c *Config) Validate() error {
}
}

// check for blacklisted headers
for k := range c.Webserver.Headers {
for _, v := range blacklistHeaders {
if v == strings.ToLower(k) {
return ErrInvalidHeader{Header: k}
}
}
}

return nil
}

Expand Down
27 changes: 24 additions & 3 deletions config/config_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,10 @@ func TestParse(t *testing.T) {
port = ":8080"
cors_allowed_origin = "tegola.io"

[webserver.headers]
Access-Control-Allow-Origin = "*"
Access-Control-Allow-Methods = "GET, OPTIONS"

[cache]
type = "file"
basepath = "/tmp/tegola-cache"
Expand Down Expand Up @@ -133,9 +137,12 @@ func TestParse(t *testing.T) {
TileBuffer: env.IntPtr(env.Int(12)),
LocationName: "",
Webserver: config.Webserver{
HostName: "cdn.tegola.io",
Port: ":8080",
CORSAllowedOrigin: "tegola.io",
HostName: "cdn.tegola.io",
Port: ":8080",
Headers: env.Dict{
"Access-Control-Allow-Origin": "*",
"Access-Control-Allow-Methods": "GET, OPTIONS",
},
},
Cache: env.Dict{
"type": "file",
Expand Down Expand Up @@ -690,6 +697,20 @@ func TestValidate(t *testing.T) {
ProviderLayer2: "provider2.water_default_z",
},
},
"6 blocked headers": {
config: config.Config{
LocationName: "",
Webserver: config.Webserver{
Port: ":8080",
Headers: env.Dict{
"Content-Encoding": "plain/text",
},
},
},
expectedErr: config.ErrInvalidHeader{
Header: "Content-Encoding",
},
},
}

for name, tc := range tests {
Expand Down
8 changes: 8 additions & 0 deletions config/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,3 +52,11 @@ type ErrMissingEnvVar struct {
func (e ErrMissingEnvVar) Error() string {
return fmt.Sprintf("config: config file is referencing an environment variable that is not set (%v)", e.EnvVar)
}

type ErrInvalidHeader struct {
Header string
}

func (e ErrInvalidHeader) Error() string {
return fmt.Sprintf("config: header (%v) blacklisted", e.Header)
}
20 changes: 0 additions & 20 deletions server/middleware_cors.go

This file was deleted.

23 changes: 23 additions & 0 deletions server/middleware_headers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
package server

import "net/http"

func HeadersHandler(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {

// default CORS headers. may be overwritten by the user
w.Header().Set("Access-Control-Allow-Origin", CORSAllowedOrigin)
w.Header().Set("Access-Control-Allow-Methods", CORSAllowedMethods)

for name, value := range Headers {
v, ok := value.(string)
if ok {
w.Header().Set(name, v)
}
}

next.ServeHTTP(w, r)

return
})
}
21 changes: 14 additions & 7 deletions server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
"strings"

"github.com/dimfeld/httptreemux"

"github.com/go-spatial/tegola"
"github.com/go-spatial/tegola/atlas"
"github.com/go-spatial/tegola/internal/log"
Expand Down Expand Up @@ -36,6 +35,14 @@ var (
// configurable via the tegola config.toml file (set in main.go)
CORSAllowedOrigin string = "*"

// CORSAllowedMethods is the "Access-Control-Allow-Methods" CORS header.
// configurable via the tegola config.toml file (set in main.go)
CORSAllowedMethods string = "GET, OPTIONS"

// Headers is the map of http reply headers.
// configurable via the tegola config.toml file (set in main.go)
Headers map[string]interface{}

// TileBuffer is the tile buffer to use.
// configurable via tegola config.tomal file (set in main.go)
TileBuffer float64 = tegola.DefaultTileBuffer
Expand All @@ -50,16 +57,16 @@ func NewRouter(a *atlas.Atlas) *httptreemux.TreeMux {
r.OptionsHandler = corsHandler

// capabilities endpoints
group.UsingContext().Handler("GET", "/capabilities", CORSHandler(HandleCapabilities{}))
group.UsingContext().Handler("GET", "/capabilities/:map_name", CORSHandler(HandleMapCapabilities{}))
group.UsingContext().Handler("GET", "/capabilities", HeadersHandler(HandleCapabilities{}))
group.UsingContext().Handler("GET", "/capabilities/:map_name", HeadersHandler(HandleMapCapabilities{}))

// map tiles
hMapLayerZXY := HandleMapLayerZXY{Atlas: a}
group.UsingContext().Handler("GET", "/maps/:map_name/:z/:x/:y", CORSHandler(GZipHandler(TileCacheHandler(a, hMapLayerZXY))))
group.UsingContext().Handler("GET", "/maps/:map_name/:layer_name/:z/:x/:y", CORSHandler(GZipHandler(TileCacheHandler(a, hMapLayerZXY))))
group.UsingContext().Handler("GET", "/maps/:map_name/:z/:x/:y", HeadersHandler(GZipHandler(TileCacheHandler(a, hMapLayerZXY))))
group.UsingContext().Handler("GET", "/maps/:map_name/:layer_name/:z/:x/:y", HeadersHandler(GZipHandler(TileCacheHandler(a, hMapLayerZXY))))

// map style
group.UsingContext().Handler("GET", "/maps/:map_name/style.json", CORSHandler(HandleMapStyle{}))
group.UsingContext().Handler("GET", "/maps/:map_name/style.json", HeadersHandler(HandleMapStyle{}))

// setup viewer routes, which can be excluded via build flags
setupViewer(group)
Expand Down Expand Up @@ -148,6 +155,6 @@ var URLRoot = func(r *http.Request) string {
// corsHanlder is used to respond to all OPTIONS requests for registered routes
func corsHandler(w http.ResponseWriter, r *http.Request, params map[string]string) {
w.Header().Set("Access-Control-Allow-Origin", CORSAllowedOrigin)
w.Header().Set("Access-Control-Allow-Methods", "GET, OPTIONS")
w.Header().Set("Access-Control-Allow-Methods", CORSAllowedMethods)
return
}