diff options
author | Wolfy-J <[email protected]> | 2019-06-24 13:35:04 +0300 |
---|---|---|
committer | Wolfy-J <[email protected]> | 2019-06-24 13:35:04 +0300 |
commit | 5dc7dd6b231ccea05ffbec0df47ecaa866192308 (patch) | |
tree | 7959b582590bfbe15205480e64de2f14de2d6b47 /service/headers | |
parent | 464baf2eb7bd87ed80332280e8f73faa2d495746 (diff) |
polishing fastcgi integration, polishing headers service (splitted from http)
Diffstat (limited to 'service/headers')
-rw-r--r-- | service/headers/config.go | 41 | ||||
-rw-r--r-- | service/headers/service.go | 115 |
2 files changed, 156 insertions, 0 deletions
diff --git a/service/headers/config.go b/service/headers/config.go new file mode 100644 index 00000000..bb7a6b2b --- /dev/null +++ b/service/headers/config.go @@ -0,0 +1,41 @@ +package headers + +import "github.com/spiral/roadrunner/service" + +// Config declares headers service configuration. +type Config struct { + // CORS settings. + CORS *CORSConfig + + // Request headers to add to every payload send to PHP. + Request map[string]string + + // Response headers to add to every payload generated by PHP. + Response map[string]string +} + +// CORS headers configuration. +type CORSConfig struct { + // AllowedOrigin: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin + AllowedOrigin string + + // AllowedHeaders: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers + AllowedHeaders string + + // AllowedMethods: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods + AllowedMethods string + + // AllowCredentials https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Credentials + AllowCredentials *bool + + // ExposeHeaders: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Expose-Headers + ExposedHeaders string + + // MaxAge of CORS headers in seconds/ + MaxAge int +} + +// Hydrate service config. +func (c *Config) Hydrate(cfg service.Config) error { + return cfg.Unmarshal(c) +} diff --git a/service/headers/service.go b/service/headers/service.go new file mode 100644 index 00000000..9060e9ff --- /dev/null +++ b/service/headers/service.go @@ -0,0 +1,115 @@ +package headers + +import ( + rrhttp "github.com/spiral/roadrunner/service/http" + "net/http" + "strconv" +) + +const ( + // ID contains default service name. + ID = "headers" +) + +// Service serves static files. Potentially convert into middleware? +type Service struct { + // server configuration (location, forbidden files and etc) + cfg *Config +} + +// Init must return configure service and return true if service hasStatus enabled. Must return error in case of +// misconfiguration. Services must not be used without proper configuration pushed first. +func (s *Service) Init(cfg *Config, r *rrhttp.Service) (bool, error) { + if r == nil { + return false, nil + } + + s.cfg = cfg + r.AddMiddleware(s.middleware) + + return true, nil +} + +// middleware must return true if request/response pair is handled within the middleware. +func (s *Service) middleware(f http.HandlerFunc) http.HandlerFunc { + // Define the http.HandlerFunc + return func(w http.ResponseWriter, r *http.Request) { + + if s.cfg.Request != nil { + for k, v := range s.cfg.Request { + r.Header.Add(k, v) + } + } + + if s.cfg.Response != nil { + for k, v := range s.cfg.Response { + w.Header().Set(k, v) + } + } + + if s.cfg.CORS != nil { + if r.Method == http.MethodOptions { + s.preflightRequest(w, r) + return + } + + s.corsHeaders(w, r) + } + + f(w, r) + } +} + +// configure OPTIONS response +func (s *Service) preflightRequest(w http.ResponseWriter, r *http.Request) { + headers := w.Header() + + headers.Add("Vary", "Origin") + headers.Add("Vary", "Access-Control-Request-Method") + headers.Add("Vary", "Access-Control-Request-Headers") + + if s.cfg.CORS.AllowedOrigin != "" { + headers.Set("Access-Control-Allow-Origin", s.cfg.CORS.AllowedOrigin) + } + + if s.cfg.CORS.AllowedHeaders != "" { + headers.Set("Access-Control-Allow-Headers", s.cfg.CORS.AllowedHeaders) + } + + if s.cfg.CORS.AllowedMethods != "" { + headers.Set("Access-Control-Allow-Methods", s.cfg.CORS.AllowedMethods) + } + + if s.cfg.CORS.AllowCredentials != nil { + headers.Set("Access-Control-Allow-Credentials", strconv.FormatBool(*s.cfg.CORS.AllowCredentials)) + } + + if s.cfg.CORS.MaxAge > 0 { + headers.Set("Access-Control-Max-Age", strconv.Itoa(s.cfg.CORS.MaxAge)) + } + + w.WriteHeader(http.StatusOK) +} + +// configure CORS headers +func (s *Service) corsHeaders(w http.ResponseWriter, r *http.Request) { + headers := w.Header() + + headers.Add("Vary", "Origin") + + if s.cfg.CORS.AllowedOrigin != "" { + headers.Set("Access-Control-Allow-Origin", s.cfg.CORS.AllowedOrigin) + } + + if s.cfg.CORS.AllowedHeaders != "" { + headers.Set("Access-Control-Allow-Headers", s.cfg.CORS.AllowedHeaders) + } + + if s.cfg.CORS.ExposedHeaders != "" { + headers.Set("Access-Control-Expose-Headers", s.cfg.CORS.ExposedHeaders) + } + + if s.cfg.CORS.AllowCredentials != nil { + headers.Set("Access-Control-Allow-Credentials", strconv.FormatBool(*s.cfg.CORS.AllowCredentials)) + } +} |