aboutsummaryrefslogtreecommitdiff
path: root/src/net/http/server.go
diff options
context:
space:
mode:
authorDamien Neil <dneil@google.com>2024-05-29 09:24:20 -0700
committerDamien Neil <dneil@google.com>2024-11-05 22:14:59 +0000
commitbfc8f28068c4aff44aded67aef12e56ecc843717 (patch)
treed689a3e8af0036e9276aa45c5193df8f1349d6f3 /src/net/http/server.go
parent635c2dce04259f2c84aeac543f0305b3e7c8ed7b (diff)
downloadgo-bfc8f28068c4aff44aded67aef12e56ecc843717.tar.xz
net/http: add Protocols field to Server and Transport
Support configuring which HTTP version(s) a server or client use via an explicit set of protocols. The Protocols field takes precedence over TLSNextProto and ForceAttemptHTTP2. Fixes #67814 Change-Id: I09ece88f78ad4d98ca1f213157b5f62ae11e063f Reviewed-on: https://go-review.googlesource.com/c/go/+/607496 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Jonathan Amsterdam <jba@google.com> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
Diffstat (limited to 'src/net/http/server.go')
-rw-r--r--src/net/http/server.go79
1 files changed, 71 insertions, 8 deletions
diff --git a/src/net/http/server.go b/src/net/http/server.go
index db44e7c5c2..2c9774a7a5 100644
--- a/src/net/http/server.go
+++ b/src/net/http/server.go
@@ -2979,6 +2979,13 @@ type Server struct {
// See https://go.dev/issue/67813.
HTTP2 *HTTP2Config
+ // Protocols is the set of protocols accepted by the server.
+ //
+ // If Protocols is nil, the default is usually HTTP/1 and HTTP/2.
+ // If TLSNextProto is non-nil and does not contain an "h2" entry,
+ // the default is HTTP/1 only.
+ Protocols *Protocols
+
inShutdown atomic.Bool // true when server is in shutdown
disableKeepAlives atomic.Bool
@@ -3389,9 +3396,7 @@ func (s *Server) ServeTLS(l net.Listener, certFile, keyFile string) error {
}
config := cloneTLSConfig(s.TLSConfig)
- if !slices.Contains(config.NextProtos, "http/1.1") {
- config.NextProtos = append(config.NextProtos, "http/1.1")
- }
+ config.NextProtos = adjustNextProtos(config.NextProtos, s.protocols())
configHasCert := len(config.Certificates) > 0 || config.GetCertificate != nil || config.GetConfigForClient != nil
if !configHasCert || certFile != "" || keyFile != "" {
@@ -3407,6 +3412,59 @@ func (s *Server) ServeTLS(l net.Listener, certFile, keyFile string) error {
return s.Serve(tlsListener)
}
+func (s *Server) protocols() Protocols {
+ if s.Protocols != nil {
+ return *s.Protocols // user-configured set
+ }
+
+ // The historic way of disabling HTTP/2 is to set TLSNextProto to
+ // a non-nil map with no "h2" entry.
+ _, hasH2 := s.TLSNextProto["h2"]
+ http2Disabled := s.TLSNextProto != nil && !hasH2
+
+ // If GODEBUG=http2server=0, then HTTP/2 is disabled unless
+ // the user has manually added an "h2" entry to TLSNextProto
+ // (probably by using x/net/http2 directly).
+ if http2server.Value() == "0" && !hasH2 {
+ http2Disabled = true
+ }
+
+ var p Protocols
+ p.SetHTTP1(true) // default always includes HTTP/1
+ if !http2Disabled {
+ p.SetHTTP2(true)
+ }
+ return p
+}
+
+// adjustNextProtos adds or removes "http/1.1" and "h2" entries from
+// a tls.Config.NextProtos list, according to the set of protocols in protos.
+func adjustNextProtos(nextProtos []string, protos Protocols) []string {
+ var have Protocols
+ nextProtos = slices.DeleteFunc(nextProtos, func(s string) bool {
+ switch s {
+ case "http/1.1":
+ if !protos.HTTP1() {
+ return true
+ }
+ have.SetHTTP1(true)
+ case "h2":
+ if !protos.HTTP2() {
+ return true
+ }
+ have.SetHTTP2(true)
+ }
+ return false
+ })
+ if protos.HTTP2() && !have.HTTP2() {
+ nextProtos = append(nextProtos, "h2")
+ }
+ if protos.HTTP1() && !have.HTTP1() {
+ nextProtos = append(nextProtos, "http/1.1")
+ }
+ return nextProtos
+}
+
// trackListener adds or removes a net.Listener to the set of tracked
// listeners.
//
@@ -3600,16 +3658,21 @@ func (s *Server) onceSetNextProtoDefaults() {
if omitBundledHTTP2 {
return
}
+ if !s.protocols().HTTP2() {
+ return
+ }
if http2server.Value() == "0" {
http2server.IncNonDefault()
return
}
- // Enable HTTP/2 by default if the user hasn't otherwise
- // configured their TLSNextProto map.
- if s.TLSNextProto == nil {
- conf := &http2Server{}
- s.nextProtoErr = http2ConfigureServer(s, conf)
+ if _, ok := s.TLSNextProto["h2"]; ok {
+ // TLSNextProto already contains an HTTP/2 implementation.
+ // The user probably called golang.org/x/net/http2.ConfigureServer
+ // to add it.
+ return
}
+ conf := &http2Server{}
+ s.nextProtoErr = http2ConfigureServer(s, conf)
}
// TimeoutHandler returns a [Handler] that runs h with the given time limit.