@@ -21,9 +21,11 @@ type connectionStater interface {
21
21
// can do this.
22
22
// 2. After wrapping the connection doesn't implement connectionStater, emit a warning so that listener
23
23
// wrapper authors will hopefully implement it.
24
+ // 3. check if the connection matches a specific http version. h2/h2c has a distinct preface.
24
25
type http2Listener struct {
25
26
useTLS bool
26
- useH2C bool
27
+ useH1 bool
28
+ useH2 bool
27
29
net.Listener
28
30
logger * zap.Logger
29
31
}
@@ -39,35 +41,32 @@ func (h *http2Listener) Accept() (net.Conn, error) {
39
41
if _ , ok := conn .(connectionStater ); ! ok {
40
42
h .logger .Warn ("tls is enabled, but listener wrapper returns a connection that doesn't implement connectionStater" )
41
43
}
42
- return & http2Conn {
43
- idx : len (http2 .ClientPreface ),
44
- Conn : conn ,
45
- }, nil
46
44
}
47
45
48
46
if _ , ok := conn .(connectionStater ); ok {
49
47
h .logger .Warn ("tls is disabled, but listener wrapper returns a connection that implements connectionStater" )
50
- return & http2Conn {
51
- idx : len (http2 .ClientPreface ),
52
- Conn : conn ,
53
- }, nil
54
48
}
55
49
56
- if h .useH2C {
50
+ // if both h1 and h2 are enabled, we don't need to check the preface
51
+ if h .useH1 && h .useH2 {
57
52
return & http2Conn {
58
53
idx : len (http2 .ClientPreface ),
59
54
Conn : conn ,
60
55
}, nil
61
56
}
62
57
63
58
return & http2Conn {
64
- Conn : conn ,
59
+ h2Expected : h .useH2 ,
60
+ Conn : conn ,
65
61
}, nil
66
62
}
67
63
68
64
type http2Conn struct {
69
- // check h2 preface if it's smaller that the preface
65
+ // current index where the preface should match,
66
+ // no matching is done if idx is >= len(http2.ClientPreface)
70
67
idx int
68
+ // whether the connection is expected to be h2/h2c
69
+ h2Expected bool
71
70
// log if one such connection is detected
72
71
logger * zap.Logger
73
72
net.Conn
@@ -79,14 +78,16 @@ func (c *http2Conn) Read(p []byte) (int, error) {
79
78
}
80
79
n , err := c .Conn .Read (p )
81
80
for i := range n {
82
- // mismatch
83
- if p [i ] != http2 .ClientPreface [c .idx ] {
84
- c .idx = len (http2 .ClientPreface )
85
- return n , err
81
+ // first mismatch, close the connection if h2 is expected
82
+ if p [i ] != http2 .ClientPreface [c .idx ] && c .h2Expected {
83
+ c .logger .Debug ("h1 connection detected, but h1 is not enabled" )
84
+ _ = c .Conn .Close ()
85
+ return 0 , io .EOF
86
86
}
87
87
c .idx ++
88
- if c .idx == len (http2 .ClientPreface ) {
89
- c .logger .Warn ("h2c connection detected, but h2c is not enabled" )
88
+ // matching complete
89
+ if c .idx == len (http2 .ClientPreface ) && ! c .h2Expected {
90
+ c .logger .Debug ("h2/h2c connection detected, but h2/h2c is not enabled" )
90
91
_ = c .Conn .Close ()
91
92
return 0 , io .EOF
92
93
}
0 commit comments