Commit dc89b5b4 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: update bundled http2

Updates x/net/http2 to git rev 493a262 for https://golang.org/cl/19223

Fixes #14227

Change-Id: I626122811138fb3d88e4eea83f8da3fdcf91e0dc
Reviewed-on: https://go-review.googlesource.com/19250Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
parent 107a6ef4
...@@ -2331,6 +2331,10 @@ var http2isTokenTable = [127]bool{ ...@@ -2331,6 +2331,10 @@ var http2isTokenTable = [127]bool{
'~': true, '~': true,
} }
type http2connectionStater interface {
ConnectionState() tls.ConnectionState
}
// pipe is a goroutine-safe io.Reader/io.Writer pair. It's like // pipe is a goroutine-safe io.Reader/io.Writer pair. It's like
// io.Pipe except there are no PipeReader/PipeWriter halves, and the // io.Pipe except there are no PipeReader/PipeWriter halves, and the
// underlying buffer is an interface. (io.Pipe is always unbuffered) // underlying buffer is an interface. (io.Pipe is always unbuffered)
...@@ -2593,28 +2597,76 @@ func http2ConfigureServer(s *Server, conf *http2Server) error { ...@@ -2593,28 +2597,76 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
if http2testHookOnConn != nil { if http2testHookOnConn != nil {
http2testHookOnConn() http2testHookOnConn()
} }
conf.handleConn(hs, c, h) conf.ServeConn(c, &http2ServeConnOpts{
Handler: h,
BaseConfig: hs,
})
} }
s.TLSNextProto[http2NextProtoTLS] = protoHandler s.TLSNextProto[http2NextProtoTLS] = protoHandler
s.TLSNextProto["h2-14"] = protoHandler s.TLSNextProto["h2-14"] = protoHandler
return nil return nil
} }
func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) { // ServeConnOpts are options for the Server.ServeConn method.
type http2ServeConnOpts struct {
// BaseConfig optionally sets the base configuration
// for values. If nil, defaults are used.
BaseConfig *Server
// Handler specifies which handler to use for processing
// requests. If nil, BaseConfig.Handler is used. If BaseConfig
// or BaseConfig.Handler is nil, http.DefaultServeMux is used.
Handler Handler
}
func (o *http2ServeConnOpts) baseConfig() *Server {
if o != nil && o.BaseConfig != nil {
return o.BaseConfig
}
return new(Server)
}
func (o *http2ServeConnOpts) handler() Handler {
if o != nil {
if o.Handler != nil {
return o.Handler
}
if o.BaseConfig != nil && o.BaseConfig.Handler != nil {
return o.BaseConfig.Handler
}
}
return DefaultServeMux
}
// ServeConn serves HTTP/2 requests on the provided connection and
// blocks until the connection is no longer readable.
//
// ServeConn starts speaking HTTP/2 assuming that c has not had any
// reads or writes. It writes its initial settings frame and expects
// to be able to read the preface and settings frame from the
// client. If c has a ConnectionState method like a *tls.Conn, the
// ConnectionState is used to verify the TLS ciphersuite and to set
// the Request.TLS field in Handlers.
//
// ServeConn does not support h2c by itself. Any h2c support must be
// implemented in terms of providing a suitably-behaving net.Conn.
//
// The opts parameter is optional. If nil, default values are used.
func (s *http2Server) ServeConn(c net.Conn, opts *http2ServeConnOpts) {
sc := &http2serverConn{ sc := &http2serverConn{
srv: srv, srv: s,
hs: hs, hs: opts.baseConfig(),
conn: c, conn: c,
remoteAddrStr: c.RemoteAddr().String(), remoteAddrStr: c.RemoteAddr().String(),
bw: http2newBufferedWriter(c), bw: http2newBufferedWriter(c),
handler: h, handler: opts.handler(),
streams: make(map[uint32]*http2stream), streams: make(map[uint32]*http2stream),
readFrameCh: make(chan http2readFrameResult), readFrameCh: make(chan http2readFrameResult),
wantWriteFrameCh: make(chan http2frameWriteMsg, 8), wantWriteFrameCh: make(chan http2frameWriteMsg, 8),
wroteFrameCh: make(chan http2frameWriteResult, 1), wroteFrameCh: make(chan http2frameWriteResult, 1),
bodyReadCh: make(chan http2bodyReadMsg), bodyReadCh: make(chan http2bodyReadMsg),
doneServing: make(chan struct{}), doneServing: make(chan struct{}),
advMaxStreams: srv.maxConcurrentStreams(), advMaxStreams: s.maxConcurrentStreams(),
writeSched: http2writeScheduler{ writeSched: http2writeScheduler{
maxFrameSize: http2initialMaxFrameSize, maxFrameSize: http2initialMaxFrameSize,
}, },
...@@ -2630,10 +2682,10 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) { ...@@ -2630,10 +2682,10 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen()) sc.hpackDecoder.SetMaxStringLength(sc.maxHeaderStringLen())
fr := http2NewFramer(sc.bw, c) fr := http2NewFramer(sc.bw, c)
fr.SetMaxReadFrameSize(srv.maxReadFrameSize()) fr.SetMaxReadFrameSize(s.maxReadFrameSize())
sc.framer = fr sc.framer = fr
if tc, ok := c.(*tls.Conn); ok { if tc, ok := c.(http2connectionStater); ok {
sc.tlsState = new(tls.ConnectionState) sc.tlsState = new(tls.ConnectionState)
*sc.tlsState = tc.ConnectionState() *sc.tlsState = tc.ConnectionState()
...@@ -2646,7 +2698,7 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) { ...@@ -2646,7 +2698,7 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
} }
if !srv.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) { if !s.PermitProhibitedCipherSuites && http2isBadCipher(sc.tlsState.CipherSuite) {
sc.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite)) sc.rejectConn(http2ErrCodeInadequateSecurity, fmt.Sprintf("Prohibited TLS 1.2 Cipher Suite: %x", sc.tlsState.CipherSuite))
return return
...@@ -4874,10 +4926,7 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) { ...@@ -4874,10 +4926,7 @@ func (t *http2Transport) NewClientConn(c net.Conn) (*http2ClientConn, error) {
cc.henc = hpack.NewEncoder(&cc.hbuf) cc.henc = hpack.NewEncoder(&cc.hbuf)
type connectionStater interface { if cs, ok := c.(http2connectionStater); ok {
ConnectionState() tls.ConnectionState
}
if cs, ok := c.(connectionStater); ok {
state := cs.ConnectionState() state := cs.ConnectionState()
cc.tlsState = &state cc.tlsState = &state
} }
...@@ -5028,7 +5077,27 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration { ...@@ -5028,7 +5077,27 @@ func (cc *http2ClientConn) responseHeaderTimeout() time.Duration {
return 0 return 0
} }
// checkConnHeaders checks whether req has any invalid connection-level headers.
// per RFC 7540 section 8.1.2.2: Connection-Specific Header Fields.
// Certain headers are special-cased as okay but not transmitted later.
func http2checkConnHeaders(req *Request) error {
if v := req.Header.Get("Upgrade"); v != "" {
return errors.New("http2: invalid Upgrade request header")
}
if v := req.Header.Get("Transfer-Encoding"); (v != "" && v != "chunked") || len(req.Header["Transfer-Encoding"]) > 1 {
return errors.New("http2: invalid Transfer-Encoding request header")
}
if v := req.Header.Get("Connection"); (v != "" && v != "close" && v != "keep-alive") || len(req.Header["Connection"]) > 1 {
return errors.New("http2: invalid Connection request header")
}
return nil
}
func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) { func (cc *http2ClientConn) RoundTrip(req *Request) (*Response, error) {
if err := http2checkConnHeaders(req); err != nil {
return nil, err
}
trailers, err := http2commaSeparatedTrailers(req) trailers, err := http2commaSeparatedTrailers(req)
if err != nil { if err != nil {
return nil, err return nil, err
...@@ -5334,10 +5403,14 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail ...@@ -5334,10 +5403,14 @@ func (cc *http2ClientConn) encodeHeaders(req *Request, addGzipHeader bool, trail
var didUA bool var didUA bool
for k, vv := range req.Header { for k, vv := range req.Header {
lowKey := strings.ToLower(k) lowKey := strings.ToLower(k)
if lowKey == "host" || lowKey == "content-length" { switch lowKey {
case "host", "content-length":
continue continue
} case "connection", "proxy-connection", "transfer-encoding", "upgrade":
if lowKey == "user-agent" {
continue
case "user-agent":
didUA = true didUA = true
if len(vv) < 1 { if len(vv) < 1 {
...@@ -5445,8 +5518,9 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr ...@@ -5445,8 +5518,9 @@ func (cc *http2ClientConn) streamByID(id uint32, andRemove bool) *http2clientStr
// clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop. // clientConnReadLoop is the state owned by the clientConn's frame-reading readLoop.
type http2clientConnReadLoop struct { type http2clientConnReadLoop struct {
cc *http2ClientConn cc *http2ClientConn
activeRes map[uint32]*http2clientStream // keyed by streamID activeRes map[uint32]*http2clientStream // keyed by streamID
closeWhenIdle bool
hdec *hpack.Decoder hdec *hpack.Decoder
...@@ -5503,7 +5577,7 @@ func (rl *http2clientConnReadLoop) cleanup() { ...@@ -5503,7 +5577,7 @@ func (rl *http2clientConnReadLoop) cleanup() {
func (rl *http2clientConnReadLoop) run() error { func (rl *http2clientConnReadLoop) run() error {
cc := rl.cc cc := rl.cc
closeWhenIdle := cc.t.disableKeepAlives() rl.closeWhenIdle = cc.t.disableKeepAlives()
gotReply := false gotReply := false
for { for {
f, err := cc.fr.ReadFrame() f, err := cc.fr.ReadFrame()
...@@ -5552,7 +5626,7 @@ func (rl *http2clientConnReadLoop) run() error { ...@@ -5552,7 +5626,7 @@ func (rl *http2clientConnReadLoop) run() error {
if err != nil { if err != nil {
return err return err
} }
if closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 { if rl.closeWhenIdle && gotReply && maybeIdle && len(rl.activeRes) == 0 {
cc.closeIfIdle() cc.closeIfIdle()
} }
} }
...@@ -5803,6 +5877,9 @@ func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) { ...@@ -5803,6 +5877,9 @@ func (rl *http2clientConnReadLoop) endStream(cs *http2clientStream) {
} }
cs.bufPipe.closeWithErrorAndCode(err, code) cs.bufPipe.closeWithErrorAndCode(err, code)
delete(rl.activeRes, cs.ID) delete(rl.activeRes, cs.ID)
if cs.req.Close || cs.req.Header.Get("Connection") == "close" {
rl.closeWhenIdle = true
}
} }
func (cs *http2clientStream) copyTrailers() { func (cs *http2clientStream) copyTrailers() {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment