diff --git a/tools/http2_interop/frameheader.go b/tools/http2_interop/frameheader.go
index 78fe4201f627c75fa985c434302d087ae28cf3db..84f6fa5c55822277ff51d100679ab0a07042f5a6 100644
--- a/tools/http2_interop/frameheader.go
+++ b/tools/http2_interop/frameheader.go
@@ -58,7 +58,11 @@ func (fh *FrameHeader) MarshalBinary() ([]byte, error) {
 	buf[0], buf[1], buf[2] = byte(fh.Length>>16), byte(fh.Length>>8), byte(fh.Length)
 	buf[3] = byte(fh.Type)
 	buf[4] = fh.Flags
-	binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID))
+	var res uint32
+	if fh.Reserved {
+		res = 0x80000000
+	}
+	binary.BigEndian.PutUint32(buf[5:], uint32(fh.StreamID)|res)
 
 	return buf, nil
 }
@@ -89,6 +93,8 @@ func (ft FrameType) String() string {
 		return "WINDOW_UPDATE"
 	case ContinuationFrameType:
 		return "CONTINUATION"
+	case HTTP1FrameType:
+		return "HTTP/1.? (Bad)"
 	default:
 		return fmt.Sprintf("UNKNOWN(%d)", byte(ft))
 	}
@@ -106,4 +112,9 @@ const (
 	GoAwayFrameType       FrameType = 7
 	WindowUpdateFrameType FrameType = 8
 	ContinuationFrameType FrameType = 9
+
+	// HTTP1FrameType is not a real type, but rather a convenient way to check if the response
+	// is an http response.  The type of a frame header is the 4th byte, which in an http1
+	// response will be "HTTP/1.1 200 OK" or something like that.  The character for "P" is 80.
+	HTTP1FrameType FrameType = 80
 )
diff --git a/tools/http2_interop/http1frame.go b/tools/http2_interop/http1frame.go
new file mode 100644
index 0000000000000000000000000000000000000000..68ab197b6524a24b45a8ae14e59b33f64920d600
--- /dev/null
+++ b/tools/http2_interop/http1frame.go
@@ -0,0 +1,49 @@
+package http2interop
+
+import (
+	"bytes"
+	"io"
+	"strings"
+)
+
+// HTTP1Frame is not a real frame, but rather a way to represent an http1.x response.
+type HTTP1Frame struct {
+	Header FrameHeader
+	Data   []byte
+}
+
+func (f *HTTP1Frame) GetHeader() *FrameHeader {
+	return &f.Header
+}
+
+func (f *HTTP1Frame) ParsePayload(r io.Reader) error {
+	var buf bytes.Buffer
+	if _, err := io.Copy(&buf, r); err != nil {
+		return err
+	}
+	f.Data = buf.Bytes()
+	return nil
+}
+
+func (f *HTTP1Frame) MarshalPayload() ([]byte, error) {
+	return []byte(string(f.Data)), nil
+}
+
+func (f *HTTP1Frame) MarshalBinary() ([]byte, error) {
+	buf, err := f.Header.MarshalBinary()
+	if err != nil {
+		return nil, err
+	}
+
+	buf = append(buf, f.Data...)
+
+	return buf, nil
+}
+
+func (f *HTTP1Frame) String() string {
+	s := string(f.Data)
+	parts := strings.SplitN(s, "\n", 2)
+	headerleft, _ := f.Header.MarshalBinary()
+
+	return strings.TrimSpace(string(headerleft) + parts[0])
+}
diff --git a/tools/http2_interop/http2interop.go b/tools/http2_interop/http2interop.go
index bef8b0b656eaf75990d3521e87e9b4f5bd94b8e7..abd7d4cf7d77449b3a02e4756ca61cb8b05f6448 100644
--- a/tools/http2_interop/http2interop.go
+++ b/tools/http2_interop/http2interop.go
@@ -49,11 +49,16 @@ func parseFrame(r io.Reader) (Frame, error) {
 		f = &SettingsFrame{
 			Header: fh,
 		}
+	case HTTP1FrameType:
+		f = &HTTP1Frame{
+			Header: fh,
+		}
 	default:
 		f = &UnknownFrame{
 			Header: fh,
 		}
 	}
