aboutsummaryrefslogtreecommitdiffhomepage
path: root/tools/http2_interop/http2interop.go
diff options
context:
space:
mode:
authorGravatar Carl Mastrangelo <notcarl@google.com>2015-11-20 17:43:15 -0800
committerGravatar Carl Mastrangelo <notcarl@google.com>2015-11-24 15:41:54 -0800
commit945836eade7d8f12f6eb84bc209da13ae7c89b38 (patch)
treed71142335c99eb5ccd124536c182320218e26a1b /tools/http2_interop/http2interop.go
parent299bcd55216349fe45b17d30e9bab19a85073db8 (diff)
Handle goaway and http1 responses
Diffstat (limited to 'tools/http2_interop/http2interop.go')
-rw-r--r--tools/http2_interop/http2interop.go178
1 files changed, 116 insertions, 62 deletions
diff --git a/tools/http2_interop/http2interop.go b/tools/http2_interop/http2interop.go
index bef8b0b656..abd7d4cf7d 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
}