github.com/PDOK/gokoala@v0.50.6/internal/engine/router.go (about) 1 package engine 2 3 import ( 4 "net/http" 5 "runtime/debug" 6 "time" 7 8 "github.com/go-chi/chi/v5" 9 "github.com/go-chi/chi/v5/middleware" 10 "github.com/go-chi/cors" 11 ) 12 13 func newRouter(version string, enableTrailingSlash bool, enableCORS bool) *chi.Mux { 14 router := chi.NewRouter() 15 router.Use(middleware.RealIP) // should be first middleware 16 router.Use(middleware.Logger) // log to console 17 router.Use(problemRecoverer) // catch panics and turn into 500s 18 router.Use(middleware.GetHead) // support HEAD requests https://docs.ogc.org/is/17-069r4/17-069r4.html#_http_1_1 19 if enableTrailingSlash { 20 router.Use(middleware.StripSlashes) 21 } 22 if enableCORS { 23 router.Use(cors.Handler(cors.Options{ 24 AllowedOrigins: []string{"*"}, 25 AllowedMethods: []string{http.MethodGet, http.MethodHead, http.MethodOptions}, 26 AllowedHeaders: []string{HeaderRequestedWith}, 27 ExposedHeaders: []string{HeaderContentCrs, HeaderLink}, 28 AllowCredentials: false, 29 MaxAge: int((time.Hour * 24).Seconds()), 30 })) 31 } 32 // some GIS clients don't sent proper CORS preflight requests, still respond with OK for any OPTIONS request 33 router.Use(optionsFallback) 34 // add semver header, implements https://gitdocumentatie.logius.nl/publicatie/api/adr/#api-57 35 router.Use(middleware.SetHeader(HeaderAPIVersion, version)) 36 router.Use(middleware.Compress(5, CompressibleMediaTypes...)) // enable gzip responses 37 return router 38 } 39 40 func optionsFallback(next http.Handler) http.Handler { 41 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 42 if r.Method == http.MethodOptions { 43 w.WriteHeader(http.StatusOK) 44 return 45 } 46 next.ServeHTTP(w, r) 47 }) 48 } 49 50 // Custom middleware.Recoverer adapted from Chi (https://github.com/go-chi/chi/blob/master/middleware/recoverer.go) 51 // to return RFC-7807 Problem messages. 52 func problemRecoverer(next http.Handler) http.Handler { 53 return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { 54 defer func() { 55 if rvr := recover(); rvr != nil { 56 if rvr == http.ErrAbortHandler { //nolint:errorlint // already so in Chi 57 // we don't recover http.ErrAbortHandler so the response 58 // to the client is aborted, this should not be logged 59 panic(rvr) 60 } 61 62 logEntry := middleware.GetLogEntry(r) 63 if logEntry != nil { 64 logEntry.Panic(rvr, debug.Stack()) 65 } else { 66 middleware.PrintPrettyStack(rvr) 67 } 68 69 if r.Header.Get("Connection") != "Upgrade" { 70 RenderProblem(ProblemServerError, w) 71 } 72 } 73 }() 74 next.ServeHTTP(w, r) 75 }) 76 }