Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(2)

Unified Diff: third_party/grpc/tools/http2_interop/http2interop.go

Issue 1932353002: Initial checkin of gRPC to third_party/ Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
Index: third_party/grpc/tools/http2_interop/http2interop.go
diff --git a/third_party/grpc/tools/http2_interop/http2interop.go b/third_party/grpc/tools/http2_interop/http2interop.go
new file mode 100644
index 0000000000000000000000000000000000000000..1276a71afc9849e790aa93e4bb9193f1cf04b639
--- /dev/null
+++ b/third_party/grpc/tools/http2_interop/http2interop.go
@@ -0,0 +1,405 @@
+package http2interop
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "fmt"
+ "io"
+ "net"
+ "testing"
+ "time"
+)
+
+const (
+ Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
+)
+
+var (
+ defaultTimeout = 1 * time.Second
+)
+
+type HTTP2InteropCtx struct {
+ // Inputs
+ ServerHost string
+ ServerPort int
+ UseTLS bool
+ UseTestCa bool
+ ServerHostnameOverride string
+
+ T *testing.T
+
+ // Derived
+ serverSpec string
+ authority string
+ rootCAs *x509.CertPool
+}
+
+func parseFrame(r io.Reader) (Frame, error) {
+ fh := FrameHeader{}
+ if err := fh.Parse(r); err != nil {
+ return nil, err
+ }
+ var f Frame
+ switch fh.Type {
+ case PingFrameType:
+ f = &PingFrame{
+ Header: fh,
+ }
+ case SettingsFrameType:
+ 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
+ }
+
+ return f, nil
+}
+
+func streamFrame(w io.Writer, f Frame) error {
+ raw, err := f.MarshalBinary()
+ if err != nil {
+ return err
+ }
+ if _, err := w.Write(raw); err != nil {
+ return err
+ }
+ return nil
+}
+
+func testClientShortSettings(ctx *HTTP2InteropCtx, length int) error {
+ conn, err := connect(ctx)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ if _, err := conn.Write([]byte(Preface)); err != nil {
+ return err
+ }
+
+ // Bad, settings, non multiple of 6
+ sf := &UnknownFrame{
+ Header: FrameHeader{
+ Type: SettingsFrameType,
+ },
+ Data: make([]byte, length),
+ }
+ if err := streamFrame(conn, sf); err != nil {
+ ctx.T.Log("Unable to stream frame", sf)
+ return err
+ }
+
+ if _, err := expectGoAwaySoon(conn); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func testClientPrefaceWithStreamId(ctx *HTTP2InteropCtx) error {
+ conn, err := connect(ctx)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ // Good so far
+ if _, err := conn.Write([]byte(Preface)); err != nil {
+ return err
+ }
+
+ // Bad, settings do not have ids
+ sf := &SettingsFrame{
+ Header: FrameHeader{
+ StreamID: 1,
+ },
+ }
+ if err := streamFrame(conn, sf); err != nil {
+ return err
+ }
+
+ if _, err := expectGoAwaySoon(conn); err != nil {
+ return err
+ }
+ return nil
+}
+
+func testUnknownFrameType(ctx *HTTP2InteropCtx) error {
+ conn, err := connect(ctx)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ if err := http2Connect(conn, nil); err != nil {
+ return err
+ }
+
+ // Write a bunch of invalid frame types.
+ for ft := ContinuationFrameType + 1; ft != 0; ft++ {
+ fh := &UnknownFrame{
+ Header: FrameHeader{
+ Type: ft,
+ },
+ }
+ if err := streamFrame(conn, fh); err != nil {
+ ctx.T.Log("Unable to stream frame", fh)
+ return err
+ }
+ }
+
+ pf := &PingFrame{
+ Data: []byte("01234567"),
+ }
+ if err := streamFrame(conn, pf); err != nil {
+ ctx.T.Log("Unable to stream frame", pf)
+ return err
+ }
+
+ for {
+ frame, err := parseFrame(conn)
+ if err != nil {
+ 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 {
+ return fmt.Errorf("Bad ping %+v", *npf)
+ }
+ return nil
+ }
+ }
+
+ return nil
+}
+
+func testShortPreface(ctx *HTTP2InteropCtx, prefacePrefix string) error {
+ conn, err := connect(ctx)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ if _, err := conn.Write([]byte(prefacePrefix)); err != nil {
+ return err
+ }
+
+ if _, err := expectGoAwaySoon(conn); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func testTLSMaxVersion(ctx *HTTP2InteropCtx, version uint16) error {
+ config := buildTlsConfig(ctx)
+ config.MaxVersion = version
+ conn, err := connectWithTls(ctx, config)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ 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
+}
+
+func testTLSApplicationProtocol(ctx *HTTP2InteropCtx) error {
+ config := buildTlsConfig(ctx)
+ config.NextProtos = []string{"h2c"}
+ conn, err := connectWithTls(ctx, config)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ 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
+}
+
+func testTLSBadCipherSuites(ctx *HTTP2InteropCtx) error {
+ config := buildTlsConfig(ctx)
+ // These are the suites that Go supports, but are forbidden by http2.
+ config.CipherSuites = []uint16{
+ tls.TLS_RSA_WITH_RC4_128_SHA,
+ tls.TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ tls.TLS_RSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_RSA_WITH_AES_256_CBC_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ tls.TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ tls.TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ }
+ conn, err := connectWithTls(ctx, config)
+ if err != nil {
+ return err
+ }
+ defer conn.Close()
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ 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
+}
+
+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 nil, err
+ }
+ if gf, ok := f.(*GoAwayFrame); !ok {
+ continue
+ } else {
+ return gf, nil
+ }
+ }
+}
+
+func http2Connect(c net.Conn, sf *SettingsFrame) error {
+ if _, err := c.Write([]byte(Preface)); err != nil {
+ return err
+ }
+
+ if sf == nil {
+ sf = &SettingsFrame{}
+ }
+ if err := streamFrame(c, sf); err != nil {
+ return err
+ }
+ return nil
+}
+
+// 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)
+ } else {
+ config := buildTlsConfig(ctx)
+ conn, err = connectWithTls(ctx, config)
+ }
+ if err != nil {
+ return nil, err
+ }
+ conn.SetDeadline(time.Now().Add(defaultTimeout))
+
+ return conn, nil
+}
+
+func buildTlsConfig(ctx *HTTP2InteropCtx) *tls.Config {
+ return &tls.Config{
+ RootCAs: ctx.rootCAs,
+ NextProtos: []string{"h2"},
+ ServerName: ctx.authority,
+ MinVersion: tls.VersionTLS12,
+ }
+}
+
+func connectWithoutTls(ctx *HTTP2InteropCtx) (*CapConn, error) {
+ conn, err := net.DialTimeout("tcp", ctx.serverSpec, defaultTimeout)
+ if err != nil {
+ return nil, err
+ }
+ return &CapConn{Conn: conn}, nil
+}
+
+func connectWithTls(ctx *HTTP2InteropCtx, config *tls.Config) (*CapConn, error) {
+ conn, err := connectWithoutTls(ctx)
+ if err != nil {
+ return nil, err
+ }
+
+ return &CapConn{Conn: tls.Client(conn, config)}, nil
+}
« no previous file with comments | « third_party/grpc/tools/http2_interop/http1frame.go ('k') | third_party/grpc/tools/http2_interop/http2interop_test.go » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698