@@ -14,13 +14,15 @@ import (
1414 "strings"
1515 "time"
1616
17- "github.com/SenseUnit/dumbproxy/tlsutil "
17+ utls "github.com/refraction-networking/utls "
1818 "golang.org/x/net/http2"
1919 xproxy "golang.org/x/net/proxy"
20+
21+ "github.com/SenseUnit/dumbproxy/tlsutil"
2022)
2123
2224type h1RedeemError struct {
23- conn * tls .Conn
25+ conn net .Conn
2426}
2527
2628const alpnNegErrorText = "HTTP/2 was not negotiated via ALPN"
@@ -50,6 +52,18 @@ func h1FallbackFromContext(ctx context.Context) bool {
5052 return h1Fallback
5153}
5254
55+ type handshaker interface {
56+ HandshakeContext (context.Context ) error
57+ }
58+
59+ type connStater interface {
60+ ConnectionState () tls.ConnectionState
61+ }
62+
63+ type utlsConnStater interface {
64+ ConnectionState () utls.ConnectionState
65+ }
66+
5367type H2ProxyDialer struct {
5468 address string
5569 tlsConfig * tls.Config
@@ -185,19 +199,29 @@ func H2ProxyDialerFromURL(u *url.URL, next xproxy.Dialer) (xproxy.Dialer, error)
185199 ctc .NextProtos = append (ctc .NextProtos [0 :len (ctc .NextProtos ):len (ctc .NextProtos )], "http/1.1" )
186200 }
187201 conn = tlsFactory (conn , ctc )
188- if tlsConn , ok := conn .(* tls.Conn ); ok {
189- // it's a crypto/tls connection, we ought to see how ALPN went
190- if err := tlsConn .HandshakeContext (ctx ); err != nil {
191- tlsConn .Close ()
202+ if hs , ok := conn .(handshaker ); ok {
203+ if err := hs .HandshakeContext (ctx ); err != nil {
204+ conn .Close ()
192205 return nil , err
193206 }
194- if tlsConn .ConnectionState ().NegotiatedProtocol != "h2" {
207+ var negProto string
208+ switch c := conn .(type ) {
209+ case connStater :
210+ negProto = c .ConnectionState ().NegotiatedProtocol
211+ case utlsConnStater :
212+ negProto = c .ConnectionState ().NegotiatedProtocol
213+ default :
214+ // can't access TLS extensions of conn, ALPN is not available
215+ return conn , nil
216+ }
217+ // it's a TLS connection with ALPN, we ought to see how negotiation went
218+ if negProto != "h2" {
195219 if h1Fallback {
196220 // HTTP/2 was NOT negotiated! abort, but save the connection
197221 // for potential redemption via HTTP/1 dialer
198- return nil , h1RedeemError {tlsConn }
222+ return nil , h1RedeemError {conn }
199223 } else {
200- tlsConn .Close ()
224+ conn .Close ()
201225 return nil , errors .New (alpnNegErrorText )
202226 }
203227 }
0 commit comments