Browse Source

http2: add tests to verify the type of peer stream resets

Make sure that both the server and client can see typed errors when
the peer's body is interrupted by a stream reset. grpc will need this.

Turns out things were okay, but the behavior wasn't locked in. Now it is.

Change-Id: I449a52e368efe9a3d44c59cc9a4fc15365bc4f12
Reviewed-on: https://go-review.googlesource.com/18502
Reviewed-by: Andrew Gerrand <adg@golang.org>
Brad Fitzpatrick 10 years ago
parent
commit
5df5483e05
2 changed files with 47 additions and 5 deletions
  1. 16 5
      http2/server_test.go
  2. 31 0
      http2/transport_test.go

+ 16 - 5
http2/server_test.go

@@ -75,6 +75,7 @@ func resetHooks() {
 type serverTesterOpt string
 type serverTesterOpt string
 
 
 var optOnlyServer = serverTesterOpt("only_server")
 var optOnlyServer = serverTesterOpt("only_server")
+var optQuiet = serverTesterOpt("quiet_logging")
 
 
 func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester {
 func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}) *serverTester {
 	resetHooks()
 	resetHooks()
@@ -89,7 +90,7 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
 		NextProtos: []string{NextProtoTLS, "h2-14"},
 		NextProtos: []string{NextProtoTLS, "h2-14"},
 	}
 	}
 
 
-	onlyServer := false
+	var onlyServer, quiet bool
 	for _, opt := range opts {
 	for _, opt := range opts {
 		switch v := opt.(type) {
 		switch v := opt.(type) {
 		case func(*tls.Config):
 		case func(*tls.Config):
@@ -97,7 +98,12 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
 		case func(*httptest.Server):
 		case func(*httptest.Server):
 			v(ts)
 			v(ts)
 		case serverTesterOpt:
 		case serverTesterOpt:
-			onlyServer = (v == optOnlyServer)
+			switch v {
+			case optOnlyServer:
+				onlyServer = true
+			case optQuiet:
+				quiet = true
+			}
 		default:
 		default:
 			t.Fatalf("unknown newServerTester option type %T", v)
 			t.Fatalf("unknown newServerTester option type %T", v)
 		}
 		}
@@ -116,7 +122,11 @@ func newServerTester(t testing.TB, handler http.HandlerFunc, opts ...interface{}
 	st.hpackDec = hpack.NewDecoder(initialHeaderTableSize, st.onHeaderField)
 	st.hpackDec = hpack.NewDecoder(initialHeaderTableSize, st.onHeaderField)
 
 
 	ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
 	ts.TLS = ts.Config.TLSConfig // the httptest.Server has its own copy of this TLS config
-	ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, logBuf), "", log.LstdFlags)
+	if quiet {
+		ts.Config.ErrorLog = log.New(ioutil.Discard, "", 0)
+	} else {
+		ts.Config.ErrorLog = log.New(io.MultiWriter(stderrv(), twriter{t: t, st: st}, logBuf), "", log.LstdFlags)
+	}
 	ts.StartTLS()
 	ts.StartTLS()
 
 
 	if VerboseLogs {
 	if VerboseLogs {
@@ -1120,8 +1130,9 @@ func TestServer_RSTStream_Unblocks_Read(t *testing.T) {
 			}
 			}
 		},
 		},
 		func(err error) {
 		func(err error) {
-			if err == nil {
-				t.Error("unexpected nil error from Request.Body.Read")
+			want := StreamError{StreamID: 0x1, Code: 0x8}
+			if !reflect.DeepEqual(err, want) {
+				t.Errorf("Read error = %v; want %v", err, want)
 			}
 			}
 		},
 		},
 	)
 	)

+ 31 - 0
http2/transport_test.go

@@ -1232,3 +1232,34 @@ func TestTransportChecksResponseHeaderListSize(t *testing.T) {
 	ct.run()
 	ct.run()
 
 
 }
 }
+
+// Test that the the Transport returns a typed error from Response.Body.Read calls
+// when the server sends an error. (here we use a panic, since that should generate
+// a stream error, but others like cancel should be similar)
+func TestTransportBodyReadErrorType(t *testing.T) {
+	st := newServerTester(t,
+		func(w http.ResponseWriter, r *http.Request) {
+			w.(http.Flusher).Flush() // force headers out
+			panic("boom")
+		},
+		optOnlyServer,
+		optQuiet,
+	)
+	defer st.Close()
+
+	tr := &Transport{TLSClientConfig: tlsConfigInsecure}
+	defer tr.CloseIdleConnections()
+	c := &http.Client{Transport: tr}
+
+	res, err := c.Get(st.ts.URL)
+	if err != nil {
+		t.Fatal(err)
+	}
+	defer res.Body.Close()
+	buf := make([]byte, 100)
+	n, err := res.Body.Read(buf)
+	want := StreamError{StreamID: 0x1, Code: 0x2}
+	if !reflect.DeepEqual(want, err) {
+		t.Errorf("Read = %v, %#v; want error %#v", n, err, want)
+	}
+}