soheilhy / cmux

Connection multiplexer for GoLang: serve different services on the same port!
Apache License 2.0
2.53k stars 197 forks source link

gPRC and HTTP/2 health check with TLS #68

Open jeffreydking opened 5 years ago

jeffreydking commented 5 years ago

I can't get gPRC and HTTP/2 health checks (both with TLS) to work. I believe the prescribed approach is to follow the RecursiveCmux example; we need to handle the TLS handshake before we can match on HTTP2HeaderFieldPrefix for gRPC (all other TLS traffic would be routed to the HTTP/2 health check server).

The problem then arises that, for the HTTP/2 health check server, we can't use http.ListenAndServeTLS since the TLS is already resolved using tls.NewListener. So we must use http.Serve. http.Serve documentation says:

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

Adding "h2" to the TLS Config.NextProtos is straight forward enough. However, even though tls.NewListener returns a listener that returns tls.Conn connections, it appears that when this listener is wrapped in the CMux object, it modifies the listener to return MuxConn connections rather than tls.Conn. This breaks things. When I execute:

curl https://localhost:443 --http2 -Ik

I get a response of

curl: (16) Error in the HTTP2 framing layer

Is it possible to serve gPRC and HTTP/2 health checks (both with TLS) using the cmux package?

DanTulovsky commented 3 years ago

I am also seeing this error. I am using RecursiveCmux approach. Additionally, it seems that:

m.MatchWithWriters(cmux.HTTP2MatchHeaderFieldPrefixSendSettings("content-type", "grpc"))

does not actually work. It fails to match grpc traffic. So trying to serve bother http2 and grpc at the same time isn't working.

raidancampbell commented 3 years ago

I'm still seeing it with the same setup as OP. Walking through the code, it appears the issue occurs on this type assertion in the stdlib:

tlsConn, ok := c.rwc.(*tls.Conn)

rwc is of type MuxConn, which is:

type MuxConn struct {
    net.Conn
    buf bufferedReader
}

Unfortunately, type assertion on the embedded struct fails, even though the underlying net.Conn is of type *crypto/tls.Conn