Skip to content

Commit b599c1f

Browse files
vcabbagebradfitz
authored andcommitted
net/http: add tests for http2 Server WriteTimeout enforcement per stream
Updates #18437 Change-Id: Iaa8a35d18eca8be24763dd151ad9e324ecbf7f7b Reviewed-on: https://go-review.googlesource.com/34726 Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
1 parent 9968348 commit b599c1f

File tree

1 file changed

+125
-0
lines changed

1 file changed

+125
-0
lines changed

src/net/http/serve_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -642,6 +642,131 @@ func TestHTTP2WriteDeadlineExtendedOnNewRequest(t *testing.T) {
642642
}
643643
}
644644

645+
// tryTimeouts runs testFunc with increasing timeouts. Test passes on first success,
646+
// and fails if all timeouts fail.
647+
func tryTimeouts(t *testing.T, testFunc func(timeout time.Duration) error) {
648+
tries := []time.Duration{250 * time.Millisecond, 500 * time.Millisecond, 1 * time.Second}
649+
for i, timeout := range tries {
650+
err := testFunc(timeout)
651+
if err == nil {
652+
return
653+
}
654+
t.Logf("failed at %v: %v", timeout, err)
655+
if i != len(tries)-1 {
656+
t.Logf("retrying at %v ...", tries[i+1])
657+
}
658+
}
659+
t.Fatal("all attempts failed")
660+
}
661+
662+
// Test that the HTTP/2 server RSTs stream on slow write.
663+
func TestHTTP2WriteDeadlineEnforcedPerStream(t *testing.T) {
664+
t.Skip("disabled until Issue 18437 is fixed")
665+
if testing.Short() {
666+
t.Skip("skipping in short mode")
667+
}
668+
setParallel(t)
669+
defer afterTest(t)
670+
tryTimeouts(t, testHTTP2WriteDeadlineEnforcedPerStream)
671+
}
672+
673+
func testHTTP2WriteDeadlineEnforcedPerStream(timeout time.Duration) error {
674+
reqNum := 0
675+
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
676+
reqNum++
677+
if reqNum == 1 {
678+
return // first request succeeds
679+
}
680+
time.Sleep(timeout) // second request times out
681+
}))
682+
ts.Config.WriteTimeout = timeout / 2
683+
ts.TLS = &tls.Config{NextProtos: []string{"h2"}}
684+
ts.StartTLS()
685+
defer ts.Close()
686+
687+
c := ts.Client()
688+
if err := ExportHttp2ConfigureTransport(c.Transport.(*Transport)); err != nil {
689+
return fmt.Errorf("ExportHttp2ConfigureTransport: %v", err)
690+
}
691+
692+
req, err := NewRequest("GET", ts.URL, nil)
693+
if err != nil {
694+
return fmt.Errorf("NewRequest: %v", err)
695+
}
696+
r, err := c.Do(req)
697+
if err != nil {
698+
return fmt.Errorf("http2 Get #1: %v", err)
699+
}
700+
r.Body.Close()
701+
if r.ProtoMajor != 2 {
702+
return fmt.Errorf("http2 Get expected HTTP/2.0, got %q", r.Proto)
703+
}
704+
705+
req, err = NewRequest("GET", ts.URL, nil)
706+
if err != nil {
707+
return fmt.Errorf("NewRequest: %v", err)
708+
}
709+
r, err = c.Do(req)
710+
if err == nil {
711+
r.Body.Close()
712+
if r.ProtoMajor != 2 {
713+
return fmt.Errorf("http2 Get expected HTTP/2.0, got %q", r.Proto)
714+
}
715+
return fmt.Errorf("http2 Get #2 expected error, got nil")
716+
}
717+
expected := "stream ID 3; INTERNAL_ERROR" // client IDs are odd, second stream should be 3
718+
if !strings.Contains(err.Error(), expected) {
719+
return fmt.Errorf("http2 Get #2: expected error to contain %q, got %q", expected, err)
720+
}
721+
return nil
722+
}
723+
724+
// Test that the HTTP/2 server does not send RST when WriteDeadline not set.
725+
func TestHTTP2NoWriteDeadline(t *testing.T) {
726+
t.Skip("disabled until Issue 18437 is fixed")
727+
if testing.Short() {
728+
t.Skip("skipping in short mode")
729+
}
730+
setParallel(t)
731+
defer afterTest(t)
732+
tryTimeouts(t, testHTTP2NoWriteDeadline)
733+
}
734+
735+
func testHTTP2NoWriteDeadline(timeout time.Duration) error {
736+
reqNum := 0
737+
ts := httptest.NewUnstartedServer(HandlerFunc(func(res ResponseWriter, req *Request) {
738+
reqNum++
739+
if reqNum == 1 {
740+
return // first request succeeds
741+
}
742+
time.Sleep(timeout) // second request timesout
743+
}))
744+
ts.TLS = &tls.Config{NextProtos: []string{"h2"}}
745+
ts.StartTLS()
746+
defer ts.Close()
747+
748+
c := ts.Client()
749+
if err := ExportHttp2ConfigureTransport(c.Transport.(*Transport)); err != nil {
750+
return fmt.Errorf("ExportHttp2ConfigureTransport: %v", err)
751+
}
752+
753+
for i := 0; i < 2; i++ {
754+
req, err := NewRequest("GET", ts.URL, nil)
755+
if err != nil {
756+
return fmt.Errorf("NewRequest: %v", err)
757+
}
758+
r, err := c.Do(req)
759+
if err != nil {
760+
return fmt.Errorf("http2 Get #%d: %v", i, err)
761+
}
762+
r.Body.Close()
763+
if r.ProtoMajor != 2 {
764+
return fmt.Errorf("http2 Get expected HTTP/2.0, got %q", r.Proto)
765+
}
766+
}
767+
return nil
768+
}
769+
645770
// golang.org/issue/4741 -- setting only a write timeout that triggers
646771
// shouldn't cause a handler to block forever on reads (next HTTP
647772
// request) that will never happen.

0 commit comments

Comments
 (0)