summaryrefslogtreecommitdiff
path: root/plugins/http/serve.go
diff options
context:
space:
mode:
authorValery Piashchynski <[email protected]>2021-04-28 16:43:59 +0300
committerValery Piashchynski <[email protected]>2021-04-28 16:43:59 +0300
commitb789df7dcc9268f98f2bacfb40f753b10d521e4f (patch)
tree126b0fd8271f27e77f9107906bb0e6713a49d6ab /plugins/http/serve.go
parent30c25f17fa7d6386e33a4894c812f7ca5db990ad (diff)
- Update CHANGELOG
- Add tests for the etags functionality Signed-off-by: Valery Piashchynski <[email protected]>
Diffstat (limited to 'plugins/http/serve.go')
-rw-r--r--plugins/http/serve.go242
1 files changed, 242 insertions, 0 deletions
diff --git a/plugins/http/serve.go b/plugins/http/serve.go
new file mode 100644
index 00000000..338d4339
--- /dev/null
+++ b/plugins/http/serve.go
@@ -0,0 +1,242 @@
+package http
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "net/http"
+ "net/http/fcgi"
+ "net/url"
+ "os"
+ "strings"
+
+ "github.com/spiral/errors"
+ "github.com/spiral/roadrunner/v2/plugins/logger"
+ "github.com/spiral/roadrunner/v2/utils"
+ "golang.org/x/net/http2"
+ "golang.org/x/sys/cpu"
+)
+
+func (s *Plugin) serveHTTP(errCh chan error) {
+ if s.http == nil {
+ return
+ }
+ const op = errors.Op("http_plugin_serve_http")
+
+ if len(s.mdwr) > 0 {
+ applyMiddlewares(s.http, s.mdwr, s.cfg.Middleware, s.log)
+ }
+ l, err := utils.CreateListener(s.cfg.Address)
+ if err != nil {
+ errCh <- errors.E(op, err)
+ return
+ }
+
+ err = s.http.Serve(l)
+ if err != nil && err != http.ErrServerClosed {
+ errCh <- errors.E(op, err)
+ return
+ }
+}
+
+func (s *Plugin) serveHTTPS(errCh chan error) {
+ if s.https == nil {
+ return
+ }
+ const op = errors.Op("http_plugin_serve_https")
+ if len(s.mdwr) > 0 {
+ applyMiddlewares(s.https, s.mdwr, s.cfg.Middleware, s.log)
+ }
+ l, err := utils.CreateListener(s.cfg.SSLConfig.Address)
+ if err != nil {
+ errCh <- errors.E(op, err)
+ return
+ }
+
+ err = s.https.ServeTLS(
+ l,
+ s.cfg.SSLConfig.Cert,
+ s.cfg.SSLConfig.Key,
+ )
+
+ if err != nil && err != http.ErrServerClosed {
+ errCh <- errors.E(op, err)
+ return
+ }
+}
+
+// serveFCGI starts FastCGI server.
+func (s *Plugin) serveFCGI(errCh chan error) {
+ if s.fcgi == nil {
+ return
+ }
+ const op = errors.Op("http_plugin_serve_fcgi")
+
+ if len(s.mdwr) > 0 {
+ applyMiddlewares(s.https, s.mdwr, s.cfg.Middleware, s.log)
+ }
+
+ l, err := utils.CreateListener(s.cfg.FCGIConfig.Address)
+ if err != nil {
+ errCh <- errors.E(op, err)
+ return
+ }
+
+ err = fcgi.Serve(l, s.fcgi.Handler)
+ if err != nil && err != http.ErrServerClosed {
+ errCh <- errors.E(op, err)
+ return
+ }
+}
+
+func (s *Plugin) redirect(w http.ResponseWriter, r *http.Request) {
+ target := &url.URL{
+ Scheme: HTTPSScheme,
+ // host or host:port
+ Host: s.tlsAddr(r.Host, false),
+ Path: r.URL.Path,
+ RawQuery: r.URL.RawQuery,
+ }
+
+ http.Redirect(w, r, target.String(), http.StatusPermanentRedirect)
+}
+
+// https://golang.org/pkg/net/http/#Hijacker
+//go:inline
+func headerContainsUpgrade(r *http.Request) bool {
+ if _, ok := r.Header["Upgrade"]; ok {
+ return true
+ }
+ return false
+}
+
+// append RootCA to the https server TLS config
+func (s *Plugin) appendRootCa() error {
+ const op = errors.Op("http_plugin_append_root_ca")
+ rootCAs, err := x509.SystemCertPool()
+ if err != nil {
+ return nil
+ }
+ if rootCAs == nil {
+ rootCAs = x509.NewCertPool()
+ }
+
+ CA, err := os.ReadFile(s.cfg.SSLConfig.RootCA)
+ if err != nil {
+ return err
+ }
+
+ // should append our CA cert
+ ok := rootCAs.AppendCertsFromPEM(CA)
+ if !ok {
+ return errors.E(op, errors.Str("could not append Certs from PEM"))
+ }
+ // disable "G402 (CWE-295): TLS MinVersion too low. (Confidence: HIGH, Severity: HIGH)"
+ // #nosec G402
+ cfg := &tls.Config{
+ InsecureSkipVerify: false,
+ RootCAs: rootCAs,
+ }
+ s.http.TLSConfig = cfg
+
+ return nil
+}
+
+// Init https server
+func (s *Plugin) initSSL() *http.Server {
+ var topCipherSuites []uint16
+ var defaultCipherSuitesTLS13 []uint16
+
+ hasGCMAsmAMD64 := cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
+ hasGCMAsmARM64 := cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
+ // Keep in sync with crypto/aes/cipher_s390x.go.
+ hasGCMAsmS390X := cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
+
+ hasGCMAsm := hasGCMAsmAMD64 || hasGCMAsmARM64 || hasGCMAsmS390X
+
+ if hasGCMAsm {
+ // If AES-GCM hardware is provided then priorities AES-GCM
+ // cipher suites.
+ topCipherSuites = []uint16{
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ }
+ defaultCipherSuitesTLS13 = []uint16{
+ tls.TLS_AES_128_GCM_SHA256,
+ tls.TLS_CHACHA20_POLY1305_SHA256,
+ tls.TLS_AES_256_GCM_SHA384,
+ }
+ } else {
+ // Without AES-GCM hardware, we put the ChaCha20-Poly1305
+ // cipher suites first.
+ topCipherSuites = []uint16{
+ tls.TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ tls.TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ }
+ defaultCipherSuitesTLS13 = []uint16{
+ tls.TLS_CHACHA20_POLY1305_SHA256,
+ tls.TLS_AES_128_GCM_SHA256,
+ tls.TLS_AES_256_GCM_SHA384,
+ }
+ }
+
+ DefaultCipherSuites := make([]uint16, 0, 22)
+ DefaultCipherSuites = append(DefaultCipherSuites, topCipherSuites...)
+ DefaultCipherSuites = append(DefaultCipherSuites, defaultCipherSuitesTLS13...)
+
+ sslServer := &http.Server{
+ Addr: s.tlsAddr(s.cfg.Address, true),
+ Handler: s,
+ ErrorLog: s.stdLog,
+ TLSConfig: &tls.Config{
+ CurvePreferences: []tls.CurveID{
+ tls.CurveP256,
+ tls.CurveP384,
+ tls.CurveP521,
+ tls.X25519,
+ },
+ CipherSuites: DefaultCipherSuites,
+ MinVersion: tls.VersionTLS12,
+ PreferServerCipherSuites: true,
+ },
+ }
+
+ return sslServer
+}
+
+// init http/2 server
+func (s *Plugin) initHTTP2() error {
+ return http2.ConfigureServer(s.https, &http2.Server{
+ MaxConcurrentStreams: s.cfg.HTTP2Config.MaxConcurrentStreams,
+ })
+}
+
+// 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.SSLConfig.Port != 443 {
+ host = fmt.Sprintf("%s:%v", host, s.cfg.SSLConfig.Port)
+ }
+
+ return host
+}
+
+func applyMiddlewares(server *http.Server, middlewares map[string]Middleware, order []string, log logger.Logger) {
+ for i := len(order) - 1; i >= 0; i-- {
+ if mdwr, ok := middlewares[order[i]]; ok {
+ server.Handler = mdwr.Middleware(server.Handler)
+ } else {
+ log.Warn("requested middleware does not exist", "requested", order[i])
+ }
+ }
+}