diff options
author | Valery Piashchynski <[email protected]> | 2021-01-21 13:25:36 +0300 |
---|---|---|
committer | Valery Piashchynski <[email protected]> | 2021-01-21 13:25:36 +0300 |
commit | 7da6c78449776e1f3c6716250bca0b712a0423a4 (patch) | |
tree | f3512de66aca2bba408485a0ea2fc936c0e4fb9b /plugins/http | |
parent | 0ff05b2732b4fd0783f959c94c54d7e39169f979 (diff) |
Uniform all configs
Add debug server
Check nil's for all plugin intialization
Diffstat (limited to 'plugins/http')
-rw-r--r-- | plugins/http/config/fcgi.go | 7 | ||||
-rw-r--r-- | plugins/http/config/http.go (renamed from plugins/http/config.go) | 158 | ||||
-rw-r--r-- | plugins/http/config/http2.go | 28 | ||||
-rw-r--r-- | plugins/http/config/ip.go | 26 | ||||
-rw-r--r-- | plugins/http/config/ssl.go | 19 | ||||
-rw-r--r-- | plugins/http/config/uploads_config.go (renamed from plugins/http/uploads_config.go) | 12 | ||||
-rw-r--r-- | plugins/http/handler.go | 15 | ||||
-rw-r--r-- | plugins/http/parse.go | 4 | ||||
-rw-r--r-- | plugins/http/plugin.go | 39 | ||||
-rw-r--r-- | plugins/http/request.go | 3 | ||||
-rw-r--r-- | plugins/http/uploads.go | 5 |
11 files changed, 161 insertions, 155 deletions
diff --git a/plugins/http/config/fcgi.go b/plugins/http/config/fcgi.go new file mode 100644 index 00000000..3d4acbe1 --- /dev/null +++ b/plugins/http/config/fcgi.go @@ -0,0 +1,7 @@ +package config + +// FCGI for FastCGI server. +type FCGI struct { + // Address and port to handle as http server. + Address string +} diff --git a/plugins/http/config.go b/plugins/http/config/http.go index e272e550..76547fde 100644 --- a/plugins/http/config.go +++ b/plugins/http/config/http.go @@ -1,4 +1,4 @@ -package http +package config import ( "net" @@ -11,42 +11,19 @@ import ( poolImpl "github.com/spiral/roadrunner/v2/pkg/pool" ) -// Cidrs is a slice of IPNet addresses -type Cidrs []*net.IPNet - -// IsTrusted checks if the ip address exists in the provided in the config addresses -func (c *Cidrs) IsTrusted(ip string) bool { - if len(*c) == 0 { - return false - } - - i := net.ParseIP(ip) - if i == nil { - return false - } - - for _, cird := range *c { - if cird.Contains(i) { - return true - } - } - - return false -} - -// Config configures RoadRunner HTTP server. -type Config struct { +// HTTP configures RoadRunner HTTP server. +type HTTP struct { // Port and port to handle as http server. Address string - // SSL defines https server options. - SSL *SSLConfig + // SSLConfig defines https server options. + SSLConfig *SSL `mapstructure:"ssl"` - // FCGI configuration. You can use FastCGI without HTTP server. - FCGI *FCGIConfig + // FCGIConfig configuration. You can use FastCGI without HTTP server. + FCGIConfig *FCGI `mapstructure:"fcgi"` - // HTTP2 configuration - HTTP2 *HTTP2Config + // HTTP2Config configuration + HTTP2Config *HTTP2 `mapstructure:"http2"` // MaxRequestSize specified max size for payload body in megabytes, set 0 to unlimited. MaxRequestSize uint64 `mapstructure:"max_request_size"` @@ -55,7 +32,7 @@ type Config struct { TrustedSubnets []string `mapstructure:"trusted_subnets"` // Uploads configures uploads configuration. - Uploads *UploadsConfig + Uploads *Uploads `mapstructure:"uploads"` // Pool configures worker pool. Pool *poolImpl.Config `mapstructure:"pool"` @@ -67,80 +44,31 @@ type Config struct { Middleware []string // slice of net.IPNet - cidrs Cidrs -} - -// FCGIConfig for FastCGI server. -type FCGIConfig struct { - // Address and port to handle as http server. - Address string -} - -// HTTP2Config HTTP/2 server customizations. -type HTTP2Config struct { - // Enable or disable HTTP/2 extension, default enable. - Enabled bool - - // H2C enables HTTP/2 over TCP - H2C bool - - // MaxConcurrentStreams defaults to 128. - MaxConcurrentStreams uint32 `mapstructure:"max_concurrent_streams"` -} - -// InitDefaults sets default values for HTTP/2 configuration. -func (cfg *HTTP2Config) InitDefaults() error { - cfg.Enabled = true - cfg.MaxConcurrentStreams = 128 - - return nil -} - -// SSLConfig defines https server configuration. -type SSLConfig struct { - // Port to listen as HTTPS server, defaults to 443. - Port int - - // Redirect when enabled forces all http connections to switch to https. - Redirect bool - - // Key defined private server key. - Key string - - // Cert is https certificate. - Cert string - - // Root CA file - RootCA string + Cidrs Cidrs } // EnableHTTP is true when http server must run. -func (c *Config) EnableHTTP() bool { +func (c *HTTP) EnableHTTP() bool { return c.Address != "" } // EnableTLS returns true if pool must listen TLS connections. -func (c *Config) EnableTLS() bool { - return c.SSL.Key != "" || c.SSL.Cert != "" || c.SSL.RootCA != "" -} - -// EnableHTTP2 when HTTP/2 extension must be enabled (only with TSL). -func (c *Config) EnableHTTP2() bool { - return c.HTTP2.Enabled +func (c *HTTP) EnableTLS() bool { + return c.SSLConfig.Key != "" || c.SSLConfig.Cert != "" || c.SSLConfig.RootCA != "" } // EnableH2C when HTTP/2 extension must be enabled on TCP. -func (c *Config) EnableH2C() bool { - return c.HTTP2.H2C +func (c *HTTP) EnableH2C() bool { + return c.HTTP2Config.H2C } // EnableFCGI is true when FastCGI server must be enabled. -func (c *Config) EnableFCGI() bool { - return c.FCGI.Address != "" +func (c *HTTP) EnableFCGI() bool { + return c.FCGIConfig.Address != "" } -// InitDefaults must populate Config values using given Config source. Must return error if Config is not valid. -func (c *Config) InitDefaults() error { +// InitDefaults must populate HTTP values using given HTTP source. Must return error if HTTP is not valid. +func (c *HTTP) InitDefaults() error { if c.Pool == nil { // default pool c.Pool = &poolImpl.Config{ @@ -153,27 +81,27 @@ func (c *Config) InitDefaults() error { } } - if c.HTTP2 == nil { - c.HTTP2 = &HTTP2Config{} + if c.HTTP2Config == nil { + c.HTTP2Config = &HTTP2{} } - if c.FCGI == nil { - c.FCGI = &FCGIConfig{} + if c.FCGIConfig == nil { + c.FCGIConfig = &FCGI{} } if c.Uploads == nil { - c.Uploads = &UploadsConfig{} + c.Uploads = &Uploads{} } - if c.SSL == nil { - c.SSL = &SSLConfig{} + if c.SSLConfig == nil { + c.SSLConfig = &SSL{} } - if c.SSL.Port == 0 { - c.SSL.Port = 443 + if c.SSLConfig.Port == 0 { + c.SSLConfig.Port = 443 } - err := c.HTTP2.InitDefaults() + err := c.HTTP2Config.InitDefaults() if err != nil { return err } @@ -199,7 +127,7 @@ func (c *Config) InitDefaults() error { if err != nil { return err } - c.cidrs = cidrs + c.Cidrs = cidrs return c.Valid() } @@ -220,8 +148,8 @@ func ParseCIDRs(subnets []string) (Cidrs, error) { } // IsTrusted if api can be trusted to use X-Real-Ip, X-Forwarded-For -func (c *Config) IsTrusted(ip string) bool { - if c.cidrs == nil { +func (c *HTTP) IsTrusted(ip string) bool { + if c.Cidrs == nil { return false } @@ -230,7 +158,7 @@ func (c *Config) IsTrusted(ip string) bool { return false } - for _, cird := range c.cidrs { + for _, cird := range c.Cidrs { if cird.Contains(i) { return true } @@ -240,13 +168,13 @@ func (c *Config) IsTrusted(ip string) bool { } // Valid validates the configuration. -func (c *Config) Valid() error { +func (c *HTTP) Valid() error { const op = errors.Op("validation") if c.Uploads == nil { return errors.E(op, errors.Str("malformed uploads config")) } - if c.HTTP2 == nil { + if c.HTTP2Config == nil { return errors.E(op, errors.Str("malformed http2 config")) } @@ -263,27 +191,27 @@ func (c *Config) Valid() error { } if c.EnableTLS() { - if _, err := os.Stat(c.SSL.Key); err != nil { + if _, err := os.Stat(c.SSLConfig.Key); err != nil { if os.IsNotExist(err) { - return errors.E(op, errors.Errorf("key file '%s' does not exists", c.SSL.Key)) + return errors.E(op, errors.Errorf("key file '%s' does not exists", c.SSLConfig.Key)) } return err } - if _, err := os.Stat(c.SSL.Cert); err != nil { + if _, err := os.Stat(c.SSLConfig.Cert); err != nil { if os.IsNotExist(err) { - return errors.E(op, errors.Errorf("cert file '%s' does not exists", c.SSL.Cert)) + return errors.E(op, errors.Errorf("cert file '%s' does not exists", c.SSLConfig.Cert)) } return err } // RootCA is optional, but if provided - check it - if c.SSL.RootCA != "" { - if _, err := os.Stat(c.SSL.RootCA); err != nil { + if c.SSLConfig.RootCA != "" { + if _, err := os.Stat(c.SSLConfig.RootCA); err != nil { if os.IsNotExist(err) { - return errors.E(op, errors.Errorf("root ca path provided, but path '%s' does not exists", c.SSL.RootCA)) + return errors.E(op, errors.Errorf("root ca path provided, but path '%s' does not exists", c.SSLConfig.RootCA)) } return err } diff --git a/plugins/http/config/http2.go b/plugins/http/config/http2.go new file mode 100644 index 00000000..b1e109e9 --- /dev/null +++ b/plugins/http/config/http2.go @@ -0,0 +1,28 @@ +package config + +// HTTP2 HTTP/2 server customizations. +type HTTP2 struct { + // h2cHandler is a Handler which implements h2c by hijacking the HTTP/1 traffic + // that should be h2c traffic. There are two ways to begin a h2c connection + // (RFC 7540 Section 3.2 and 3.4): (1) Starting with Prior Knowledge - this + // works by starting an h2c connection with a string of bytes that is valid + // HTTP/1, but unlikely to occur in practice and (2) Upgrading from HTTP/1 to + // h2c - this works by using the HTTP/1 Upgrade header to request an upgrade to + // h2c. When either of those situations occur we hijack the HTTP/1 connection, + // convert it to a HTTP/2 connection and pass the net.Conn to http2.ServeConn. + + // H2C enables HTTP/2 over TCP + H2C bool + + // MaxConcurrentStreams defaults to 128. + MaxConcurrentStreams uint32 `mapstructure:"max_concurrent_streams"` +} + +// InitDefaults sets default values for HTTP/2 configuration. +func (cfg *HTTP2) InitDefaults() error { + if cfg.MaxConcurrentStreams == 0 { + cfg.MaxConcurrentStreams = 128 + } + + return nil +} diff --git a/plugins/http/config/ip.go b/plugins/http/config/ip.go new file mode 100644 index 00000000..c4981f74 --- /dev/null +++ b/plugins/http/config/ip.go @@ -0,0 +1,26 @@ +package config + +import "net" + +// Cidrs is a slice of IPNet addresses +type Cidrs []*net.IPNet + +// IsTrusted checks if the ip address exists in the provided in the config addresses +func (c *Cidrs) IsTrusted(ip string) bool { + if len(*c) == 0 { + return false + } + + i := net.ParseIP(ip) + if i == nil { + return false + } + + for _, cird := range *c { + if cird.Contains(i) { + return true + } + } + + return false +} diff --git a/plugins/http/config/ssl.go b/plugins/http/config/ssl.go new file mode 100644 index 00000000..aae6e920 --- /dev/null +++ b/plugins/http/config/ssl.go @@ -0,0 +1,19 @@ +package config + +// SSL defines https server configuration. +type SSL struct { + // Port to listen as HTTPS server, defaults to 443. + Port int + + // Redirect when enabled forces all http connections to switch to https. + Redirect bool + + // Key defined private server key. + Key string + + // Cert is https certificate. + Cert string + + // Root CA file + RootCA string +} diff --git a/plugins/http/uploads_config.go b/plugins/http/config/uploads_config.go index 4c20c8e8..5edb0ab7 100644 --- a/plugins/http/uploads_config.go +++ b/plugins/http/config/uploads_config.go @@ -1,4 +1,4 @@ -package http +package config import ( "os" @@ -6,8 +6,8 @@ import ( "strings" ) -// UploadsConfig describes file location and controls access to them. -type UploadsConfig struct { +// Uploads describes file location and controls access to them. +type Uploads struct { // Dir contains name of directory to control access to. Dir string @@ -17,14 +17,14 @@ type UploadsConfig struct { } // InitDefaults sets missing values to their default values. -func (cfg *UploadsConfig) InitDefaults() error { +func (cfg *Uploads) InitDefaults() error { cfg.Forbid = []string{".php", ".exe", ".bat"} cfg.Dir = os.TempDir() return nil } // TmpDir returns temporary directory. -func (cfg *UploadsConfig) TmpDir() string { +func (cfg *Uploads) TmpDir() string { if cfg.Dir != "" { return cfg.Dir } @@ -33,7 +33,7 @@ func (cfg *UploadsConfig) TmpDir() string { } // Forbids must return true if file extension is not allowed for the upload. -func (cfg *UploadsConfig) Forbids(filename string) bool { +func (cfg *Uploads) Forbids(filename string) bool { ext := strings.ToLower(path.Ext(filename)) for _, v := range cfg.Forbid { diff --git a/plugins/http/handler.go b/plugins/http/handler.go index 3e21ab2b..ecdcb2c0 100644 --- a/plugins/http/handler.go +++ b/plugins/http/handler.go @@ -12,17 +12,10 @@ import ( "github.com/spiral/errors" "github.com/spiral/roadrunner/v2/interfaces/events" "github.com/spiral/roadrunner/v2/interfaces/pool" + "github.com/spiral/roadrunner/v2/plugins/http/config" "github.com/spiral/roadrunner/v2/plugins/logger" ) -const ( - // EventResponse thrown after the request been processed. See ErrorEvent as payload. - EventResponse = iota + 500 - - // EventError thrown on any non job error provided by road runner server. - EventError -) - // MB is 1024 bytes const MB uint64 = 1024 * 1024 @@ -66,8 +59,8 @@ func (e *ResponseEvent) Elapsed() time.Duration { // parsed files and query, payload will include parsed form dataTree (if any). type Handler struct { maxRequestSize uint64 - uploads UploadsConfig - trusted Cidrs + uploads config.Uploads + trusted config.Cidrs log logger.Logger pool pool.Pool mul sync.Mutex @@ -75,7 +68,7 @@ type Handler struct { } // NewHandler return handle interface implementation -func NewHandler(maxReqSize uint64, uploads UploadsConfig, trusted Cidrs, pool pool.Pool) (*Handler, error) { +func NewHandler(maxReqSize uint64, uploads config.Uploads, trusted config.Cidrs, pool pool.Pool) (*Handler, error) { if pool == nil { return nil, errors.E(errors.Str("pool should be initialized")) } diff --git a/plugins/http/parse.go b/plugins/http/parse.go index d4a1604b..780e1279 100644 --- a/plugins/http/parse.go +++ b/plugins/http/parse.go @@ -2,6 +2,8 @@ package http import ( "net/http" + + "github.com/spiral/roadrunner/v2/plugins/http/config" ) // MaxLevel defines maximum tree depth for incoming request data and files. @@ -60,7 +62,7 @@ func (d dataTree) mount(i []string, v []string) { } // parse incoming dataTree request into JSON (including contentMultipart form dataTree) -func parseUploads(r *http.Request, cfg UploadsConfig) *Uploads { +func parseUploads(r *http.Request, cfg config.Uploads) *Uploads { u := &Uploads{ cfg: cfg, tree: make(fileTree), diff --git a/plugins/http/plugin.go b/plugins/http/plugin.go index d9c1729e..35acd2b7 100644 --- a/plugins/http/plugin.go +++ b/plugins/http/plugin.go @@ -21,6 +21,7 @@ import ( "github.com/spiral/roadrunner/v2/plugins/checker" "github.com/spiral/roadrunner/v2/plugins/config" "github.com/spiral/roadrunner/v2/plugins/http/attributes" + httpConfig "github.com/spiral/roadrunner/v2/plugins/http/config" "github.com/spiral/roadrunner/v2/plugins/logger" "github.com/spiral/roadrunner/v2/plugins/server" "github.com/spiral/roadrunner/v2/utils" @@ -52,7 +53,7 @@ type Plugin struct { server server.Server log logger.Logger - cfg *Config `mapstructure:"http"` + cfg *httpConfig.HTTP `mapstructure:"http"` // middlewares to chain mdwr middleware @@ -72,16 +73,15 @@ type Plugin struct { // misconfiguration. Services must not be used without proper configuration pushed first. func (s *Plugin) Init(cfg config.Configurer, log logger.Logger, server server.Server) error { const op = errors.Op("http_plugin_init") + if !cfg.Has(PluginName) { + return errors.E(op, errors.Disabled) + } + err := cfg.UnmarshalKey(PluginName, &s.cfg) if err != nil { return errors.E(op, err) } - // if no HTTP section in config - disable HTTP - if s.cfg == nil { - return errors.E(op, errors.Disabled) - } - err = s.cfg.InitDefaults() if err != nil { return errors.E(op, err) @@ -142,7 +142,7 @@ func (s *Plugin) Serve() chan error { s.handler, err = NewHandler( s.cfg.MaxRequestSize, *s.cfg.Uploads, - s.cfg.cidrs, + s.cfg.Cidrs, s.pool, ) if err != nil { @@ -162,7 +162,7 @@ func (s *Plugin) Serve() chan error { if s.cfg.EnableTLS() { s.https = s.initSSL() - if s.cfg.SSL.RootCA != "" { + if s.cfg.SSLConfig.RootCA != "" { err = s.appendRootCa() if err != nil { errCh <- errors.E(op, err) @@ -170,7 +170,8 @@ func (s *Plugin) Serve() chan error { } } - if s.cfg.EnableHTTP2() { + // if HTTP2Config not nil + if s.cfg.HTTP2Config != nil { if err := s.initHTTP2(); err != nil { errCh <- errors.E(op, err) return errCh @@ -200,8 +201,8 @@ func (s *Plugin) Serve() chan error { if s.https != nil { go func() { httpErr := s.https.ListenAndServeTLS( - s.cfg.SSL.Cert, - s.cfg.SSL.Key, + s.cfg.SSLConfig.Cert, + s.cfg.SSLConfig.Key, ) if httpErr != nil && httpErr != http.ErrServerClosed { @@ -322,7 +323,7 @@ func (s *Plugin) Reset() error { s.handler, err = NewHandler( s.cfg.MaxRequestSize, *s.cfg.Uploads, - s.cfg.cidrs, + s.cfg.Cidrs, s.pool, ) if err != nil { @@ -362,7 +363,7 @@ func (s *Plugin) Status() checker.Status { } func (s *Plugin) redirect(w http.ResponseWriter, r *http.Request) bool { - if s.https != nil && r.TLS == nil && s.cfg.SSL.Redirect { + if s.https != nil && r.TLS == nil && s.cfg.SSLConfig.Redirect { target := &url.URL{ Scheme: "https", Host: s.tlsAddr(r.Host, false), @@ -396,7 +397,7 @@ func (s *Plugin) appendRootCa() error { rootCAs = x509.NewCertPool() } - CA, err := ioutil.ReadFile(s.cfg.SSL.RootCA) + CA, err := ioutil.ReadFile(s.cfg.SSLConfig.RootCA) if err != nil { return err } @@ -489,13 +490,13 @@ func (s *Plugin) initSSL() *http.Server { // init http/2 server func (s *Plugin) initHTTP2() error { return http2.ConfigureServer(s.https, &http2.Server{ - MaxConcurrentStreams: s.cfg.HTTP2.MaxConcurrentStreams, + MaxConcurrentStreams: s.cfg.HTTP2Config.MaxConcurrentStreams, }) } // serveFCGI starts FastCGI server. func (s *Plugin) serveFCGI() error { - l, err := utils.CreateListener(s.cfg.FCGI.Address) + l, err := utils.CreateListener(s.cfg.FCGIConfig.Address) if err != nil { return err } @@ -508,13 +509,13 @@ func (s *Plugin) serveFCGI() error { return nil } -// tlsAddr replaces listen or host port with port configured by SSL config. +// tlsAddr replaces listen or host port with port configured by SSLConfig config. func (s *Plugin) tlsAddr(host string, forcePort bool) string { // remove current forcePort first host = strings.Split(host, ":")[0] - if forcePort || s.cfg.SSL.Port != 443 { - host = fmt.Sprintf("%s:%v", host, s.cfg.SSL.Port) + if forcePort || s.cfg.SSLConfig.Port != 443 { + host = fmt.Sprintf("%s:%v", host, s.cfg.SSLConfig.Port) } return host diff --git a/plugins/http/request.go b/plugins/http/request.go index 3983fdde..a1398819 100644 --- a/plugins/http/request.go +++ b/plugins/http/request.go @@ -11,6 +11,7 @@ import ( j "github.com/json-iterator/go" "github.com/spiral/roadrunner/v2/pkg/payload" "github.com/spiral/roadrunner/v2/plugins/http/attributes" + "github.com/spiral/roadrunner/v2/plugins/http/config" "github.com/spiral/roadrunner/v2/plugins/logger" ) @@ -70,7 +71,7 @@ func fetchIP(pair string) string { } // NewRequest creates new PSR7 compatible request using net/http request. -func NewRequest(r *http.Request, cfg UploadsConfig) (*Request, error) { +func NewRequest(r *http.Request, cfg config.Uploads) (*Request, error) { req := &Request{ RemoteAddr: fetchIP(r.RemoteAddr), Protocol: r.Proto, diff --git a/plugins/http/uploads.go b/plugins/http/uploads.go index d5196844..f9f8e1c8 100644 --- a/plugins/http/uploads.go +++ b/plugins/http/uploads.go @@ -1,6 +1,7 @@ package http import ( + "github.com/spiral/roadrunner/v2/plugins/http/config" "github.com/spiral/roadrunner/v2/plugins/logger" "io" @@ -30,7 +31,7 @@ const ( // Uploads tree manages uploaded files tree and temporary files. type Uploads struct { // associated temp directory and forbidden extensions. - cfg UploadsConfig + cfg config.Uploads // pre processed data tree for Uploads. tree fileTree @@ -112,7 +113,7 @@ func NewUpload(f *multipart.FileHeader) *FileUpload { // STACK // DEFER FILE CLOSE (2) // DEFER TMP CLOSE (1) -func (f *FileUpload) Open(cfg UploadsConfig) (err error) { +func (f *FileUpload) Open(cfg config.Uploads) (err error) { if cfg.Forbids(f.Name) { f.Error = UploadErrorExtension return nil |