Skip to content

Commit 53fc330

Browse files
committed
net/http: add Server.Close & Server.Shutdown for forced & graceful shutdown
Also updates x/net/http2 to git rev 541150 for: http2: add support for graceful shutdown of Server https://golang.org/cl/32412 http2: make http2.Server access http1's Server via an interface check https://golang.org/cl/32417 Fixes #4674 Fixes #9478 Change-Id: I8021a18dee0ef2fe3946ac1776d2b10d3d429052 Reviewed-on: https://go-review.googlesource.com/32329 Run-TryBot: Brad Fitzpatrick <[email protected]> Reviewed-by: Brad Fitzpatrick <[email protected]>
1 parent 2d4d22a commit 53fc330

File tree

5 files changed

+352
-15
lines changed

5 files changed

+352
-15
lines changed

src/net/http/export_test.go

+6
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,12 @@ func (t *Transport) IdleConnKeysForTesting() (keys []string) {
8787
return
8888
}
8989

90+
func (t *Transport) IdleConnKeyCountForTesting() int {
91+
t.idleMu.Lock()
92+
defer t.idleMu.Unlock()
93+
return len(t.idleConn)
94+
}
95+
9096
func (t *Transport) IdleConnStrsForTesting() []string {
9197
var ret []string
9298
t.idleMu.Lock()

src/net/http/h2_bundle.go

+52-10
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/net/http/http_test.go

+5
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,13 @@ import (
1212
"os/exec"
1313
"reflect"
1414
"testing"
15+
"time"
1516
)
1617

18+
func init() {
19+
shutdownPollInterval = 5 * time.Millisecond
20+
}
21+
1722
func TestForeachHeaderElement(t *testing.T) {
1823
tests := []struct {
1924
in string

src/net/http/serve_test.go

+93
Original file line numberDiff line numberDiff line change
@@ -4832,3 +4832,96 @@ func TestServerIdleTimeout(t *testing.T) {
48324832
t.Fatal("copy byte succeeded; want err")
48334833
}
48344834
}
4835+
4836+
func get(t *testing.T, c *Client, url string) string {
4837+
res, err := c.Get(url)
4838+
if err != nil {
4839+
t.Fatal(err)
4840+
}
4841+
defer res.Body.Close()
4842+
slurp, err := ioutil.ReadAll(res.Body)
4843+
if err != nil {
4844+
t.Fatal(err)
4845+
}
4846+
return string(slurp)
4847+
}
4848+
4849+
// Tests that calls to Server.SetKeepAlivesEnabled(false) closes any
4850+
// currently-open connections.
4851+
func TestServerSetKeepAlivesEnabledClosesConns(t *testing.T) {
4852+
if runtime.GOOS == "nacl" {
4853+
t.Skip("skipping on nacl; see golang.org/issue/17695")
4854+
}
4855+
defer afterTest(t)
4856+
ts := httptest.NewServer(HandlerFunc(func(w ResponseWriter, r *Request) {
4857+
io.WriteString(w, r.RemoteAddr)
4858+
}))
4859+
defer ts.Close()
4860+
4861+
tr := &Transport{}
4862+
defer tr.CloseIdleConnections()
4863+
c := &Client{Transport: tr}
4864+
4865+
get := func() string { return get(t, c, ts.URL) }
4866+
4867+
a1, a2 := get(), get()
4868+
if a1 != a2 {
4869+
t.Fatal("expected first two requests on same connection")
4870+
}
4871+
var idle0 int
4872+
if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
4873+
idle0 = tr.IdleConnKeyCountForTesting()
4874+
return idle0 == 1
4875+
}) {
4876+
t.Fatalf("idle count before SetKeepAlivesEnabled called = %v; want 1", idle0)
4877+
}
4878+
4879+
ts.Config.SetKeepAlivesEnabled(false)
4880+
4881+
var idle1 int
4882+
if !waitCondition(2*time.Second, 10*time.Millisecond, func() bool {
4883+
idle1 = tr.IdleConnKeyCountForTesting()
4884+
return idle1 == 0
4885+
}) {
4886+
t.Fatalf("idle count after SetKeepAlivesEnabled called = %v; want 0", idle1)
4887+
}
4888+
4889+
a3 := get()
4890+
if a3 == a2 {
4891+
t.Fatal("expected third request on new connection")
4892+
}
4893+
}
4894+
4895+
func TestServerShutdown_h1(t *testing.T) { testServerShutdown(t, h1Mode) }
4896+
func TestServerShutdown_h2(t *testing.T) { testServerShutdown(t, h2Mode) }
4897+
4898+
func testServerShutdown(t *testing.T, h2 bool) {
4899+
defer afterTest(t)
4900+
var doShutdown func() // set later
4901+
var shutdownRes = make(chan error, 1)
4902+
cst := newClientServerTest(t, h2, HandlerFunc(func(w ResponseWriter, r *Request) {
4903+
go doShutdown()
4904+
// Shutdown is graceful, so it should not interrupt
4905+
// this in-flight response. Add a tiny sleep here to
4906+
// increase the odds of a failure if shutdown has
4907+
// bugs.
4908+
time.Sleep(20 * time.Millisecond)
4909+
io.WriteString(w, r.RemoteAddr)
4910+
}))
4911+
defer cst.close()
4912+
4913+
doShutdown = func() {
4914+
shutdownRes <- cst.ts.Config.Shutdown(context.Background())
4915+
}
4916+
get(t, cst.c, cst.ts.URL) // calls t.Fail on failure
4917+
4918+
if err := <-shutdownRes; err != nil {
4919+
t.Fatalf("Shutdown: %v", err)
4920+
}
4921+
4922+
res, err := cst.c.Get(cst.ts.URL)
4923+
if err == nil {
4924+
res.Body.Close()
4925+
t.Fatal("second request should fail. server should be shut down")
4926+
}
4927+
}

0 commit comments

Comments
 (0)