| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420 | 
							- // Copyright 2019 The gRPC Authors
 
- //
 
- // Licensed under the Apache License, Version 2.0 (the "License");
 
- // you may not use this file except in compliance with the License.
 
- // You may obtain a copy of the License at
 
- //
 
- //     http://www.apache.org/licenses/LICENSE-2.0
 
- //
 
- // Unless required by applicable law or agreed to in writing, software
 
- // distributed under the License is distributed on an "AS IS" BASIS,
 
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 
- // See the License for the specific language governing permissions and
 
- // limitations under the License.
 
- 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.
 
- 	// Frame number 11 is the upcoming ALTSVC frame, and should not be tested.
 
- 	for ft := ContinuationFrameType + 2; 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
 
- }
 
 
  |