Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: h2 does not support other net.Conn than *tls.Conn #55076

Open
lukeo3o1 opened this issue Sep 14, 2022 · 7 comments · May be fixed by #55077
Open

net/http: h2 does not support other net.Conn than *tls.Conn #55076

lukeo3o1 opened this issue Sep 14, 2022 · 7 comments · May be fixed by #55077
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Milestone

Comments

@lukeo3o1
Copy link

lukeo3o1 commented Sep 14, 2022

What version of Go are you using (go version)?

$ go version
go1.19.1 windows/amd64

Does this issue reproduce with the latest release?

Yes

What operating system and processor architecture are you using (go env)?

go env Output
$ go env
set GO111MODULE=
set GOARCH=amd64
set GOBIN=
set GOCACHE=C:\Users\Luke\AppData\Local\go-build
set GOENV=C:\Users\Luke\AppData\Roaming\go\env
set GOEXE=.exe
set GOEXPERIMENT=
set GOFLAGS=
set GOHOSTARCH=amd64
set GOHOSTOS=windows
set GOINSECURE=
set GOMODCACHE=D:\lukeo3o1\go\pkg\mod
set GONOPROXY=
set GONOSUMDB=
set GOOS=windows
set GOPATH=D:\lukeo3o1\go
set GOPRIVATE=
set GOPROXY=https://proxy.golang.org,direct
set GOROOT=C:\Program Files\Go
set GOSUMDB=sum.golang.org
set GOTMPDIR=
set GOTOOLDIR=C:\Program Files\Go\pkg\tool\windows_amd64
set GOVCS=
set GOVERSION=go1.19.1
set GCCGO=gccgo
set GOAMD64=v1
set AR=ar
set CC=gcc
set CXX=g++
set CGO_ENABLED=1
set GOMOD=D:\lukeo3o1\go\src\test\go.mod
set GOWORK=
set CGO_CFLAGS=-g -O2
set CGO_CPPFLAGS=
set CGO_CXXFLAGS=-g -O2
set CGO_FFLAGS=-g -O2
set CGO_LDFLAGS=-g -O2
set PKG_CONFIG=pkg-config
set GOGCCFLAGS=-m64 -mthreads -Wl,--no-gc-sections -fmessage-length=0 -fdebug-prefix-map=C:\Users\Luke\AppData\Local\Temp\go-build3309280822=/tmp/go-build -gno-record-gcc-switches

What did you do?

package main

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

	"github.com/soheilhy/cmux"
)

func main() {
	cer, err := tls.LoadX509KeyPair("server.crt", "server.key")
	if err != nil {
		panic(err)
	}

	l, err := tls.Listen("tcp", ":443", &tls.Config{
		Certificates: []tls.Certificate{cer},
		MinVersion:   tls.VersionTLS13,
		NextProtos:   []string{"h2", "http/1.1"},
	})
	if err != nil {
		panic(err)
	}
	defer l.Close()

	m := cmux.New(l)
	http2l := m.Match(cmux.HTTP2())

	server := http.Server{
		Handler: http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
			fmt.Fprintln(w, "Hello, World!")
		}),
	}

	go m.Serve()

	if err := server.Serve(http2l); err != nil {
		log.Println(err)
	}
}

What did you expect to see?

2022/09/15 01:24:30 http2: Transport creating client conn 0xc00013c480 to [::1]:443
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: wrote SETTINGS len=18, settings: ENABLE_PUSH=0, INITIAL_WINDOW_SIZE=4194304, MAX_HEADER_LIST_SIZE=10485760
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: wrote WINDOW_UPDATE len=4 (conn) incr=1073741824
2022/09/15 01:24:30 http2: Transport encoding header ":authority" = "localhost"
2022/09/15 01:24:30 http2: Transport encoding header ":method" = "GET"
2022/09/15 01:24:30 http2: Transport encoding header ":path" = "/"
2022/09/15 01:24:30 http2: Transport encoding header ":scheme" = "https"
2022/09/15 01:24:30 http2: Transport encoding header "accept-encoding" = "gzip"
2022/09/15 01:24:30 http2: Transport encoding header "user-agent" = "Go-http-client/2.0"
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: read SETTINGS len=24, settings: MAX_FRAME_SIZE=1048576, MAX_CONCURRENT_STREAMS=250, MAX_HEADER_LIST_SIZE=1048896, INITIAL_WINDOW_SIZE=1048576
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: wrote HEADERS flags=END_STREAM|END_HEADERS stream=1 len=31
2022/09/15 01:24:30 http2: Transport received SETTINGS len=24, settings: MAX_FRAME_SIZE=1048576, MAX_CONCURRENT_STREAMS=250, MAX_HEADER_LIST_SIZE=1048896, INITIAL_WINDOW_SIZE=1048576
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: wrote SETTINGS flags=ACK len=0
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: read SETTINGS flags=ACK len=0
2022/09/15 01:24:30 http2: Transport received SETTINGS flags=ACK len=0
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: read WINDOW_UPDATE len=4 (conn) incr=983041
2022/09/15 01:24:30 http2: Transport received WINDOW_UPDATE len=4 (conn) incr=983041
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: read HEADERS flags=END_HEADERS stream=1 len=49
2022/09/15 01:24:30 http2: decoded hpack field header field ":status" = "200"
2022/09/15 01:24:30 http2: decoded hpack field header field "content-type" = "text/plain; charset=utf-8"
2022/09/15 01:24:30 http2: decoded hpack field header field "content-length" = "14"
2022/09/15 01:24:30 http2: decoded hpack field header field "date" = "Wed, 14 Sep 2022 17:24:30 GMT"
2022/09/15 01:24:30 http2: Transport received HEADERS flags=END_HEADERS stream=1 len=49
2022/09/15 01:24:30 http2: Framer 0xc0001540e0: read DATA flags=END_STREAM stream=1 len=14 data="Hello, World!\n"
2022/09/15 01:24:30 http2: Transport received DATA flags=END_STREAM stream=1 len=14 data="Hello, World!\n"

