|
@@ -220,6 +220,7 @@ func (srv *Server) handleConn(hs *http.Server, c net.Conn, h http.Handler) {
|
|
|
sc.inflow.add(initialWindowSize)
|
|
sc.inflow.add(initialWindowSize)
|
|
|
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
|
|
sc.hpackEncoder = hpack.NewEncoder(&sc.headerWriteBuf)
|
|
|
sc.hpackDecoder = hpack.NewDecoder(initialHeaderTableSize, sc.onNewHeaderField)
|
|
sc.hpackDecoder = hpack.NewDecoder(initialHeaderTableSize, sc.onNewHeaderField)
|
|
|
|
|
+ sc.hpackDecoder.SetMaxHeaderListSize(sc.maxHeaderListSize())
|
|
|
|
|
|
|
|
fr := NewFramer(sc.bw, c)
|
|
fr := NewFramer(sc.bw, c)
|
|
|
fr.SetMaxReadFrameSize(srv.maxReadFrameSize())
|
|
fr.SetMaxReadFrameSize(srv.maxReadFrameSize())
|
|
@@ -353,7 +354,7 @@ type serverConn struct {
|
|
|
streams map[uint32]*stream
|
|
streams map[uint32]*stream
|
|
|
initialWindowSize int32
|
|
initialWindowSize int32
|
|
|
headerTableSize uint32
|
|
headerTableSize uint32
|
|
|
- maxHeaderListSize uint32 // zero means unknown (default)
|
|
|
|
|
|
|
+ peerMaxHeaderListSize uint32 // zero means unknown (default)
|
|
|
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
|
|
canonHeader map[string]string // http2-lower-case -> Go-Canonical-Case
|
|
|
req requestParam // non-zero while reading request headers
|
|
req requestParam // non-zero while reading request headers
|
|
|
writingFrame bool // started write goroutine but haven't heard back on wroteFrameCh
|
|
writingFrame bool // started write goroutine but haven't heard back on wroteFrameCh
|
|
@@ -370,6 +371,18 @@ type serverConn struct {
|
|
|
hpackEncoder *hpack.Encoder
|
|
hpackEncoder *hpack.Encoder
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+func (sc *serverConn) maxHeaderListSize() uint32 {
|
|
|
|
|
+ n := sc.hs.MaxHeaderBytes
|
|
|
|
|
+ if n == 0 {
|
|
|
|
|
+ n = http.DefaultMaxHeaderBytes
|
|
|
|
|
+ }
|
|
|
|
|
+ // http2's count is in a slightly different unit and includes 32 bytes per pair.
|
|
|
|
|
+ // So, take the net/http.Server value and pad it up a bit, assuming 10 headers.
|
|
|
|
|
+ const perFieldOverhead = 32 // per http2 spec
|
|
|
|
|
+ const typicalHeaders = 10 // conservative
|
|
|
|
|
+ return uint32(n + typicalHeaders*perFieldOverhead)
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
// requestParam is the state of the next request, initialized over
|
|
// requestParam is the state of the next request, initialized over
|
|
|
// potentially several frames HEADERS + zero or more CONTINUATION
|
|
// potentially several frames HEADERS + zero or more CONTINUATION
|
|
|
// frames.
|
|
// frames.
|
|
@@ -602,6 +615,7 @@ func (sc *serverConn) serve() {
|
|
|
write: writeSettings{
|
|
write: writeSettings{
|
|
|
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
|
|
{SettingMaxFrameSize, sc.srv.maxReadFrameSize()},
|
|
|
{SettingMaxConcurrentStreams, sc.advMaxStreams},
|
|
{SettingMaxConcurrentStreams, sc.advMaxStreams},
|
|
|
|
|
+ {SettingMaxHeaderListSize, sc.maxHeaderListSize()},
|
|
|
|
|
|
|
|
// TODO: more actual settings, notably
|
|
// TODO: more actual settings, notably
|
|
|
// SettingInitialWindowSize, but then we also
|
|
// SettingInitialWindowSize, but then we also
|
|
@@ -1100,7 +1114,7 @@ func (sc *serverConn) processSetting(s Setting) error {
|
|
|
case SettingMaxFrameSize:
|
|
case SettingMaxFrameSize:
|
|
|
sc.writeSched.maxFrameSize = s.Val
|
|
sc.writeSched.maxFrameSize = s.Val
|
|
|
case SettingMaxHeaderListSize:
|
|
case SettingMaxHeaderListSize:
|
|
|
- sc.maxHeaderListSize = s.Val
|
|
|
|
|
|
|
+ sc.peerMaxHeaderListSize = s.Val
|
|
|
default:
|
|
default:
|
|
|
// Unknown setting: "An endpoint that receives a SETTINGS
|
|
// Unknown setting: "An endpoint that receives a SETTINGS
|
|
|
// frame with any unknown or unsupported identifier MUST
|
|
// frame with any unknown or unsupported identifier MUST
|