Commit bb00a8d9 authored by Brad Fitzpatrick's avatar Brad Fitzpatrick

net/http: update bundled http2, add TestServerKeepAlivesEnabled h1/h2 tests

Updates x/net/http2 to x/net git rev 6dfeb344 for:

   http2: make Server respect http1 Server's SetKeepAlivesEnabled
   https://golang.org/cl/33153

And adds a test in std.

Fixes #17717

Change-Id: I3ba000abb6f3f682261e105d8a4bb93bde6609fe
Reviewed-on: https://go-review.googlesource.com/33231
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarTom Bergan <tombergan@google.com>
parent b83350a2
...@@ -44,6 +44,19 @@ func (t *clientServerTest) close() { ...@@ -44,6 +44,19 @@ func (t *clientServerTest) close() {
t.ts.Close() t.ts.Close()
} }
func (t *clientServerTest) getURL(u string) string {
res, err := t.c.Get(u)
if err != nil {
t.t.Fatal(err)
}
defer res.Body.Close()
slurp, err := ioutil.ReadAll(res.Body)
if err != nil {
t.t.Fatal(err)
}
return string(slurp)
}
func (t *clientServerTest) scheme() string { func (t *clientServerTest) scheme() string {
if t.h2 { if t.h2 {
return "https" return "https"
......
...@@ -3549,7 +3549,7 @@ func (sc *http2serverConn) serve() { ...@@ -3549,7 +3549,7 @@ func (sc *http2serverConn) serve() {
return return
case <-gracefulShutdownCh: case <-gracefulShutdownCh:
gracefulShutdownCh = nil gracefulShutdownCh = nil
sc.goAwayIn(http2ErrCodeNo, 0) sc.startGracefulShutdown()
case <-sc.shutdownTimerCh: case <-sc.shutdownTimerCh:
sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr()) sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
return return
...@@ -3834,6 +3834,13 @@ func (sc *http2serverConn) scheduleFrameWrite() { ...@@ -3834,6 +3834,13 @@ func (sc *http2serverConn) scheduleFrameWrite() {
sc.inFrameScheduleLoop = false sc.inFrameScheduleLoop = false
} }
// startGracefulShutdown sends a GOAWAY with ErrCodeNo to tell the
// client we're gracefully shutting down. The connection isn't closed
// until all current streams are done.
func (sc *http2serverConn) startGracefulShutdown() {
sc.goAwayIn(http2ErrCodeNo, 0)
}
func (sc *http2serverConn) goAway(code http2ErrCode) { func (sc *http2serverConn) goAway(code http2ErrCode) {
sc.serveG.check() sc.serveG.check()
var forceCloseIn time.Duration var forceCloseIn time.Duration
...@@ -4028,12 +4035,15 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) { ...@@ -4028,12 +4035,15 @@ func (sc *http2serverConn) closeStream(st *http2stream, err error) {
} else { } else {
sc.curClientStreams-- sc.curClientStreams--
} }
if sc.curClientStreams+sc.curPushedStreams == 0 {
sc.setConnState(StateIdle)
}
delete(sc.streams, st.id) delete(sc.streams, st.id)
if len(sc.streams) == 0 && sc.srv.IdleTimeout != 0 { if len(sc.streams) == 0 {
sc.idleTimer.Reset(sc.srv.IdleTimeout) sc.setConnState(StateIdle)
if sc.srv.IdleTimeout != 0 {
sc.idleTimer.Reset(sc.srv.IdleTimeout)
}
if http2h1ServerKeepAlivesDisabled(sc.hs) {
sc.startGracefulShutdown()
}
} }
if p := st.body; p != nil { if p := st.body; p != nil {
...@@ -4177,7 +4187,7 @@ func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error { ...@@ -4177,7 +4187,7 @@ func (sc *http2serverConn) processGoAway(f *http2GoAwayFrame) error {
} else { } else {
sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f) sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
} }
sc.goAwayIn(http2ErrCodeNo, 0) sc.startGracefulShutdown()
sc.pushEnabled = false sc.pushEnabled = false
return nil return nil
...@@ -5181,7 +5191,7 @@ func (sc *http2serverConn) startPush(msg http2startPushRequest) { ...@@ -5181,7 +5191,7 @@ func (sc *http2serverConn) startPush(msg http2startPushRequest) {
} }
if sc.maxPushPromiseID+2 >= 1<<31 { if sc.maxPushPromiseID+2 >= 1<<31 {
sc.goAwayIn(http2ErrCodeNo, 0) sc.startGracefulShutdown()
return 0, http2ErrPushLimitReached return 0, http2ErrPushLimitReached
} }
sc.maxPushPromiseID += 2 sc.maxPushPromiseID += 2
...@@ -5326,6 +5336,20 @@ func http2h1ServerShutdownChan(hs *Server) <-chan struct{} { ...@@ -5326,6 +5336,20 @@ func http2h1ServerShutdownChan(hs *Server) <-chan struct{} {
// optional test hook for h1ServerShutdownChan. // optional test hook for h1ServerShutdownChan.
var http2testh1ServerShutdownChan func(hs *Server) <-chan struct{} var http2testh1ServerShutdownChan func(hs *Server) <-chan struct{}
// h1ServerKeepAlivesDisabled reports whether hs has its keep-alives
// disabled. See comments on h1ServerShutdownChan above for why
// the code is written this way.
func http2h1ServerKeepAlivesDisabled(hs *Server) bool {
var x interface{} = hs
type I interface {
doKeepAlives() bool
}
if hs, ok := x.(I); ok {
return !hs.doKeepAlives()
}
return false
}
const ( const (
// transportDefaultConnFlow is how many connection-level flow control // transportDefaultConnFlow is how many connection-level flow control
// tokens we give the server at start-up, past the default 64k. // tokens we give the server at start-up, past the default 64k.
......
...@@ -4992,3 +4992,29 @@ func TestServerCloseDeadlock(t *testing.T) { ...@@ -4992,3 +4992,29 @@ func TestServerCloseDeadlock(t *testing.T) {
s.Close() s.Close()
s.Close() s.Close()
} }
// Issue 17717: tests that Server.SetKeepAlivesEnabled is respected by
// both HTTP/1 and HTTP/2.
func TestServerKeepAlivesEnabled_h1(t *testing.T) { testServerKeepAlivesEnabled(t, h1Mode) }
func TestServerKeepAlivesEnabled_h2(t *testing.T) { testServerKeepAlivesEnabled(t, h2Mode) }
func testServerKeepAlivesEnabled(t *testing.T, h2 bool) {
setParallel(t)
defer afterTest(t)
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
fmt.Fprintf(w, "%v", r.RemoteAddr)
}))
defer cst.close()
srv := cst.ts.Config
srv.SetKeepAlivesEnabled(false)
a := cst.getURL(cst.ts.URL)
if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
t.Fatalf("test server has active conns")
}
b := cst.getURL(cst.ts.URL)
if a == b {
t.Errorf("got same connection between first and second requests")
}
if !waitCondition(2*time.Second, 10*time.Millisecond, srv.ExportAllConnsIdle) {
t.Fatalf("test server has active conns")
}
}
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