You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficcontrol.apache.org by da...@apache.org on 2018/12/20 22:46:31 UTC

[trafficcontrol] branch master updated: Added a configuration setting, 'DisableHTTP2'. The setting (#3149)

This is an automated email from the ASF dual-hosted git repository.

dangogh pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/trafficcontrol.git


The following commit(s) were added to refs/heads/master by this push:
     new 495d1ed  Added a configuration setting, 'DisableHTTP2'.  The setting (#3149)
495d1ed is described below

commit 495d1ed83d0e1a5b350dd5d5a1d3046caa13311c
Author: John J. Rushford <jr...@apache.org>
AuthorDate: Thu Dec 20 15:46:27 2018 -0700

    Added a configuration setting, 'DisableHTTP2'.  The setting (#3149)
    
    is false by default but when set to 'true', the grove server
    will not negotiate and serve HTTP2.
---
 grove/README.md        |  1 +
 grove/config/config.go |  6 ++++--
 grove/grove.go         | 31 ++++++++++++++++++-------------
 grove/web/listener.go  |  7 +++++--
 4 files changed, 28 insertions(+), 17 deletions(-)

diff --git a/grove/README.md b/grove/README.md
index 21ad09f..7fce45e 100644
--- a/grove/README.md
+++ b/grove/README.md
@@ -76,6 +76,7 @@ The config file has the following fields:
 | `rfc_compliant` | Whether to strictly adhere to RFC 7234. If false, client requests which can harm a parent, such as `no-cache` are ignored. |
 | `port` | The HTTP port to serve on. |
 | `https_port` | The HTTPS port to serve on. |
+| `disable_http2` | When set to true, HTTP2 support is disabled, the default is 'false' with HTTP2 enabled. changing this setting requires a restart of grove. |
 | `cache_size_bytes` | The maximum size of the memory cache, in bytes. This is a soft maximum, and the cache may temporarily exceed this size until older values can be purged. The cache uses a Least Recently Used algorithm, purging the oldest requested object when a request for an uncached object is received with a full cache. Also note the cache size calculation does not currently count headers. |
 | `remap_rules_file` | The file with remap rules. See [Remap Rules](#remap-rules). |
 | `concurrent_rule_requests` | The maximum number of simultaneous requests which will be issued to a parent for any rule. |
diff --git a/grove/config/config.go b/grove/config/config.go
index 70e0903..a621830 100644
--- a/grove/config/config.go
+++ b/grove/config/config.go
@@ -28,8 +28,9 @@ type Config struct {
 	// RFCCompliant determines whether `Cache-Control: no-cache` requests are honored. The ability to ignore `no-cache` is necessary to protect origin servers from DDOS attacks. In general, CDNs and caching proxies with the goal of origin protection should set RFCComplaint false. Cache with other goals (performance, load balancing, etc) should set RFCCompliant true.
 	RFCCompliant bool `json:"rfc_compliant"`
 	// Port is the HTTP port to serve on
-	Port      int `json:"port"`
-	HTTPSPort int `json:"https_port"`
+	Port         int  `json:"port"`
+	HTTPSPort    int  `json:"https_port"`
+	DisableHTTP2 bool `json:"disable_http2"`
 	// CacheSizeBytes is the size of the memory cache, in bytes.
 	CacheSizeBytes int    `json:"cache_size_bytes"`
 	RemapRulesFile string `json:"remap_rules_file"`
@@ -89,6 +90,7 @@ const MSPerSec = 1000
 var DefaultConfig = Config{
 	RFCCompliant:           true,
 	Port:                   80,
+	DisableHTTP2:           false,
 	HTTPSPort:              443,
 	CacheSizeBytes:         bytesPerGibibyte,
 	RemapRulesFile:         "remap.config",
diff --git a/grove/grove.go b/grove/grove.go
index 99ed55b..3b1fda9 100644
--- a/grove/grove.go
+++ b/grove/grove.go
@@ -124,7 +124,7 @@ func main() {
 	httpsConnStateCallback := (func(net.Conn, http.ConnState))(nil)
 	tlsConfig := (*tls.Config)(nil)
 	if cfg.CertFile != "" && cfg.KeyFile != "" {
-		if httpsListener, httpsConns, httpsConnStateCallback, tlsConfig, err = web.InterceptListenTLS("tcp", fmt.Sprintf(":%d", cfg.HTTPSPort), certs); err != nil {
+		if httpsListener, httpsConns, httpsConnStateCallback, tlsConfig, err = web.InterceptListenTLS("tcp", fmt.Sprintf(":%d", cfg.HTTPSPort), certs, cfg.DisableHTTP2); err != nil {
 			log.Errorf("creating HTTPS listener %v: %v\n", cfg.HTTPSPort, err)
 			return
 		}
@@ -163,10 +163,10 @@ func main() {
 	plugins.OnStartup(remapper.PluginCfg(), pluginContext, plugin.StartupData{Config: cfg, Shared: remapper.PluginSharedCfg()})
 
 	// TODO add config to not serve HTTP (only HTTPS). If port is not set?
-	httpServer := startServer(httpHandler, httpListener, httpConnStateCallback, nil, cfg.Port, idleTimeout, readTimeout, writeTimeout, "http")
+	httpServer := startServer(httpHandler, httpListener, httpConnStateCallback, nil, cfg.Port, idleTimeout, readTimeout, writeTimeout, cfg.DisableHTTP2, "http")
 
 	if cfg.CertFile != "" && cfg.KeyFile != "" {
-		httpsServer = startServer(httpsHandler, httpsListener, httpsConnStateCallback, tlsConfig, cfg.HTTPSPort, idleTimeout, readTimeout, writeTimeout, "https")
+		httpsServer = startServer(httpsHandler, httpsListener, httpsConnStateCallback, tlsConfig, cfg.HTTPSPort, idleTimeout, readTimeout, writeTimeout, cfg.DisableHTTP2, "https")
 	}
 
 	reloadConfig := func() {
@@ -214,7 +214,7 @@ func main() {
 		}
 
 		if cfg.HTTPSPort != oldCfg.HTTPSPort {
-			if httpsListener, httpsConns, httpsConnStateCallback, tlsConfig, err = web.InterceptListenTLS("tcp", fmt.Sprintf(":%d", cfg.HTTPSPort), certs); err != nil {
+			if httpsListener, httpsConns, httpsConnStateCallback, tlsConfig, err = web.InterceptListenTLS("tcp", fmt.Sprintf(":%d", cfg.HTTPSPort), certs, cfg.DisableHTTP2); err != nil {
 				log.Errorf("creating HTTPS listener %v: %v\n", cfg.HTTPSPort, err)
 			}
 		}
@@ -269,7 +269,7 @@ func main() {
 				}
 
 			}
-			httpServer = startServer(httpHandler, httpListener, httpConnStateCallback, nil, cfg.Port, idleTimeout, readTimeout, writeTimeout, "http")
+			httpServer = startServer(httpHandler, httpListener, httpConnStateCallback, nil, cfg.Port, idleTimeout, readTimeout, writeTimeout, cfg.DisableHTTP2, "http")
 		}
 
 		if (httpsServer == nil || cfg.HTTPSPort != oldCfg.HTTPSPort) && cfg.CertFile != "" && cfg.KeyFile != "" {
@@ -286,7 +286,7 @@ func main() {
 				}
 			}
 
-			httpsServer = startServer(httpsHandler, httpsListener, httpsConnStateCallback, tlsConfig, cfg.HTTPSPort, idleTimeout, readTimeout, writeTimeout, "https")
+			httpsServer = startServer(httpsHandler, httpsListener, httpsConnStateCallback, tlsConfig, cfg.HTTPSPort, idleTimeout, readTimeout, writeTimeout, cfg.DisableHTTP2, "https")
 		}
 	}
 
@@ -324,7 +324,7 @@ func signalReloader(sig os.Signal, f func()) {
 }
 
 // startServer starts an HTTP or HTTPS server on the given port, and returns it.
-func startServer(handler http.Handler, listener net.Listener, connState func(net.Conn, http.ConnState), tlsConfig *tls.Config, port int, idleTimeout time.Duration, readTimeout time.Duration, writeTimeout time.Duration, protocol string) *http.Server {
+func startServer(handler http.Handler, listener net.Listener, connState func(net.Conn, http.ConnState), tlsConfig *tls.Config, port int, idleTimeout time.Duration, readTimeout time.Duration, writeTimeout time.Duration, h2Disabled bool, protocol string) *http.Server {
 
 	server := &http.Server{
 		Handler:      handler,
@@ -336,12 +336,17 @@ func startServer(handler http.Handler, listener net.Listener, connState func(net
 		WriteTimeout: writeTimeout,
 	}
 
-	// TODO configurable H2 timeouts and buffer sizes
-	h2Conf := &http2.Server{
-		IdleTimeout: idleTimeout,
-	}
-	if err := http2.ConfigureServer(server, h2Conf); err != nil {
-		log.Errorln(" server configuring HTTP/2: " + err.Error())
+	// HTTP2 is enabled if config.DisableHTTP2 is false
+	if !h2Disabled {
+		// TODO configurable H2 timeouts and buffer sizes
+		h2Conf := &http2.Server{
+			IdleTimeout: idleTimeout,
+		}
+		if err := http2.ConfigureServer(server, h2Conf); err != nil {
+			log.Errorln(" server configuring HTTP/2: " + err.Error())
+		}
+	} else {
+		log.Warnln("disabling HTTP2 Server per configuation setting.")
 	}
 
 	go func() {
diff --git a/grove/web/listener.go b/grove/web/listener.go
index a2d4a5b..ab6cb3a 100644
--- a/grove/web/listener.go
+++ b/grove/web/listener.go
@@ -67,9 +67,12 @@ func InterceptListen(network, laddr string) (net.Listener, *ConnMap, func(net.Co
 }
 
 // InterceptListenTLS is like InterceptListen but for serving HTTPS. It returns the tls.Config, which must be set on the http.Server using this listener for HTTP/2 to be set up.
-func InterceptListenTLS(network string, laddr string, certs []tls.Certificate) (net.Listener, *ConnMap, func(net.Conn, http.ConnState), *tls.Config, error) {
+func InterceptListenTLS(network string, laddr string, certs []tls.Certificate, h2Disabled bool) (net.Listener, *ConnMap, func(net.Conn, http.ConnState), *tls.Config, error) {
 	config := &tls.Config{}
-	config.NextProtos = []string{"h2"}
+	// HTTP2 is enabled if config.DisableHTTP2 is false
+	if !h2Disabled {
+		config.NextProtos = []string{"h2"}
+	}
 	config.Certificates = certs
 	config.BuildNameToCertificate()
 	l, err := net.Listen(network, laddr)