Skip to content

Commit

Permalink
http2: make Server respect http1 Server's SetKeepAlivesEnabled
Browse files Browse the repository at this point in the history
If the user is using Server.SetKeepAlivesEnabled(false), assume they
have a reason and respect it. Make HTTP/2 behave like HTTP/1 (except a
bit nicer, since we have GOAWAY).

Updates golang/go#17717

Change-Id: I4a5ce324f0ac8653d83e75029063cd2e270a1048
Reviewed-on: https://go-review.googlesource.com/33153
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
  • Loading branch information
bradfitz committed Nov 14, 2016
1 parent 8566e93 commit 6dfeb34
Showing 1 changed file with 32 additions and 8 deletions.
40 changes: 32 additions & 8 deletions http2/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ func (sc *serverConn) serve() {
return
case <-gracefulShutdownCh:
gracefulShutdownCh = nil
sc.goAwayIn(ErrCodeNo, 0)
sc.startGracefulShutdown()
case <-sc.shutdownTimerCh:
sc.vlogf("GOAWAY close timer fired; closing conn from %v", sc.conn.RemoteAddr())
return
Expand Down Expand Up @@ -1044,6 +1044,13 @@ func (sc *serverConn) scheduleFrameWrite() {
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 *serverConn) startGracefulShutdown() {
sc.goAwayIn(ErrCodeNo, 0)
}

func (sc *serverConn) goAway(code ErrCode) {
sc.serveG.check()
var forceCloseIn time.Duration
Expand Down Expand Up @@ -1263,12 +1270,15 @@ func (sc *serverConn) closeStream(st *stream, err error) {
} else {
sc.curClientStreams--
}
if sc.curClientStreams+sc.curPushedStreams == 0 {
sc.setConnState(http.StateIdle)
}
delete(sc.streams, st.id)
if len(sc.streams) == 0 && sc.srv.IdleTimeout != 0 {
sc.idleTimer.Reset(sc.srv.IdleTimeout)
if len(sc.streams) == 0 {
sc.setConnState(http.StateIdle)
if sc.srv.IdleTimeout != 0 {
sc.idleTimer.Reset(sc.srv.IdleTimeout)
}
if h1ServerKeepAlivesDisabled(sc.hs) {
sc.startGracefulShutdown()
}
}
if p := st.body; p != nil {
// Return any buffered unread bytes worth of conn-level flow control.
Expand Down Expand Up @@ -1450,7 +1460,7 @@ func (sc *serverConn) processGoAway(f *GoAwayFrame) error {
} else {
sc.vlogf("http2: received GOAWAY %+v, starting graceful shutdown", f)
}
sc.goAwayIn(ErrCodeNo, 0)
sc.startGracefulShutdown()
// http://tools.ietf.org/html/rfc7540#section-6.8
// We should not create any new streams, which means we should disable push.
sc.pushEnabled = false
Expand Down Expand Up @@ -2529,7 +2539,7 @@ func (sc *serverConn) startPush(msg startPushRequest) {
// A server that is unable to establish a new stream identifier can send a GOAWAY
// frame so that the client is forced to open a new connection for new streams.
if sc.maxPushPromiseID+2 >= 1<<31 {
sc.goAwayIn(ErrCodeNo, 0)
sc.startGracefulShutdown()
return 0, ErrPushLimitReached
}
sc.maxPushPromiseID += 2
Expand Down Expand Up @@ -2678,3 +2688,17 @@ func h1ServerShutdownChan(hs *http.Server) <-chan struct{} {

// optional test hook for h1ServerShutdownChan.
var testh1ServerShutdownChan func(hs *http.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 h1ServerKeepAlivesDisabled(hs *http.Server) bool {
var x interface{} = hs
type I interface {
doKeepAlives() bool
}
if hs, ok := x.(I); ok {
return !hs.doKeepAlives()
}
return false
}

0 comments on commit 6dfeb34

Please sign in to comment.