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  }