+
 	if err := f.ParsePayload(r); err != nil {
 		return nil, err
 	}
@@ -73,13 +78,14 @@ func streamFrame(w io.Writer, f Frame) error {
 }
 
 func testClientShortSettings(ctx *HTTP2InteropCtx, length int) error {
-	c, err := connect(ctx)
+	conn, err := connect(ctx)
 	if err != nil {
 		return err
 	}
-	defer c.Close()
+	defer conn.Close()
+	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
-	if _, err := c.Write([]byte(Preface)); err != nil {
+	if _, err := conn.Write([]byte(Preface)); err != nil {
 		return err
 	}
 
@@ -90,30 +96,28 @@ func testClientShortSettings(ctx *HTTP2InteropCtx, length int) error {
 		},
 		Data: make([]byte, length),
 	}
-	if err := streamFrame(c, sf); err != nil {
+	if err := streamFrame(conn, sf); err != nil {
 		ctx.T.Log("Unable to stream frame", sf)
 		return err
 	}
 
-	for {
-		if _, err := parseFrame(c); err != nil {
-			ctx.T.Log("Unable to parse frame")
-			return err
-		}
+	if _, err := expectGoAwaySoon(conn); err != nil {
+		return err
 	}
 
 	return nil
 }
 
 func testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error {
-	c, err := connect(ctx)
+	conn, err := connect(ctx)
 	if err != nil {
 		return err
 	}
-	defer c.Close()
+	defer conn.Close()
+	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
 	// Good so far
-	if _, err := c.Write([]byte(Preface)); err != nil {
+	if _, err := conn.Write([]byte(Preface)); err != nil {
 		return err
 	}
 
@@ -123,34 +127,25 @@ func testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error {
 			StreamID: 1,
 		},
 	}
-	if err := streamFrame(c, sf); err != nil {
+	if err := streamFrame(conn, sf); err != nil {
 		return err
 	}
 
-	for {
-		if _, err := parseFrame(c); err != nil {
-			return err
-		}
+	if _, err := expectGoAwaySoon(conn); err != nil {
+		return err
 	}
-
 	return nil
 }
 
 func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
-	c, err := connect(ctx)
+	conn, err := connect(ctx)
 	if err != nil {
 		return err
 	}
-	defer c.Close()
-
-	if _, err := c.Write([]byte(Preface)); err != nil {
-		return err
-	}
+	defer conn.Close()
+	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
-	// Send some settings, which are part of the client preface
-	sf := &SettingsFrame{}
-	if err := streamFrame(c, sf); err != nil {
-		ctx.T.Log("Unable to stream frame", sf)
+	if err := http2Connect(conn, nil); err != nil {
 		return err
 	}
 
@@ -161,7 +156,7 @@ func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
 				Type: ft,
 			},
 		}
-		if err := streamFrame(c, fh); err != nil {
+		if err := streamFrame(conn, fh); err != nil {
 			ctx.T.Log("Unable to stream frame", fh)
 			return err
 		}
@@ -170,18 +165,19 @@ func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
 	pf := &PingFrame{
 		Data: []byte("01234567"),
 	}
-	if err := streamFrame(c, pf); err != nil {
-		ctx.T.Log("Unable to stream frame", sf)
+	if err := streamFrame(conn, pf); err != nil {
+		ctx.T.Log("Unable to stream frame", pf)
 		return err
 	}
 
 	for {
-		frame, err := parseFrame(c)
+		frame, err := parseFrame(conn)
 		if err != nil {
-			ctx.T.Log("Unable to parse frame")
+			ctx.T.Log("Unable to parse frame", err)
 			return err
 		}
 		if npf, ok := frame.(*PingFrame); !ok {
+			ctx.T.Log("Got frame", frame.GetHeader().Type)
 			continue
 		} else {
 			if string(npf.Data) != string(pf.Data) || npf.Header.Flags&PING_ACK == 0 {
@@ -195,21 +191,22 @@ func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
 }
 
 func testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error {
-	c, err := connect(ctx)
+	conn, err := connect(ctx)
 	if err != nil {
 		return err
 	}
-	defer c.Close()
+	defer conn.Close()
+	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
-	if _, err := c.Write([]byte(prefacePrefix)); err != nil {
+	if _, err := conn.Write([]byte(prefacePrefix)); err != nil {
 		return err
 	}
 
-	buf := make([]byte, 256)
-	for ; err == nil; _, err = c.Read(buf) {
+	if _, err := expectGoAwaySoon(conn); err != nil {
+		return err
 	}
-	// TODO: maybe check for a GOAWAY?
-	return err
+
+	return nil
 }
 
 func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error {
@@ -222,13 +219,18 @@ func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error {
 	defer conn.Close()
 	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
-	buf := make([]byte, 256)
-	if n, err := conn.Read(buf); err != nil {
-		if n != 0 {
-			return fmt.Errorf("Expected no bytes to be read, but was %d", n)
-		}
+	if err := http2Connect(conn, nil); err != nil {
+		return err
+	}
+
+	gf, err := expectGoAway(conn)
+	if err != nil {
 		return err
 	}
+	// TODO: make an enum out of this
+	if gf.Code != 0xC {
+		return fmt.Errorf("Expected an Inadequate security code: %v", gf)
+	}
 	return nil
 }
 
@@ -242,13 +244,18 @@ func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error {
 	defer conn.Close()
 	conn.SetDeadline(time.Now().Add(defaultTimeout))
 
-	buf := make([]byte, 256)
-	if n, err := conn.Read(buf); err != nil {
-		if n != 0 {
-			return fmt.Errorf("Expected no bytes to be read, but was %d", n)
-		}
+	if err := http2Connect(conn, nil); err != nil {
+		return err
+	}
+
+	gf, err := expectGoAway(conn)
+	if err != nil {
 		return err
 	}
+	// TODO: make an enum out of this
+	if gf.Code != 0xC {
+		return fmt.Errorf("Expected an Inadequate security code: %v", gf)
+	}
 	return nil
 }
 
@@ -279,16 +286,44 @@ func testTLSBadCipherSuites(ctx *HTTP2InteropCtx) error {
 		return err
 	}
 
+	gf, err := expectGoAway(conn)
+	if err != nil {
+		return err
+	}
+	// TODO: make an enum out of this
+	if gf.Code != 0xC {
+		return fmt.Errorf("Expected an Inadequate security code: %v", gf)
+	}
+	return nil
+}
+
+func expectGoAway(conn net.Conn) (*GoAwayFrame, error) {
+	f, err := parseFrame(conn)
+	if err != nil {
+		return nil, err
+	}
+	if gf, ok := f.(*GoAwayFrame); !ok {
+		return nil, fmt.Errorf("Expected GoAway Frame %+v", f)
+	} else {
+		return gf, nil
+	}
+}
+
+// expectGoAwaySoon checks that a GOAWAY frame eventually comes.  Servers usually send
+// the initial settings frames before any data has actually arrived.  This function
+// checks that a go away shows.
+func expectGoAwaySoon(conn net.Conn) (*GoAwayFrame, error) {
 	for {
 		f, err := parseFrame(conn)
 		if err != nil {
-			return err
+			return nil, err
 		}
-		if gf, ok := f.(*GoAwayFrame); ok {
-			return fmt.Errorf("Got goaway frame %d", gf.Code)
+		if gf, ok := f.(*GoAwayFrame); !ok {
+			continue
+		} else {
+			return gf, nil
 		}
 	}
-	return nil
 }
 
 func http2Connect(c net.Conn, sf *SettingsFrame) error {
@@ -304,8 +339,29 @@ func http2Connect(c net.Conn, sf *SettingsFrame) error {
 	return nil
 }
 
-func connect(ctx *HTTP2InteropCtx) (net.Conn, error) {
-	var conn net.Conn
+// CapConn captures connection traffic if Log is non-nil
+type CapConn struct {
+	net.Conn
+	Log func(args ...interface{})
+}
+
+func (c *CapConn) Write(data []byte) (int, error) {
+	if c.Log != nil {
+		c.Log(" SEND: ", data)
+	}
+	return c.Conn.Write(data)
+}
+
+func (c *CapConn) Read(data []byte) (int, error) {
+	n, err := c.Conn.Read(data)
+	if c.Log != nil {
+		c.Log(" RECV: ", data[:n], err)
+	}
+	return n, err
+}
+
+func connect(ctx *HTTP2InteropCtx) (*CapConn, error) {
+	var conn *CapConn
 	var err error
 	if !ctx.UseTLS {
 		conn, err = connectWithoutTls(ctx)
@@ -327,24 +383,22 @@ func buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config {
 		NextProtos: []string{"h2"},
 		ServerName: ctx.authority,
 		MinVersion: tls.VersionTLS12,
-		// TODO(carl-mastrangelo): remove this once all test certificates have been updated.
-		InsecureSkipVerify: true,
 	}
 }
 
-func connectWithoutTls(ctx *HTTP2InteropCtx) (net.Conn, error) {
+func connectWithoutTls(ctx *HTTP2InteropCtx) (*CapConn, error) {
 	conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout)
 	if err != nil {
 		return nil, err
 	}
-	return conn, nil
+	return &CapConn{Conn: conn}, nil
 }
 
-func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*tls.Conn, error) {
+func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*CapConn, error) {
 	conn, err := connectWithoutTls(ctx)
 	if err != nil {
 		return nil, err
 	}
 
-	return tls.Client(conn, config), nil
+	return &CapConn{Conn: tls.Client(conn, config)}, nil
 }
diff --git a/tools/http2_interop/http2interop_test.go b/tools/http2_interop/http2interop_test.go
index e3d366f2f2752d8b7248990bfd432c914d958ed2..b35d08556944e6ff60654878eaade07c361a0216 100644
--- a/tools/http2_interop/http2interop_test.go
+++ b/tools/http2_interop/http2interop_test.go
@@ -5,7 +5,6 @@ import (
 	"crypto/x509"
 	"flag"
 	"fmt"
-	"io"
 	"io/ioutil"
 	"os"
 	"strconv"
@@ -68,15 +67,25 @@ func (ctx *HTTP2InteropCtx) Close() error {
 	return nil
 }
 
+func TestClientShortSettings(t *testing.T) {
+	if *testCase != "framing" {
+		t.SkipNow()
+	}
+	ctx := InteropCtx(t)
+	for i := 1; i <= 5; i++ {
+		err := testClientShortSettings(ctx, i)
+		matchError(t, err, "EOF")
+	}
+}
+
 func TestShortPreface(t *testing.T) {
 	if *testCase != "framing" {
 		t.SkipNow()
 	}
 	ctx := InteropCtx(t)
 	for i := 0; i < len(Preface)-1; i++ {
-		if err := testShortPreface(ctx, Preface[:i]+"X"); err != io.EOF {
-			t.Error("Expected an EOF but was", err)
-		}
+		err := testShortPreface(ctx, Preface[:i]+"X")
+		matchError(t, err, "EOF")
 	}
 }
 
@@ -90,13 +99,22 @@ func TestUnknownFrameType(t *testing.T) {
 	}
 }
 
+func TestClientPrefaceWithStreamId(t *testing.T) {
+	if *testCase != "framing" {
+		t.SkipNow()
+	}
+	ctx := InteropCtx(t)
+	err := testClientPrefaceWithStreamId(ctx)
+	matchError(t, err, "EOF")
+}
+
 func TestTLSApplicationProtocol(t *testing.T) {
 	if *testCase != "tls" {
 		t.SkipNow()
 	}
 	ctx := InteropCtx(t)
 	err := testTLSApplicationProtocol(ctx)
-	matchError(t, err, "EOF")
+	matchError(t, err, "EOF", "broken pipe")
 }
 
 func TestTLSMaxVersion(t *testing.T) {
@@ -119,15 +137,6 @@ func TestTLSBadCipherSuites(t *testing.T) {
 	matchError(t, err, "EOF", "Got goaway frame")
 }
 
-func TestClientPrefaceWithStreamId(t *testing.T) {
-	if *testCase != "framing" {
-		t.SkipNow()
-	}
-	ctx := InteropCtx(t)
-	err := testClientPrefaceWithStreamId(ctx)
-	matchError(t, err, "EOF")
-}
-
 func matchError(t *testing.T, err error, matches ...string) {
 	if err == nil {
 		t.Fatal("Expected an error")