From 5c6e88804f7eecb6a2fb9db7ebc26abad3fd585a Mon Sep 17 00:00:00 2001 From: Andy Goldstein Date: Mon, 2 Mar 2015 12:10:14 -0500 Subject: [PATCH] bump(docker/spdystream):e9bf9912b85eec0ed6aaf317808a0eab25e3ca43 Fixes #4912 --- Godeps/Godeps.json | 2 +- .../docker/spdystream/connection.go | 16 ++-- .../github.com/docker/spdystream/spdy_test.go | 81 +++++++++++++++++++ .../github.com/docker/spdystream/stream.go | 3 + 4 files changed, 96 insertions(+), 6 deletions(-) diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index c041d87dc7760..4f78a3b3d8149 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -114,7 +114,7 @@ }, { "ImportPath": "github.com/docker/spdystream", - "Rev": "29e1da2890f60336f98d0b3bf28b05070aa2ee4d" + "Rev": "e9bf9912b85eec0ed6aaf317808a0eab25e3ca43" }, { "ImportPath": "github.com/elazarl/go-bindata-assetfs", diff --git a/Godeps/_workspace/src/github.com/docker/spdystream/connection.go b/Godeps/_workspace/src/github.com/docker/spdystream/connection.go index 3f937e4cb2357..58261b2e0bc66 100644 --- a/Godeps/_workspace/src/github.com/docker/spdystream/connection.go +++ b/Godeps/_workspace/src/github.com/docker/spdystream/connection.go @@ -72,11 +72,17 @@ Loop: timer.Reset(i.timeout) } case <-expired: - for _, stream := range i.conn.streams { - stream.Reset() - } - i.conn.Close() - break Loop + i.conn.streamCond.L.Lock() + streams := i.conn.streams + i.conn.streams = make(map[spdy.StreamId]*Stream) + i.conn.streamCond.Broadcast() + i.conn.streamCond.L.Unlock() + go func() { + for _, stream := range streams { + stream.resetStream() + } + i.conn.Close() + }() case <-i.conn.closeChan: if timer != nil { timer.Stop() diff --git a/Godeps/_workspace/src/github.com/docker/spdystream/spdy_test.go b/Godeps/_workspace/src/github.com/docker/spdystream/spdy_test.go index 715654d4a5091..a9f28224aaf79 100644 --- a/Godeps/_workspace/src/github.com/docker/spdystream/spdy_test.go +++ b/Godeps/_workspace/src/github.com/docker/spdystream/spdy_test.go @@ -396,6 +396,49 @@ func TestCloseNotification(t *testing.T) { } } +func TestIdleShutdownRace(t *testing.T) { + var wg sync.WaitGroup + server, listen, serverErr := runServer(&wg) + if serverErr != nil { + t.Fatalf("Error initializing server: %s", serverErr) + } + + conn, dialErr := net.Dial("tcp", listen) + if dialErr != nil { + t.Fatalf("Error dialing server: %s", dialErr) + } + + spdyConn, spdyErr := NewConnection(conn, false) + if spdyErr != nil { + t.Fatalf("Error creating spdy connection: %s", spdyErr) + } + go spdyConn.Serve(NoOpStreamHandler) + + authenticated = true + stream, err := spdyConn.CreateStream(http.Header{}, nil, false) + if err != nil { + t.Fatalf("Error creating stream: %v", err) + } + + spdyConn.SetIdleTimeout(5 * time.Millisecond) + go func() { + time.Sleep(5 * time.Millisecond) + stream.Reset() + }() + + select { + case <-spdyConn.CloseChan(): + case <-time.After(20 * time.Millisecond): + t.Fatal("Timed out waiting for idle connection closure") + } + + closeErr := server.Close() + if closeErr != nil { + t.Fatalf("Error shutting down server: %s", closeErr) + } + wg.Wait() +} + func TestIdleNoTimeoutSet(t *testing.T) { var wg sync.WaitGroup server, listen, serverErr := runServer(&wg) @@ -558,6 +601,44 @@ Loop: wg.Wait() } +func TestIdleRace(t *testing.T) { + var wg sync.WaitGroup + server, listen, serverErr := runServer(&wg) + if serverErr != nil { + t.Fatalf("Error initializing server: %s", serverErr) + } + + conn, dialErr := net.Dial("tcp", listen) + if dialErr != nil { + t.Fatalf("Error dialing server: %s", dialErr) + } + + spdyConn, spdyErr := NewConnection(conn, false) + if spdyErr != nil { + t.Fatalf("Error creating spdy connection: %s", spdyErr) + } + go spdyConn.Serve(NoOpStreamHandler) + + spdyConn.SetIdleTimeout(10 * time.Millisecond) + + authenticated = true + + for i := 0; i < 10; i++ { + _, err := spdyConn.CreateStream(http.Header{}, nil, false) + if err != nil { + t.Fatalf("Error creating stream: %v", err) + } + } + + <-spdyConn.CloseChan() + + closeErr := server.Close() + if closeErr != nil { + t.Fatalf("Error shutting down server: %s", closeErr) + } + wg.Wait() +} + func TestHalfClosedIdleTimeout(t *testing.T) { listener, listenErr := net.Listen("tcp", "localhost:0") if listenErr != nil { diff --git a/Godeps/_workspace/src/github.com/docker/spdystream/stream.go b/Godeps/_workspace/src/github.com/docker/spdystream/stream.go index 8ad700ed8a4b6..1c5f79ae14033 100644 --- a/Godeps/_workspace/src/github.com/docker/spdystream/stream.go +++ b/Godeps/_workspace/src/github.com/docker/spdystream/stream.go @@ -168,7 +168,10 @@ func (s *Stream) Close() error { // Reset sends a reset frame, putting the stream into the fully closed state. func (s *Stream) Reset() error { s.conn.removeStream(s) + return s.resetStream() +} +func (s *Stream) resetStream() error { s.finishLock.Lock() if s.finished { s.finishLock.Unlock()