Skip to content

Commit d1683ac

Browse files
committed
http2: server advertises SETTINGS_ENABLE_CONNECT_PROTOCOL support
1 parent 9bf379f commit d1683ac

File tree

3 files changed

+49
-26
lines changed

3 files changed

+49
-26
lines changed

Diff for: http2/frame.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1490,7 +1490,7 @@ func (mh *MetaHeadersFrame) checkPseudos() error {
14901490
pf := mh.PseudoFields()
14911491
for i, hf := range pf {
14921492
switch hf.Name {
1493-
case ":method", ":path", ":scheme", ":authority":
1493+
case ":method", ":path", ":scheme", ":authority", ":protocol":
14941494
isRequest = true
14951495
case ":status":
14961496
isResponse = true

Diff for: http2/http2.go

+22-16
Original file line numberDiff line numberDiff line change
@@ -33,10 +33,11 @@ import (
3333
)
3434

3535
var (
36-
VerboseLogs bool
37-
logFrameWrites bool
38-
logFrameReads bool
39-
inTests bool
36+
VerboseLogs bool
37+
logFrameWrites bool
38+
logFrameReads bool
39+
inTests bool
40+
disableExtendedConnectProtocol bool
4041
)
4142

4243
func init() {
@@ -49,6 +50,9 @@ func init() {
4950
logFrameWrites = true
5051
logFrameReads = true
5152
}
53+
if strings.Contains(e, "http2xconnect=0") {
54+
disableExtendedConnectProtocol = true
55+
}
5256
}
5357

5458
const (
@@ -149,21 +153,23 @@ func (s Setting) Valid() error {
149153
type SettingID uint16
150154

151155
const (
152-
SettingHeaderTableSize SettingID = 0x1
153-
SettingEnablePush SettingID = 0x2
154-
SettingMaxConcurrentStreams SettingID = 0x3
155-
SettingInitialWindowSize SettingID = 0x4
156-
SettingMaxFrameSize SettingID = 0x5
157-
SettingMaxHeaderListSize SettingID = 0x6
156+
SettingHeaderTableSize SettingID = 0x1
157+
SettingEnablePush SettingID = 0x2
158+
SettingMaxConcurrentStreams SettingID = 0x3
159+
SettingInitialWindowSize SettingID = 0x4
160+
SettingMaxFrameSize SettingID = 0x5
161+
SettingMaxHeaderListSize SettingID = 0x6
162+
SettingEnableConnectProtocol SettingID = 0x8
158163
)
159164

160165
var settingName = map[SettingID]string{
161-
SettingHeaderTableSize: "HEADER_TABLE_SIZE",
162-
SettingEnablePush: "ENABLE_PUSH",
163-
SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
164-
SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
165-
SettingMaxFrameSize: "MAX_FRAME_SIZE",
166-
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
166+
SettingHeaderTableSize: "HEADER_TABLE_SIZE",
167+
SettingEnablePush: "ENABLE_PUSH",
168+
SettingMaxConcurrentStreams: "MAX_CONCURRENT_STREAMS",
169+
SettingInitialWindowSize: "INITIAL_WINDOW_SIZE",
170+
SettingMaxFrameSize: "MAX_FRAME_SIZE",
171+
SettingMaxHeaderListSize: "MAX_HEADER_LIST_SIZE",
172+
SettingEnableConnectProtocol: "ENABLE_CONNECT_PROTOCOL",
167173
}
168174

169175
func (s SettingID) String() string {

Diff for: http2/server.go

+26-9
Original file line numberDiff line numberDiff line change
@@ -935,14 +935,18 @@ func (sc *serverConn) serve() {
935935
sc.vlogf("http2: server connection from %v on %p", sc.conn.RemoteAddr(), sc.hs)
936936
}
937937

938+
settings := writeSettings{
939+
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
940+
{SettingMaxConcurrentStreams, sc.advMaxStreams},
941+
{SettingMaxHeaderListSize, sc.maxHeaderListSize()},
942+
{SettingHeaderTableSize, sc.srv.maxDecoderHeaderTableSize()},
943+
{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
944+
}
945+
if !disableExtendedConnectProtocol {
946+
settings = append(settings, Setting{SettingEnableConnectProtocol, 1})
947+
}
938948
sc.writeFrame(FrameWriteRequest{
939-
write: writeSettings{
940-
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
941-
{SettingMaxConcurrentStreams, sc.advMaxStreams},
942-
{SettingMaxHeaderListSize, sc.maxHeaderListSize()},
943-
{SettingHeaderTableSize, sc.srv.maxDecoderHeaderTableSize()},
944-
{SettingInitialWindowSize, uint32(sc.srv.initialStreamRecvWindowSize())},
945-
},
949+
write: settings,
946950
})
947951
sc.unackedSettings++
948952

@@ -1757,6 +1761,9 @@ func (sc *serverConn) processSetting(s Setting) error {
17571761
sc.maxFrameSize = int32(s.Val) // the maximum valid s.Val is < 2^31
17581762
case SettingMaxHeaderListSize:
17591763
sc.peerMaxHeaderListSize = s.Val
1764+
case SettingEnableConnectProtocol:
1765+
// Receipt of this parameter by a server does not
1766+
// have any impact
17601767
default:
17611768
// Unknown setting: "An endpoint that receives a SETTINGS
17621769
// frame with any unknown or unsupported identifier MUST
@@ -2187,11 +2194,17 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
21872194
scheme: f.PseudoValue("scheme"),
21882195
authority: f.PseudoValue("authority"),
21892196
path: f.PseudoValue("path"),
2197+
protocol: f.PseudoValue("protocol"),
2198+
}
2199+
2200+
// extended connect is disabled, so we should not see :protocol
2201+
if disableExtendedConnectProtocol && rp.protocol != "" {
2202+
return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
21902203
}
21912204

21922205
isConnect := rp.method == "CONNECT"
21932206
if isConnect {
2194-
if rp.path != "" || rp.scheme != "" || rp.authority == "" {
2207+
if rp.protocol == "" && (rp.path != "" || rp.scheme != "" || rp.authority == "") {
21952208
return nil, nil, sc.countError("bad_connect", streamError(f.StreamID, ErrCodeProtocol))
21962209
}
21972210
} else if rp.method == "" || rp.path == "" || (rp.scheme != "https" && rp.scheme != "http") {
@@ -2215,6 +2228,9 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
22152228
if rp.authority == "" {
22162229
rp.authority = rp.header.Get("Host")
22172230
}
2231+
if rp.protocol != "" {
2232+
rp.header.Set(":protocol", rp.protocol)
2233+
}
22182234

22192235
rw, req, err := sc.newWriterAndRequestNoBody(st, rp)
22202236
if err != nil {
@@ -2241,6 +2257,7 @@ func (sc *serverConn) newWriterAndRequest(st *stream, f *MetaHeadersFrame) (*res
22412257
type requestParam struct {
22422258
method string
22432259
scheme, authority, path string
2260+
protocol string
22442261
header http.Header
22452262
}
22462263

@@ -2282,7 +2299,7 @@ func (sc *serverConn) newWriterAndRequestNoBody(st *stream, rp requestParam) (*r
22822299

22832300
var url_ *url.URL
22842301
var requestURI string
2285-
if rp.method == "CONNECT" {
2302+
if rp.method == "CONNECT" && rp.protocol == "" {
22862303
url_ = &url.URL{Host: rp.authority}
22872304
requestURI = rp.authority // mimic HTTP/1 server behavior
22882305
} else {

0 commit comments

Comments
 (0)