mirror of https://github.com/golang/go.git
net/http: update copy of http2
Updates to x/net git revision 9946ad7 Change-Id: I95c03daf382667002a5b22f184bd9b7d18144913 Reviewed-on: https://go-review.googlesource.com/16066 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
cf59c1f9cc
commit
3b000b3eae
|
|
@ -1750,7 +1750,7 @@ const (
|
||||||
var (
|
var (
|
||||||
http2errClientDisconnected = errors.New("client disconnected")
|
http2errClientDisconnected = errors.New("client disconnected")
|
||||||
http2errClosedBody = errors.New("body closed by handler")
|
http2errClosedBody = errors.New("body closed by handler")
|
||||||
http2errStreamBroken = errors.New("http2: stream broken")
|
http2errStreamClosed = errors.New("http2: stream closed")
|
||||||
)
|
)
|
||||||
|
|
||||||
var http2responseWriterStatePool = sync.Pool{
|
var http2responseWriterStatePool = sync.Pool{
|
||||||
|
|
@ -1819,24 +1819,33 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
|
||||||
if conf == nil {
|
if conf == nil {
|
||||||
conf = new(http2Server)
|
conf = new(http2Server)
|
||||||
}
|
}
|
||||||
|
|
||||||
if s.TLSConfig == nil {
|
if s.TLSConfig == nil {
|
||||||
s.TLSConfig = new(tls.Config)
|
s.TLSConfig = new(tls.Config)
|
||||||
}
|
} else if s.TLSConfig.CipherSuites != nil {
|
||||||
|
// If they already provided a CipherSuite list, return
|
||||||
if s.TLSConfig.CipherSuites != nil {
|
// an error if it has a bad order or is missing
|
||||||
|
// ECDHE_RSA_WITH_AES_128_GCM_SHA256.
|
||||||
const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
const requiredCipher = tls.TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
|
||||||
haveRequired := false
|
haveRequired := false
|
||||||
for _, v := range s.TLSConfig.CipherSuites {
|
sawBad := false
|
||||||
if v == requiredCipher {
|
for i, cs := range s.TLSConfig.CipherSuites {
|
||||||
|
if cs == requiredCipher {
|
||||||
haveRequired = true
|
haveRequired = true
|
||||||
break
|
}
|
||||||
|
if http2isBadCipher(cs) {
|
||||||
|
sawBad = true
|
||||||
|
} else if sawBad {
|
||||||
|
return fmt.Errorf("http2: TLSConfig.CipherSuites index %d contains an HTTP/2-approved cipher suite (%#04x), but it comes after unapproved cipher suites. With this configuration, clients that don't support previous, approved cipher suites may be given an unapproved one and reject the connection.", i, cs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if !haveRequired {
|
if !haveRequired {
|
||||||
s.TLSConfig.CipherSuites = append(s.TLSConfig.CipherSuites, requiredCipher)
|
return fmt.Errorf("http2: TLSConfig.CipherSuites is missing HTTP/2-required TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
s.TLSConfig.PreferServerCipherSuites = true
|
||||||
|
|
||||||
haveNPN := false
|
haveNPN := false
|
||||||
for _, p := range s.TLSConfig.NextProtos {
|
for _, p := range s.TLSConfig.NextProtos {
|
||||||
if p == http2NextProtoTLS {
|
if p == http2NextProtoTLS {
|
||||||
|
|
@ -1861,7 +1870,7 @@ func http2ConfigureServer(s *Server, conf *http2Server) error {
|
||||||
}
|
}
|
||||||
s.TLSNextProto[http2NextProtoTLS] = protoHandler
|
s.TLSNextProto[http2NextProtoTLS] = protoHandler
|
||||||
s.TLSNextProto["h2-14"] = protoHandler
|
s.TLSNextProto["h2-14"] = protoHandler
|
||||||
return nil // temporary manual edit to h2_bundle.go, to be deleted once we update from x/net again
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
|
func (srv *http2Server) handleConn(hs *Server, c net.Conn, h Handler) {
|
||||||
|
|
@ -1875,7 +1884,7 @@ func (srv *http2Server) handleConn(hs *Server, c net.Conn, h 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 struct{}, 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: srv.maxConcurrentStreams(),
|
||||||
|
|
@ -1961,15 +1970,15 @@ type http2serverConn struct {
|
||||||
handler Handler
|
handler Handler
|
||||||
framer *http2Framer
|
framer *http2Framer
|
||||||
hpackDecoder *hpack.Decoder
|
hpackDecoder *hpack.Decoder
|
||||||
doneServing chan struct{} // closed when serverConn.serve ends
|
doneServing chan struct{} // closed when serverConn.serve ends
|
||||||
readFrameCh chan http2readFrameResult // written by serverConn.readFrames
|
readFrameCh chan http2readFrameResult // written by serverConn.readFrames
|
||||||
wantWriteFrameCh chan http2frameWriteMsg // from handlers -> serve
|
wantWriteFrameCh chan http2frameWriteMsg // from handlers -> serve
|
||||||
wroteFrameCh chan struct{} // from writeFrameAsync -> serve, tickles more frame writes
|
wroteFrameCh chan http2frameWriteResult // from writeFrameAsync -> serve, tickles more frame writes
|
||||||
bodyReadCh chan http2bodyReadMsg // from handlers -> serve
|
bodyReadCh chan http2bodyReadMsg // from handlers -> serve
|
||||||
testHookCh chan func(int) // code to run on the serve loop
|
testHookCh chan func(int) // code to run on the serve loop
|
||||||
flow http2flow // conn-wide (not stream-specific) outbound flow control
|
flow http2flow // conn-wide (not stream-specific) outbound flow control
|
||||||
inflow http2flow // conn-wide inbound flow control
|
inflow http2flow // conn-wide inbound flow control
|
||||||
tlsState *tls.ConnectionState // shared by all handlers, like net/http
|
tlsState *tls.ConnectionState // shared by all handlers, like net/http
|
||||||
remoteAddrStr string
|
remoteAddrStr string
|
||||||
|
|
||||||
// Everything following is owned by the serve loop; use serveG.check():
|
// Everything following is owned by the serve loop; use serveG.check():
|
||||||
|
|
@ -2086,6 +2095,15 @@ func (sc *http2serverConn) state(streamID uint32) (http2streamState, *http2strea
|
||||||
return http2stateIdle, nil
|
return http2stateIdle, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setConnState calls the net/http ConnState hook for this connection, if configured.
|
||||||
|
// Note that the net/http package does StateNew and StateClosed for us.
|
||||||
|
// There is currently no plan for StateHijacked or hijacking HTTP/2 connections.
|
||||||
|
func (sc *http2serverConn) setConnState(state ConnState) {
|
||||||
|
if sc.hs.ConnState != nil {
|
||||||
|
sc.hs.ConnState(sc.conn, state)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func (sc *http2serverConn) vlogf(format string, args ...interface{}) {
|
func (sc *http2serverConn) vlogf(format string, args ...interface{}) {
|
||||||
if http2VerboseLogs {
|
if http2VerboseLogs {
|
||||||
sc.logf(format, args...)
|
sc.logf(format, args...)
|
||||||
|
|
@ -2207,20 +2225,19 @@ func (sc *http2serverConn) readFrames() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// frameWriteResult is the message passed from writeFrameAsync to the serve goroutine.
|
||||||
|
type http2frameWriteResult struct {
|
||||||
|
wm http2frameWriteMsg // what was written (or attempted)
|
||||||
|
err error // result of the writeFrame call
|
||||||
|
}
|
||||||
|
|
||||||
// writeFrameAsync runs in its own goroutine and writes a single frame
|
// writeFrameAsync runs in its own goroutine and writes a single frame
|
||||||
// and then reports when it's done.
|
// and then reports when it's done.
|
||||||
// At most one goroutine can be running writeFrameAsync at a time per
|
// At most one goroutine can be running writeFrameAsync at a time per
|
||||||
// serverConn.
|
// serverConn.
|
||||||
func (sc *http2serverConn) writeFrameAsync(wm http2frameWriteMsg) {
|
func (sc *http2serverConn) writeFrameAsync(wm http2frameWriteMsg) {
|
||||||
err := wm.write.writeFrame(sc)
|
err := wm.write.writeFrame(sc)
|
||||||
if ch := wm.done; ch != nil {
|
sc.wroteFrameCh <- http2frameWriteResult{wm, err}
|
||||||
select {
|
|
||||||
case ch <- err:
|
|
||||||
default:
|
|
||||||
panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wm.write))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
sc.wroteFrameCh <- struct{}{}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func (sc *http2serverConn) closeAllStreamsOnConnClose() {
|
func (sc *http2serverConn) closeAllStreamsOnConnClose() {
|
||||||
|
|
@ -2275,6 +2292,9 @@ func (sc *http2serverConn) serve() {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc.setConnState(StateActive)
|
||||||
|
sc.setConnState(StateIdle)
|
||||||
|
|
||||||
go sc.readFrames()
|
go sc.readFrames()
|
||||||
|
|
||||||
settingsTimer := time.NewTimer(http2firstSettingsTimeout)
|
settingsTimer := time.NewTimer(http2firstSettingsTimeout)
|
||||||
|
|
@ -2284,12 +2304,8 @@ func (sc *http2serverConn) serve() {
|
||||||
select {
|
select {
|
||||||
case wm := <-sc.wantWriteFrameCh:
|
case wm := <-sc.wantWriteFrameCh:
|
||||||
sc.writeFrame(wm)
|
sc.writeFrame(wm)
|
||||||
case <-sc.wroteFrameCh:
|
case res := <-sc.wroteFrameCh:
|
||||||
if sc.writingFrame != true {
|
sc.wroteFrame(res)
|
||||||
panic("internal error: expected to be already writing a frame")
|
|
||||||
}
|
|
||||||
sc.writingFrame = false
|
|
||||||
sc.scheduleFrameWrite()
|
|
||||||
case res := <-sc.readFrameCh:
|
case res := <-sc.readFrameCh:
|
||||||
if !sc.processFrameFromReader(res) {
|
if !sc.processFrameFromReader(res) {
|
||||||
return
|
return
|
||||||
|
|
@ -2355,20 +2371,28 @@ var http2errChanPool = sync.Pool{
|
||||||
// scheduling decisions available.
|
// scheduling decisions available.
|
||||||
func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, writeData *http2writeData) error {
|
func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, writeData *http2writeData) error {
|
||||||
ch := http2errChanPool.Get().(chan error)
|
ch := http2errChanPool.Get().(chan error)
|
||||||
sc.writeFrameFromHandler(http2frameWriteMsg{
|
err := sc.writeFrameFromHandler(http2frameWriteMsg{
|
||||||
write: writeData,
|
write: writeData,
|
||||||
stream: stream,
|
stream: stream,
|
||||||
done: ch,
|
done: ch,
|
||||||
})
|
})
|
||||||
select {
|
if err != nil {
|
||||||
case err := <-ch:
|
|
||||||
http2errChanPool.Put(ch)
|
|
||||||
return err
|
return err
|
||||||
|
}
|
||||||
|
select {
|
||||||
|
case err = <-ch:
|
||||||
case <-sc.doneServing:
|
case <-sc.doneServing:
|
||||||
return http2errClientDisconnected
|
return http2errClientDisconnected
|
||||||
case <-stream.cw:
|
case <-stream.cw:
|
||||||
return http2errStreamBroken
|
|
||||||
|
select {
|
||||||
|
case err = <-ch:
|
||||||
|
default:
|
||||||
|
return http2errStreamClosed
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
http2errChanPool.Put(ch)
|
||||||
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// writeFrameFromHandler sends wm to sc.wantWriteFrameCh, but aborts
|
// writeFrameFromHandler sends wm to sc.wantWriteFrameCh, but aborts
|
||||||
|
|
@ -2378,24 +2402,14 @@ func (sc *http2serverConn) writeDataFromHandler(stream *http2stream, writeData *
|
||||||
// deadlock writing to sc.wantWriteFrameCh (which is only mildly
|
// deadlock writing to sc.wantWriteFrameCh (which is only mildly
|
||||||
// buffered and is read by serve itself). If you're on the serve
|
// buffered and is read by serve itself). If you're on the serve
|
||||||
// goroutine, call writeFrame instead.
|
// goroutine, call writeFrame instead.
|
||||||
func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) {
|
func (sc *http2serverConn) writeFrameFromHandler(wm http2frameWriteMsg) error {
|
||||||
sc.serveG.checkNotOn()
|
sc.serveG.checkNotOn()
|
||||||
var scheduled bool
|
|
||||||
select {
|
select {
|
||||||
case sc.wantWriteFrameCh <- wm:
|
case sc.wantWriteFrameCh <- wm:
|
||||||
scheduled = true
|
return nil
|
||||||
case <-sc.doneServing:
|
case <-sc.doneServing:
|
||||||
|
|
||||||
case <-wm.stream.cw:
|
return http2errClientDisconnected
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if !scheduled && wm.done != nil {
|
|
||||||
select {
|
|
||||||
case wm.done <- http2errStreamBroken:
|
|
||||||
default:
|
|
||||||
panic("expected buffered channel")
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2421,7 +2435,6 @@ func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
|
||||||
if sc.writingFrame {
|
if sc.writingFrame {
|
||||||
panic("internal error: can only be writing one frame at a time")
|
panic("internal error: can only be writing one frame at a time")
|
||||||
}
|
}
|
||||||
sc.writingFrame = true
|
|
||||||
|
|
||||||
st := wm.stream
|
st := wm.stream
|
||||||
if st != nil {
|
if st != nil {
|
||||||
|
|
@ -2431,15 +2444,42 @@ func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
|
||||||
case http2stateClosed:
|
case http2stateClosed:
|
||||||
if st.sentReset || st.gotReset {
|
if st.sentReset || st.gotReset {
|
||||||
|
|
||||||
sc.wroteFrameCh <- struct{}{}
|
sc.scheduleFrameWrite()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wm))
|
panic(fmt.Sprintf("internal error: attempt to send a write %v on a closed stream", wm))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
sc.writingFrame = true
|
||||||
sc.needsFrameFlush = true
|
sc.needsFrameFlush = true
|
||||||
if http2endsStream(wm.write) {
|
go sc.writeFrameAsync(wm)
|
||||||
|
}
|
||||||
|
|
||||||
|
// wroteFrame is called on the serve goroutine with the result of
|
||||||
|
// whatever happened on writeFrameAsync.
|
||||||
|
func (sc *http2serverConn) wroteFrame(res http2frameWriteResult) {
|
||||||
|
sc.serveG.check()
|
||||||
|
if !sc.writingFrame {
|
||||||
|
panic("internal error: expected to be already writing a frame")
|
||||||
|
}
|
||||||
|
sc.writingFrame = false
|
||||||
|
|
||||||
|
wm := res.wm
|
||||||
|
st := wm.stream
|
||||||
|
|
||||||
|
closeStream := http2endsStream(wm.write)
|
||||||
|
|
||||||
|
if ch := wm.done; ch != nil {
|
||||||
|
select {
|
||||||
|
case ch <- res.err:
|
||||||
|
default:
|
||||||
|
panic(fmt.Sprintf("unbuffered done channel passed in for type %T", wm.write))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wm.write = nil
|
||||||
|
|
||||||
|
if closeStream {
|
||||||
if st == nil {
|
if st == nil {
|
||||||
panic("internal error: expecting non-nil stream")
|
panic("internal error: expecting non-nil stream")
|
||||||
}
|
}
|
||||||
|
|
@ -2453,7 +2493,8 @@ func (sc *http2serverConn) startFrameWrite(wm http2frameWriteMsg) {
|
||||||
sc.closeStream(st, nil)
|
sc.closeStream(st, nil)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
go sc.writeFrameAsync(wm)
|
|
||||||
|
sc.scheduleFrameWrite()
|
||||||
}
|
}
|
||||||
|
|
||||||
// scheduleFrameWrite tickles the frame writing scheduler.
|
// scheduleFrameWrite tickles the frame writing scheduler.
|
||||||
|
|
@ -2692,6 +2733,9 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
|
||||||
}
|
}
|
||||||
st.state = http2stateClosed
|
st.state = http2stateClosed
|
||||||
sc.curOpenStreams--
|
sc.curOpenStreams--
|
||||||
|
if sc.curOpenStreams == 0 {
|
||||||
|
sc.setConnState(StateIdle)
|
||||||
|
}
|
||||||
delete(sc.streams, st.id)
|
delete(sc.streams, st.id)
|
||||||
if p := st.body; p != nil {
|
if p := st.body; p != nil {
|
||||||
p.Close(err)
|
p.Close(err)
|
||||||
|
|
@ -2838,6 +2882,9 @@ func (sc *http2serverConn) processHeaders(f *http2HeadersFrame) error {
|
||||||
http2adjustStreamPriority(sc.streams, st.id, f.Priority)
|
http2adjustStreamPriority(sc.streams, st.id, f.Priority)
|
||||||
}
|
}
|
||||||
sc.curOpenStreams++
|
sc.curOpenStreams++
|
||||||
|
if sc.curOpenStreams == 1 {
|
||||||
|
sc.setConnState(StateActive)
|
||||||
|
}
|
||||||
sc.req = http2requestParam{
|
sc.req = http2requestParam{
|
||||||
stream: st,
|
stream: st,
|
||||||
header: make(Header),
|
header: make(Header),
|
||||||
|
|
@ -3031,29 +3078,32 @@ func http2handleHeaderListTooLong(w ResponseWriter, r *Request) {
|
||||||
|
|
||||||
// called from handler goroutines.
|
// called from handler goroutines.
|
||||||
// h may be nil.
|
// h may be nil.
|
||||||
func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeResHeaders) {
|
func (sc *http2serverConn) writeHeaders(st *http2stream, headerData *http2writeResHeaders) error {
|
||||||
sc.serveG.checkNotOn()
|
sc.serveG.checkNotOn()
|
||||||
var errc chan error
|
var errc chan error
|
||||||
if headerData.h != nil {
|
if headerData.h != nil {
|
||||||
|
|
||||||
errc = http2errChanPool.Get().(chan error)
|
errc = http2errChanPool.Get().(chan error)
|
||||||
}
|
}
|
||||||
sc.writeFrameFromHandler(http2frameWriteMsg{
|
if err := sc.writeFrameFromHandler(http2frameWriteMsg{
|
||||||
write: headerData,
|
write: headerData,
|
||||||
stream: st,
|
stream: st,
|
||||||
done: errc,
|
done: errc,
|
||||||
})
|
}); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
if errc != nil {
|
if errc != nil {
|
||||||
select {
|
select {
|
||||||
case <-errc:
|
case err := <-errc:
|
||||||
|
|
||||||
http2errChanPool.Put(errc)
|
http2errChanPool.Put(errc)
|
||||||
|
return err
|
||||||
case <-sc.doneServing:
|
case <-sc.doneServing:
|
||||||
|
return http2errClientDisconnected
|
||||||
case <-st.cw:
|
case <-st.cw:
|
||||||
|
return http2errStreamClosed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// called from handler goroutines.
|
// called from handler goroutines.
|
||||||
|
|
@ -3227,7 +3277,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||||
ctype = DetectContentType(p)
|
ctype = DetectContentType(p)
|
||||||
}
|
}
|
||||||
endStream := rws.handlerDone && len(p) == 0
|
endStream := rws.handlerDone && len(p) == 0
|
||||||
rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{
|
err = rws.conn.writeHeaders(rws.stream, &http2writeResHeaders{
|
||||||
streamID: rws.stream.id,
|
streamID: rws.stream.id,
|
||||||
httpResCode: rws.status,
|
httpResCode: rws.status,
|
||||||
h: rws.snapHeader,
|
h: rws.snapHeader,
|
||||||
|
|
@ -3235,6 +3285,9 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||||
contentType: ctype,
|
contentType: ctype,
|
||||||
contentLength: clen,
|
contentLength: clen,
|
||||||
})
|
})
|
||||||
|
if err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
if endStream {
|
if endStream {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
@ -3242,6 +3295,7 @@ func (rws *http2responseWriterState) writeChunk(p []byte) (n int, err error) {
|
||||||
if len(p) == 0 && !rws.handlerDone {
|
if len(p) == 0 && !rws.handlerDone {
|
||||||
return 0, nil
|
return 0, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
curWrite := &rws.curWrite
|
curWrite := &rws.curWrite
|
||||||
curWrite.streamID = rws.stream.id
|
curWrite.streamID = rws.stream.id
|
||||||
curWrite.p = p
|
curWrite.p = p
|
||||||
|
|
@ -3603,7 +3657,7 @@ func (t *http2Transport) newClientConn(host, port, key string) (*http2clientConn
|
||||||
cc.initialWindowSize = s.Val
|
cc.initialWindowSize = s.Val
|
||||||
default:
|
default:
|
||||||
|
|
||||||
log.Printf("Unhandled Setting: %v", s)
|
t.vlogf("Unhandled Setting: %v", s)
|
||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
|
|
@ -3727,7 +3781,6 @@ func (cc *http2clientConn) encodeHeaders(req *Request) []byte {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (cc *http2clientConn) writeHeader(name, value string) {
|
func (cc *http2clientConn) writeHeader(name, value string) {
|
||||||
log.Printf("sending %q = %q", name, value)
|
|
||||||
cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
|
cc.henc.WriteField(hpack.HeaderField{Name: name, Value: value})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3784,20 +3837,20 @@ func (cc *http2clientConn) readLoop() {
|
||||||
cc.readerErr = err
|
cc.readerErr = err
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
log.Printf("Transport received %v: %#v", f.Header(), f)
|
cc.vlogf("Transport received %v: %#v", f.Header(), f)
|
||||||
|
|
||||||
streamID := f.Header().StreamID
|
streamID := f.Header().StreamID
|
||||||
|
|
||||||
_, isContinue := f.(*http2ContinuationFrame)
|
_, isContinue := f.(*http2ContinuationFrame)
|
||||||
if isContinue {
|
if isContinue {
|
||||||
if streamID != continueStreamID {
|
if streamID != continueStreamID {
|
||||||
log.Printf("Protocol violation: got CONTINUATION with id %d; want %d", streamID, continueStreamID)
|
cc.logf("Protocol violation: got CONTINUATION with id %d; want %d", streamID, continueStreamID)
|
||||||
cc.readerErr = http2ConnectionError(http2ErrCodeProtocol)
|
cc.readerErr = http2ConnectionError(http2ErrCodeProtocol)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
} else if continueStreamID != 0 {
|
} else if continueStreamID != 0 {
|
||||||
|
|
||||||
log.Printf("Protocol violation: got %T for stream %d, want CONTINUATION for %d", f, streamID, continueStreamID)
|
cc.logf("Protocol violation: got %T for stream %d, want CONTINUATION for %d", f, streamID, continueStreamID)
|
||||||
cc.readerErr = http2ConnectionError(http2ErrCodeProtocol)
|
cc.readerErr = http2ConnectionError(http2ErrCodeProtocol)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -3813,7 +3866,7 @@ func (cc *http2clientConn) readLoop() {
|
||||||
|
|
||||||
cs := cc.streamByID(streamID, streamEnded)
|
cs := cc.streamByID(streamID, streamEnded)
|
||||||
if cs == nil {
|
if cs == nil {
|
||||||
log.Printf("Received frame for untracked stream ID %d", streamID)
|
cc.logf("Received frame for untracked stream ID %d", streamID)
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3829,17 +3882,19 @@ func (cc *http2clientConn) readLoop() {
|
||||||
case *http2ContinuationFrame:
|
case *http2ContinuationFrame:
|
||||||
cc.hdec.Write(f.HeaderBlockFragment())
|
cc.hdec.Write(f.HeaderBlockFragment())
|
||||||
case *http2DataFrame:
|
case *http2DataFrame:
|
||||||
log.Printf("DATA: %q", f.Data())
|
if http2VerboseLogs {
|
||||||
|
cc.logf("DATA: %q", f.Data())
|
||||||
|
}
|
||||||
cs.pw.Write(f.Data())
|
cs.pw.Write(f.Data())
|
||||||
case *http2GoAwayFrame:
|
case *http2GoAwayFrame:
|
||||||
cc.t.removeClientConn(cc)
|
cc.t.removeClientConn(cc)
|
||||||
if f.ErrCode != 0 {
|
if f.ErrCode != 0 {
|
||||||
|
|
||||||
log.Printf("transport got GOAWAY with error code = %v", f.ErrCode)
|
cc.vlogf("transport got GOAWAY with error code = %v", f.ErrCode)
|
||||||
}
|
}
|
||||||
cc.setGoAway(f)
|
cc.setGoAway(f)
|
||||||
default:
|
default:
|
||||||
log.Printf("Transport: unhandled response frame type %T", f)
|
cc.logf("Transport: unhandled response frame type %T", f)
|
||||||
}
|
}
|
||||||
headersEnded := false
|
headersEnded := false
|
||||||
if he, ok := f.(http2headersEnder); ok {
|
if he, ok := f.(http2headersEnder); ok {
|
||||||
|
|
@ -3870,7 +3925,9 @@ func (cc *http2clientConn) readLoop() {
|
||||||
|
|
||||||
func (cc *http2clientConn) onNewHeaderField(f hpack.HeaderField) {
|
func (cc *http2clientConn) onNewHeaderField(f hpack.HeaderField) {
|
||||||
|
|
||||||
log.Printf("Header field: %+v", f)
|
if http2VerboseLogs {
|
||||||
|
cc.logf("Header field: %+v", f)
|
||||||
|
}
|
||||||
if f.Name == ":status" {
|
if f.Name == ":status" {
|
||||||
code, err := strconv.Atoi(f.Value)
|
code, err := strconv.Atoi(f.Value)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -3887,6 +3944,24 @@ func (cc *http2clientConn) onNewHeaderField(f hpack.HeaderField) {
|
||||||
cc.nextRes.Header.Add(CanonicalHeaderKey(f.Name), f.Value)
|
cc.nextRes.Header.Add(CanonicalHeaderKey(f.Name), f.Value)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (cc *http2clientConn) logf(format string, args ...interface{}) {
|
||||||
|
cc.t.logf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (cc *http2clientConn) vlogf(format string, args ...interface{}) {
|
||||||
|
cc.t.vlogf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *http2Transport) vlogf(format string, args ...interface{}) {
|
||||||
|
if http2VerboseLogs {
|
||||||
|
t.logf(format, args...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (t *http2Transport) logf(format string, args ...interface{}) {
|
||||||
|
log.Printf(format, args...)
|
||||||
|
}
|
||||||
|
|
||||||
// writeFramer is implemented by any type that is used to write frames.
|
// writeFramer is implemented by any type that is used to write frames.
|
||||||
type http2writeFramer interface {
|
type http2writeFramer interface {
|
||||||
writeFrame(http2writeContext) error
|
writeFrame(http2writeContext) error
|
||||||
|
|
@ -3915,6 +3990,9 @@ func http2endsStream(w http2writeFramer) bool {
|
||||||
return v.endStream
|
return v.endStream
|
||||||
case *http2writeResHeaders:
|
case *http2writeResHeaders:
|
||||||
return v.endStream
|
return v.endStream
|
||||||
|
case nil:
|
||||||
|
|
||||||
|
panic("endsStream called on nil writeFramer")
|
||||||
}
|
}
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -282,6 +282,11 @@ func (d *Decoder) Write(p []byte) (n int, err error) {
|
||||||
for len(d.buf) > 0 {
|
for len(d.buf) > 0 {
|
||||||
err = d.parseHeaderFieldRepr()
|
err = d.parseHeaderFieldRepr()
|
||||||
if err == errNeedMore {
|
if err == errNeedMore {
|
||||||
|
// Extra paranoia, making sure saveBuf won't
|
||||||
|
// get too large. All the varint and string
|
||||||
|
// reading code earlier should already catch
|
||||||
|
// overlong things and return ErrStringLength,
|
||||||
|
// but keep this as a last resort.
|
||||||
const varIntOverhead = 8 // conservative
|
const varIntOverhead = 8 // conservative
|
||||||
if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
|
if d.maxStrLen != 0 && int64(len(d.buf)) > 2*(int64(d.maxStrLen)+varIntOverhead) {
|
||||||
return 0, ErrStringLength
|
return 0, ErrStringLength
|
||||||
|
|
@ -503,6 +508,7 @@ func (d *Decoder) readString(p []byte, wantStr bool) (s string, remain []byte, e
|
||||||
buf.Reset() // don't trust others
|
buf.Reset() // don't trust others
|
||||||
defer bufPool.Put(buf)
|
defer bufPool.Put(buf)
|
||||||
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
if err := huffmanDecode(buf, d.maxStrLen, p[:strLen]); err != nil {
|
||||||
|
buf.Reset()
|
||||||
return "", nil, err
|
return "", nil, err
|
||||||
}
|
}
|
||||||
s = buf.String()
|
s = buf.String()
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue