@@ -154,6 +154,39 @@ type Server struct {
154154 // so that we don't embed a Mutex in this struct, which will make the
155155 // struct non-copyable, which might break some callers.
156156 state * serverInternalState
157+
158+ // Synchronization group used for testing.
159+ // Outside of tests, this is nil.
160+ group synctestGroupInterface
161+ }
162+
163+ func (s * Server ) markNewGoroutine () {
164+ if s .group != nil {
165+ s .group .Join ()
166+ }
167+ }
168+
169+ func (s * Server ) now () time.Time {
170+ if s .group != nil {
171+ return s .group .Now ()
172+ }
173+ return time .Now ()
174+ }
175+
176+ // newTimer creates a new time.Timer, or a synthetic timer in tests.
177+ func (s * Server ) newTimer (d time.Duration ) timer {
178+ if s .group != nil {
179+ return s .group .NewTimer (d )
180+ }
181+ return timeTimer {time .NewTimer (d )}
182+ }
183+
184+ // afterFunc creates a new time.AfterFunc timer, or a synthetic timer in tests.
185+ func (s * Server ) afterFunc (d time.Duration , f func ()) timer {
186+ if s .group != nil {
187+ return s .group .AfterFunc (d , f )
188+ }
189+ return timeTimer {time .AfterFunc (d , f )}
157190}
158191
159192func (s * Server ) initialConnRecvWindowSize () int32 {
@@ -400,6 +433,10 @@ func (o *ServeConnOpts) handler() http.Handler {
400433//
401434// The opts parameter is optional. If nil, default values are used.
402435func (s * Server ) ServeConn (c net.Conn , opts * ServeConnOpts ) {
436+ s .serveConn (c , opts , nil )
437+ }
438+
439+ func (s * Server ) serveConn (c net.Conn , opts * ServeConnOpts , newf func (* serverConn )) {
403440 baseCtx , cancel := serverConnBaseContext (c , opts )
404441 defer cancel ()
405442
@@ -426,6 +463,9 @@ func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
426463 pushEnabled : true ,
427464 sawClientPreface : opts .SawClientPreface ,
428465 }
466+ if newf != nil {
467+ newf (sc )
468+ }
429469
430470 s .state .registerConn (sc )
431471 defer s .state .unregisterConn (sc )
@@ -599,8 +639,8 @@ type serverConn struct {
599639 inFrameScheduleLoop bool // whether we're in the scheduleFrameWrite loop
600640 needToSendGoAway bool // we need to schedule a GOAWAY frame write
601641 goAwayCode ErrCode
602- shutdownTimer * time. Timer // nil until used
603- idleTimer * time. Timer // nil if unused
642+ shutdownTimer timer // nil until used
643+ idleTimer timer // nil if unused
604644
605645 // Owned by the writeFrameAsync goroutine:
606646 headerWriteBuf bytes.Buffer
@@ -649,12 +689,12 @@ type stream struct {
649689 flow outflow // limits writing from Handler to client
650690 inflow inflow // what the client is allowed to POST/etc to us
651691 state streamState
652- resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
653- gotTrailerHeader bool // HEADER frame for trailers was seen
654- wroteHeaders bool // whether we wrote headers (not status 100)
655- readDeadline * time. Timer // nil if unused
656- writeDeadline * time. Timer // nil if unused
657- closeErr error // set before cw is closed
692+ resetQueued bool // RST_STREAM queued for write; set by sc.resetStream
693+ gotTrailerHeader bool // HEADER frame for trailers was seen
694+ wroteHeaders bool // whether we wrote headers (not status 100)
695+ readDeadline timer // nil if unused
696+ writeDeadline timer // nil if unused
697+ closeErr error // set before cw is closed
658698
659699 trailer http.Header // accumulated trailers
660700 reqTrailer http.Header // handler's Request.Trailer
@@ -811,6 +851,7 @@ type readFrameResult struct {
811851// consumer is done with the frame.
812852// It's run on its own goroutine.
813853func (sc * serverConn ) readFrames () {
854+ sc .srv .markNewGoroutine ()
814855 gate := make (chan struct {})
815856 gateDone := func () { gate <- struct {}{} }
816857 for {
@@ -843,6 +884,7 @@ type frameWriteResult struct {
843884// At most one goroutine can be running writeFrameAsync at a time per
844885// serverConn.
845886func (sc * serverConn ) writeFrameAsync (wr FrameWriteRequest , wd * writeData ) {
887+ sc .srv .markNewGoroutine ()
846888 var err error
847889 if wd == nil {
848890 err = wr .write .writeFrame (sc )
@@ -922,13 +964,13 @@ func (sc *serverConn) serve() {
922964 sc .setConnState (http .StateIdle )
923965
924966 if sc .srv .IdleTimeout > 0 {
925- sc .idleTimer = time . AfterFunc (sc .srv .IdleTimeout , sc .onIdleTimer )
967+ sc .idleTimer = sc . srv . afterFunc (sc .srv .IdleTimeout , sc .onIdleTimer )
926968 defer sc .idleTimer .Stop ()
927969 }
928970
929971 go sc .readFrames () // closed by defer sc.conn.Close above
930972
931- settingsTimer := time . AfterFunc (firstSettingsTimeout , sc .onSettingsTimer )
973+ settingsTimer := sc . srv . afterFunc (firstSettingsTimeout , sc .onSettingsTimer )
932974 defer settingsTimer .Stop ()
933975
934976 loopNum := 0
@@ -1057,10 +1099,10 @@ func (sc *serverConn) readPreface() error {
10571099 errc <- nil
10581100 }
10591101 }()
1060- timer := time . NewTimer (prefaceTimeout ) // TODO: configurable on *Server?
1102+ timer := sc . srv . newTimer (prefaceTimeout ) // TODO: configurable on *Server?
10611103 defer timer .Stop ()
10621104 select {
1063- case <- timer .C :
1105+ case <- timer .C () :
10641106 return errPrefaceTimeout
10651107 case err := <- errc :
10661108 if err == nil {
@@ -1425,7 +1467,7 @@ func (sc *serverConn) goAway(code ErrCode) {
14251467
14261468func (sc * serverConn ) shutDownIn (d time.Duration ) {
14271469 sc .serveG .check ()
1428- sc .shutdownTimer = time . AfterFunc (d , sc .onShutdownTimer )
1470+ sc .shutdownTimer = sc . srv . afterFunc (d , sc .onShutdownTimer )
14291471}
14301472
14311473func (sc * serverConn ) resetStream (se StreamError ) {
@@ -2022,7 +2064,7 @@ func (sc *serverConn) processHeaders(f *MetaHeadersFrame) error {
20222064 // (in Go 1.8), though. That's a more sane option anyway.
20232065 if sc .hs .ReadTimeout > 0 {
20242066 sc .conn .SetReadDeadline (time.Time {})
2025- st .readDeadline = time . AfterFunc (sc .hs .ReadTimeout , st .onReadTimeout )
2067+ st .readDeadline = sc . srv . afterFunc (sc .hs .ReadTimeout , st .onReadTimeout )
20262068 }
20272069
20282070 return sc .scheduleHandler (id , rw , req , handler )
@@ -2120,7 +2162,7 @@ func (sc *serverConn) newStream(id, pusherID uint32, state streamState) *stream
21202162 st .flow .add (sc .initialStreamSendWindowSize )
21212163 st .inflow .init (sc .srv .initialStreamRecvWindowSize ())
21222164 if sc .hs .WriteTimeout > 0 {
2123- st .writeDeadline = time . AfterFunc (sc .hs .WriteTimeout , st .onWriteTimeout )
2165+ st .writeDeadline = sc . srv . afterFunc (sc .hs .WriteTimeout , st .onWriteTimeout )
21242166 }
21252167
21262168 sc .streams [id ] = st
@@ -2344,6 +2386,7 @@ func (sc *serverConn) handlerDone() {
23442386
23452387// Run on its own goroutine.
23462388func (sc * serverConn ) runHandler (rw * responseWriter , req * http.Request , handler func (http.ResponseWriter , * http.Request )) {
2389+ sc .srv .markNewGoroutine ()
23472390 defer sc .sendServeMsg (handlerDoneMsg )
23482391 didPanic := true
23492392 defer func () {
@@ -2640,7 +2683,7 @@ func (rws *responseWriterState) writeChunk(p []byte) (n int, err error) {
26402683 var date string
26412684 if _ , ok := rws .snapHeader ["Date" ]; ! ok {
26422685 // TODO(bradfitz): be faster here, like net/http? measure.
2643- date = time . Now ().UTC ().Format (http .TimeFormat )
2686+ date = rws . conn . srv . now ().UTC ().Format (http .TimeFormat )
26442687 }
26452688
26462689 for _ , v := range rws .snapHeader ["Trailer" ] {
@@ -2762,7 +2805,7 @@ func (rws *responseWriterState) promoteUndeclaredTrailers() {
27622805
27632806func (w * responseWriter ) SetReadDeadline (deadline time.Time ) error {
27642807 st := w .rws .stream
2765- if ! deadline .IsZero () && deadline .Before (time . Now ()) {
2808+ if ! deadline .IsZero () && deadline .Before (w . rws . conn . srv . now ()) {
27662809 // If we're setting a deadline in the past, reset the stream immediately
27672810 // so writes after SetWriteDeadline returns will fail.
27682811 st .onReadTimeout ()
@@ -2778,17 +2821,17 @@ func (w *responseWriter) SetReadDeadline(deadline time.Time) error {
27782821 if deadline .IsZero () {
27792822 st .readDeadline = nil
27802823 } else if st .readDeadline == nil {
2781- st .readDeadline = time . AfterFunc (deadline .Sub (time . Now ()), st .onReadTimeout )
2824+ st .readDeadline = sc . srv . afterFunc (deadline .Sub (w . rws . conn . srv . now ()), st .onReadTimeout )
27822825 } else {
2783- st .readDeadline .Reset (deadline .Sub (time . Now ()))
2826+ st .readDeadline .Reset (deadline .Sub (w . rws . conn . srv . now ()))
27842827 }
27852828 })
27862829 return nil
27872830}
27882831
27892832func (w * responseWriter ) SetWriteDeadline (deadline time.Time ) error {
27902833 st := w .rws .stream
2791- if ! deadline .IsZero () && deadline .Before (time . Now ()) {
2834+ if ! deadline .IsZero () && deadline .Before (w . rws . conn . srv . now ()) {
27922835 // If we're setting a deadline in the past, reset the stream immediately
27932836 // so writes after SetWriteDeadline returns will fail.
27942837 st .onWriteTimeout ()
@@ -2804,9 +2847,9 @@ func (w *responseWriter) SetWriteDeadline(deadline time.Time) error {
28042847 if deadline .IsZero () {
28052848 st .writeDeadline = nil
28062849 } else if st .writeDeadline == nil {
2807- st .writeDeadline = time . AfterFunc (deadline .Sub (time . Now ()), st .onWriteTimeout )
2850+ st .writeDeadline = sc . srv . afterFunc (deadline .Sub (w . rws . conn . srv . now ()), st .onWriteTimeout )
28082851 } else {
2809- st .writeDeadline .Reset (deadline .Sub (time . Now ()))
2852+ st .writeDeadline .Reset (deadline .Sub (w . rws . conn . srv . now ()))
28102853 }
28112854 })
28122855 return nil
0 commit comments