What did you see instead?

2022/09/15 01:26:25 http2: Transport creating client conn 0xc00013c480 to [::1]:443
2022/09/15 01:26:25 http2: Framer 0xc0001540e0: wrote SETTINGS len=18, settings: ENABLE_PUSH=0, INITIAL_WINDOW_SIZE=4194304, MAX_HEADER_LIST_SIZE=10485760
2022/09/15 01:26:25 http2: Framer 0xc0001540e0: wrote WINDOW_UPDATE len=4 (conn) incr=1073741824
2022/09/15 01:26:25 http2: Transport encoding header ":authority" = "localhost"
2022/09/15 01:26:25 http2: Transport encoding header ":method" = "GET"
2022/09/15 01:26:25 http2: Transport encoding header ":path" = "/"
2022/09/15 01:26:25 http2: Transport encoding header ":scheme" = "https"
2022/09/15 01:26:25 http2: Transport encoding header "accept-encoding" = "gzip"
2022/09/15 01:26:25 http2: Transport encoding header "user-agent" = "Go-http-client/2.0"
2022/09/15 01:26:25 http2: Framer 0xc0001540e0: wrote HEADERS flags=END_STREAM|END_HEADERS stream=1 len=31
2022/09/15 01:26:25 http2: Transport readFrame error on conn 0xc00013c480: (*net.OpError) read tcp [::1]:56749->[::1]:443: wsarecv: An established connection was aborted by the software in your host machine.
2022/09/15 01:26:25 RoundTrip failure: read tcp [::1]:56749->[::1]:443: wsarecv: An established connection was aborted by the software in your host machine.
@neild
Copy link
Contributor

neild commented Sep 14, 2022

Server.Serve is documented as only supporting HTTP/2 on a *tls.Conn:

HTTP/2 support is only enabled if the Listener returns *tls.Conn connections and they were configured with "h2" in the TLS Config.NextProtos.

I'm not certain we want to weaken that requirement; the server is already fairly tightly coupled to *tls.Conn since it needs to access the ALPN negotiated protocol, and it seems plausible that we'd want to access other details of the TLS connection in the future. What's the use case for this?

@lukeo3o1
Copy link
Author

lukeo3o1 commented Sep 14, 2022

@neild thanks for your reply and notice

In my use case I want to use cmux to listen to http2 and grpc services on the same port.

But this *tls.Conn type requirement will make custom net.Conn not work with http2 even though the underlying operation is *tls.Conn

@seankhliao
Copy link
Member

seankhliao commented Sep 14, 2022

The usual way is via grpc's ServeHTTP and treat it like any other handler

@gopherbot
Copy link

gopherbot commented Sep 15, 2022

Change https://go.dev/cl/431155 mentions this issue: net/http: http2 conn serve's net.Conn type assertion supports non *tls.Conn types

@neild
Copy link
Contributor

neild commented Sep 16, 2022

Another way to do this today is to use http2.Server.ServeConn directly, rather than relying on net/http routing the connection to the HTTP/2 implementation.

@lukeo3o1
Copy link
Author

lukeo3o1 commented Sep 18, 2022

Another way to do this today is to use http2.Server.ServeConn directly, rather than relying on net/http routing the connection to the HTTP/2 implementation.

Oh, thx! This is a great idea to me

@cherrymui cherrymui added the NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one. label Sep 19, 2022
@cherrymui cherrymui added this to the Unplanned milestone Sep 19, 2022
@lukeo3o1
Copy link
Author

lukeo3o1 commented Sep 27, 2022

If anyone has the same issue and usecase as me

Maybe you can try to use lukeo3o1/cmux@h2-support

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
NeedsInvestigation Someone must examine and confirm this is a valid issue and not a duplicate of an existing one.
Projects
None yet
Development

Successfully merging a pull request may close this issue.

5 participants