diff options
author | Anton Titov <[email protected]> | 2019-06-24 12:49:43 +0300 |
---|---|---|
committer | GitHub <[email protected]> | 2019-06-24 12:49:43 +0300 |
commit | 464baf2eb7bd87ed80332280e8f73faa2d495746 (patch) | |
tree | 93838ae9f56525983980a3f76ab60febfdfcf3d7 | |
parent | 85126b000d140efdd99573e44241ee1e8b84d3c5 (diff) | |
parent | 3b16dd837a203fc4865e94a031b64a83080e12ef (diff) |
Merge pull request #164 from ovr/middlewares-headers
Middlewares headers
-rw-r--r-- | .rr.yaml | 22 | ||||
-rw-r--r-- | service/http/config.go | 34 | ||||
-rw-r--r-- | service/http/service.go | 100 |
3 files changed, 156 insertions, 0 deletions
@@ -28,6 +28,28 @@ http: # ssl private key key: server.key + # HTTP service provides built-in middlewares + middlewares: + # Middleware to handle CORS requests, https://www.w3.org/TR/cors/ + cors: + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin + AllowedOrigin: "*" + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers + allowedHeaders: "*" + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods + allowedMethods: "GET,POST,PUT,DELETE" + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials + allowCredentials: true + # https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers + exposedHeaders: "Cache-Control,Content-Language,Content-Type,Expires,Last-Modified,Pragma" + maxAge: 600 + # Middleware that adding Headers to the Request / Response + headers: + customRequestHeaders: + "Example-Request-Header": "Value" + customResponseHeaders: + "X-Powered-By": "RoadRunner" + # HTTP service provides FastCGI as frontend fcgi: # FastCGI connection DSN. Supported TCP and Unix sockets. diff --git a/service/http/config.go b/service/http/config.go index 5454f124..e2f42626 100644 --- a/service/http/config.go +++ b/service/http/config.go @@ -33,10 +33,40 @@ type Config struct { // HTTP2 configuration HTTP2 *HTTP2Config + // Middlewares + Middlewares *MiddlewaresConfig + // Workers configures rr server and worker pool. Workers *roadrunner.ServerConfig } +type MiddlewaresConfig struct { + Headers *HeaderMiddlewareConfig + CORS *CORSMiddlewareConfig +} + +type CORSMiddlewareConfig struct { + AllowedOrigin string + AllowedMethods string + AllowedHeaders string + AllowCredentials *bool + ExposedHeaders string + MaxAge int +} + +type HeaderMiddlewareConfig struct { + CustomRequestHeaders map[string]string + CustomResponseHeaders map[string]string +} + +func (c *MiddlewaresConfig) EnableCORS() bool { + return c.CORS != nil +} + +func (c *MiddlewaresConfig) EnableHeaders() bool { + return c.Headers.CustomRequestHeaders != nil || c.Headers.CustomResponseHeaders != nil +} + type FCGIConfig struct { // Port and port to handle as http server. Address string @@ -73,6 +103,10 @@ func (c *Config) EnableHTTP() bool { return c.Address != "" } +func (c *Config) EnableMiddlewares() bool { + return c.Middlewares != nil +} + // EnableTLS returns true if rr must listen TLS connections. func (c *Config) EnableTLS() bool { return c.SSL.Key != "" || c.SSL.Cert != "" diff --git a/service/http/service.go b/service/http/service.go index 00d877ec..f394f6af 100644 --- a/service/http/service.go +++ b/service/http/service.go @@ -12,6 +12,7 @@ import ( "net/http" "net/http/fcgi" "net/url" + "strconv" "strings" "sync" ) @@ -95,6 +96,10 @@ func (s *Service) Serve() error { s.rr.Attach(s.controller) } + if s.cfg.EnableMiddlewares() { + s.initMiddlewares() + } + s.handler = &Handler{cfg: s.cfg, rr: s.rr} s.handler.Listen(s.throw) @@ -247,3 +252,98 @@ func (s *Service) tlsAddr(host string, forcePort bool) string { return host } + +func (s *Service) headersMiddleware(f http.HandlerFunc) http.HandlerFunc { + // Define the http.HandlerFunc + return func(w http.ResponseWriter, r *http.Request) { + if s.cfg.Middlewares.Headers.CustomRequestHeaders != nil { + for k, v := range s.cfg.Middlewares.Headers.CustomRequestHeaders { + r.Header.Add(k, v) + } + } + + if s.cfg.Middlewares.Headers.CustomResponseHeaders != nil { + for k, v := range s.cfg.Middlewares.Headers.CustomResponseHeaders { + w.Header().Set(k, v) + } + } + + f(w, r) + } +} + +func handlePreflightRequest(w http.ResponseWriter, r *http.Request, options *CORSMiddlewareConfig) { + headers := w.Header() + + headers.Add("Vary", "Origin") + headers.Add("Vary", "Access-Control-Request-Method") + headers.Add("Vary", "Access-Control-Request-Headers") + + if options.AllowedOrigin != "" { + headers.Set("Access-Control-Allow-Origin", options.AllowedOrigin) + } + + if options.AllowedHeaders != "" { + headers.Set("Access-Control-Allow-Headers", options.AllowedHeaders) + } + + if options.AllowedMethods != "" { + headers.Set("Access-Control-Allow-Methods", options.AllowedMethods) + } + + if options.AllowCredentials != nil { + headers.Set("Access-Control-Allow-Credentials", strconv.FormatBool(*options.AllowCredentials)) + } + + if options.MaxAge > 0 { + headers.Set("Access-Control-Max-Age", strconv.Itoa(options.MaxAge)) + } + + w.WriteHeader(http.StatusOK); +} + +func addCORSHeaders(w http.ResponseWriter, r *http.Request, options *CORSMiddlewareConfig) { + headers := w.Header() + + headers.Add("Vary", "Origin") + + if options.AllowedOrigin != "" { + headers.Set("Access-Control-Allow-Origin", options.AllowedOrigin) + } + + if options.AllowedHeaders != "" { + headers.Set("Access-Control-Allow-Headers", options.AllowedHeaders) + } + + if options.ExposedHeaders != "" { + headers.Set("Access-Control-Expose-Headers", options.ExposedHeaders) + } + + if options.AllowCredentials != nil { + headers.Set("Access-Control-Allow-Credentials", strconv.FormatBool(*options.AllowCredentials)) + } +} + +func (s *Service) corsMiddleware(f http.HandlerFunc) http.HandlerFunc { + // Define the http.HandlerFunc + return func(w http.ResponseWriter, r *http.Request) { + if r.Method == http.MethodOptions { + handlePreflightRequest(w, r, s.cfg.Middlewares.CORS) + } else { + addCORSHeaders(w, r, s.cfg.Middlewares.CORS) + f(w, r) + } + } +} + +func (s *Service) initMiddlewares() error { + if s.cfg.Middlewares.EnableHeaders() { + s.AddMiddleware(s.headersMiddleware) + } + + if s.cfg.Middlewares.EnableCORS() { + s.AddMiddleware(s.corsMiddleware) + } + + return nil +} |