summaryrefslogtreecommitdiff
path: root/service/headers
diff options
context:
space:
mode:
authorWolfy-J <[email protected]>2019-06-24 13:35:04 +0300
committerWolfy-J <[email protected]>2019-06-24 13:35:04 +0300
commit5dc7dd6b231ccea05ffbec0df47ecaa866192308 (patch)
tree7959b582590bfbe15205480e64de2f14de2d6b47 /service/headers
parent464baf2eb7bd87ed80332280e8f73faa2d495746 (diff)
polishing fastcgi integration, polishing headers service (splitted from http)
Diffstat (limited to 'service/headers')
-rw-r--r--service/headers/config.go41
-rw-r--r--service/headers/service.go115
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))
+ }
+}