How to disable HTTP/2 using Server.TLSNextProto
Asked Answered
R

2

7

I have a Go server handling https requests:

package main
import (
        "fmt"
        "net/http"
        "log"
)
const (
        port       = "5966"
        cert       = "/tmp/cert.pem"
        key        = "/tmp/key.pem"
)
func main() {

        listen_at := ":" + port
        fmt.Println("Listening at", listen_at)
        go http.HandleFunc("/job_handler/", job_handler)
        log.Fatal(http.ListenAndServeTLS(listen_at, cert, key, nil))
}
func job_handler(w http.ResponseWriter, r *http.Request) {
       // do somework
}

Turns out in https mode, Go has transparent support for the HTTP/2 protocol. We've some clients that noticeably misbehave in HTTP/2, and hence we need to disable HTTP/2 on the server side.

Unfortunately, I can't use ENV variable GODEBUG=http2server=0 to disable HTTP/2. What's left is Server.TLSNextProto as documented here.

How can I use Server.TLSNextProto on my server code above to disable https/2?

Resplendence answered 24/9, 2019 at 22:37 Comment(1)
It says it right there in the docs you linked: "Programs that must disable HTTP/2 can do so by setting Server.TLSNextProto to a non-nil, empty map." What's unclear about that?Rufe
C
11

The simplest setup that disables HTTP/2 is

package main

import (
    "log"
    "net/http"
    "crypto/tls"
)

func main() {

    m := http.NewServeMux()

    srv := &http.Server{
        Handler:      m,
        Addr:         "127.0.0.1:8080",
        TLSNextProto: make(map[string]func(*http.Server, *tls.Conn, http.Handler)),
    }

    log.Fatal(srv.ListenAndServe())

}

You can verify the support with

curl -v --http2-prior-knowledge http://localhost:8080
Clothespin answered 25/9, 2019 at 9:42 Comment(4)
Thank you, and +1 for the curl verification tip!Resplendence
Grzegorz can you tell me how that command verifies that HTTP2 is disabled? I am trying to disable HTTP2 in this manner, and the equivalent curl command is telling me "Connection state changed (HTTP/2 confirmed)" and then "Failed sending HTTP2 data, * nghttp2_session_send() failed: The user callback function failed(-902)" Is this what I should see? It sounds to me like this method has not in fact disabled HTTP2. Thanks.Senter
@MartinDelVecchio The command parameters tells curl to use HTTP/2 protocol only. If the tool fails to communicate with server it means that HTTP/2 is not available. It is what we wanted to achieve.Barong
OK. I am seeing the same errors when I don't tell curl to use HTTP2. When I explicitly tell it to use HTTP 1.1, I get success. But when I don't tell it, it tries HTTP2, fails, and returns an error.Senter
M
1

Just an update since the OP said:

Unfortunately, I can't use ENV variable GODEBUG=http2server=0

In Go 1.21 and later you can just add //go:debug http2server=0 at the top of any source file of the main package. See The Go Blog

Meddle answered 24/5 at 7:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.