diff options
author | Valery Piashchynski <[email protected]> | 2020-11-15 12:55:12 +0300 |
---|---|---|
committer | Valery Piashchynski <[email protected]> | 2020-11-15 12:55:12 +0300 |
commit | 5260639a7e95d4d4a36b46fd4b19f665a0a60ef9 (patch) | |
tree | 31b2a616b385eb2e207b1f6e0b1269d37f95af75 /plugins/http/config.go | |
parent | a7ba4df83b4f2c67a3a0fb9d1dd35663935c90be (diff) |
Initial commit of http 2.0 plugin
Diffstat (limited to 'plugins/http/config.go')
-rw-r--r-- | plugins/http/config.go | 263 |
1 files changed, 263 insertions, 0 deletions
diff --git a/plugins/http/config.go b/plugins/http/config.go new file mode 100644 index 00000000..00f61652 --- /dev/null +++ b/plugins/http/config.go @@ -0,0 +1,263 @@ +package http + +import ( + "errors" + "fmt" + "github.com/spiral/roadrunner" + "github.com/spiral/roadrunner/service" + "net" + "os" + "strings" +) + +// Config configures RoadRunner HTTP server. +type Config struct { + // Port and port to handle as http server. + Address string + + // SSL defines https server options. + SSL SSLConfig + + // FCGI configuration. You can use FastCGI without HTTP server. + FCGI *FCGIConfig + + // HTTP2 configuration + HTTP2 *HTTP2Config + + // MaxRequestSize specified max size for payload body in megabytes, set 0 to unlimited. + MaxRequestSize int64 + + // TrustedSubnets declare IP subnets which are allowed to set ip using X-Real-Ip and X-Forwarded-For + TrustedSubnets []string + cidrs []*net.IPNet + + // Uploads configures uploads configuration. + Uploads *UploadsConfig + + // Workers configures rr server and worker pool. + Workers *roadrunner.ServerConfig +} + +// 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 +} + +// 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 +} + +// EnableHTTP is true when http server must run. +func (c *Config) EnableHTTP() bool { + return c.Address != "" +} + +// EnableTLS returns true if rr 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 +} + +// EnableH2C when HTTP/2 extension must be enabled on TCP. +func (c *Config) EnableH2C() bool { + return c.HTTP2.H2C +} + +// EnableFCGI is true when FastCGI server must be enabled. +func (c *Config) EnableFCGI() bool { + return c.FCGI.Address != "" +} + +// Hydrate must populate Config values using given Config source. Must return error if Config is not valid. +func (c *Config) Hydrate(cfg service.Config) error { + if c.Workers == nil { + c.Workers = &roadrunner.ServerConfig{} + } + + if c.HTTP2 == nil { + c.HTTP2 = &HTTP2Config{} + } + + if c.FCGI == nil { + c.FCGI = &FCGIConfig{} + } + + if c.Uploads == nil { + c.Uploads = &UploadsConfig{} + } + + if c.SSL.Port == 0 { + c.SSL.Port = 443 + } + + err := c.HTTP2.InitDefaults() + if err != nil { + return err + } + err = c.Uploads.InitDefaults() + if err != nil { + return err + } + err = c.Workers.InitDefaults() + if err != nil { + return err + } + + if err := cfg.Unmarshal(c); err != nil { + return err + } + + c.Workers.UpscaleDurations() + + if c.TrustedSubnets == nil { + // @see https://en.wikipedia.org/wiki/Reserved_IP_addresses + c.TrustedSubnets = []string{ + "10.0.0.0/8", + "127.0.0.0/8", + "172.16.0.0/12", + "192.168.0.0/16", + "::1/128", + "fc00::/7", + "fe80::/10", + } + } + + if err := c.parseCIDRs(); err != nil { + return err + } + + return c.Valid() +} + +func (c *Config) parseCIDRs() error { + for _, cidr := range c.TrustedSubnets { + _, cr, err := net.ParseCIDR(cidr) + if err != nil { + return err + } + + c.cidrs = append(c.cidrs, cr) + } + + return nil +} + +// 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 { + return false + } + + i := net.ParseIP(ip) + if i == nil { + return false + } + + for _, cird := range c.cidrs { + if cird.Contains(i) { + return true + } + } + + return false +} + +// Valid validates the configuration. +func (c *Config) Valid() error { + if c.Uploads == nil { + return errors.New("malformed uploads config") + } + + if c.HTTP2 == nil { + return errors.New("malformed http2 config") + } + + if c.Workers == nil { + return errors.New("malformed workers config") + } + + if c.Workers.Pool == nil { + return errors.New("malformed workers config (pool config is missing)") + } + + if err := c.Workers.Pool.Valid(); err != nil { + return err + } + + if !c.EnableHTTP() && !c.EnableTLS() && !c.EnableFCGI() { + return errors.New("unable to run http service, no method has been specified (http, https, http/2 or FastCGI)") + } + + if c.Address != "" && !strings.Contains(c.Address, ":") { + return errors.New("malformed http server address") + } + + if c.EnableTLS() { + if _, err := os.Stat(c.SSL.Key); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("key file '%s' does not exists", c.SSL.Key) + } + + return err + } + + if _, err := os.Stat(c.SSL.Cert); err != nil { + if os.IsNotExist(err) { + return fmt.Errorf("cert file '%s' does not exists", c.SSL.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 os.IsNotExist(err) { + return fmt.Errorf("root ca path provided, but path '%s' does not exists", c.SSL.RootCA) + } + return err + } + } + } + + return nil +} |