mirror of https://github.com/grpc/grpc.git
The C based gRPC (C++, Python, Ruby, Objective-C, PHP, C#)
https://grpc.io/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
246 lines
4.1 KiB
246 lines
4.1 KiB
9 years ago
|
package http2interop
|
||
|
|
||
|
import (
|
||
|
"crypto/tls"
|
||
|
"fmt"
|
||
|
"io"
|
||
|
"log"
|
||
|
)
|
||
|
|
||
|
const (
|
||
|
Preface = "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n"
|
||
|
)
|
||
|
|
||
|
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,
|
||
|
}
|
||
|
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 getHttp2Conn(addr string) (*tls.Conn, error) {
|
||
|
config := &tls.Config{
|
||
|
InsecureSkipVerify: true,
|
||
|
NextProtos: []string{"h2"},
|
||
|
}
|
||
|
|
||
|
conn, err := tls.Dial("tcp", addr, config)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return conn, nil
|
||
|
}
|
||
|
|
||
|
func testClientShortSettings(addr string, length int) error {
|
||
|
c, err := getHttp2Conn(addr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer c.Close()
|
||
|
|
||
|
if _, err := c.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(c, sf); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
frame, err := parseFrame(c)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
log.Println(frame)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func testClientPrefaceWithStreamId(addr string) error {
|
||
|
c, err := getHttp2Conn(addr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer c.Close()
|
||
|
|
||
|
// Good so far
|
||
|
if _, err := c.Write([]byte(Preface)); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Bad, settings do not have ids
|
||
|
sf := &SettingsFrame{
|
||
|
Header: FrameHeader{
|
||
|
StreamID: 1,
|
||
|
},
|
||
|
}
|
||
|
if err := streamFrame(c, sf); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
frame, err := parseFrame(c)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
log.Println(frame)
|
||
|
}
|
||
|
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func testUnknownFrameType(addr string) error {
|
||
|
c, err := getHttp2Conn(addr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer c.Close()
|
||
|
|
||
|
if _, err := c.Write([]byte(Preface)); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
// Send some settings, which are part of the client preface
|
||
|
sf := &SettingsFrame{}
|
||
|
if err := streamFrame(c, sf); 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(c, fh); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pf := &PingFrame{
|
||
|
Data: []byte("01234567"),
|
||
|
}
|
||
|
if err := streamFrame(c, pf); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
for {
|
||
|
frame, err := parseFrame(c)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
if npf, ok := frame.(*PingFrame); !ok {
|
||
|
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(addr string, prefacePrefix string) error {
|
||
|
c, err := getHttp2Conn(addr)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer c.Close()
|
||
|
|
||
|
if _, err := c.Write([]byte(prefacePrefix)); err != nil {
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
buf := make([]byte, 256)
|
||
|
for ; err == nil; _, err = c.Read(buf) {
|
||
|
}
|
||
|
// TODO: maybe check for a GOAWAY?
|
||
|
return err
|
||
|
}
|
||
|
|
||
|
func testTLSMaxVersion(addr string, version uint16) error {
|
||
|
config := &tls.Config{
|
||
|
InsecureSkipVerify: true,
|
||
|
NextProtos: []string{"h2"},
|
||
|
MaxVersion: version,
|
||
|
}
|
||
|
conn, err := tls.Dial("tcp", addr, config)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer conn.Close()
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|
||
|
|
||
|
func testTLSApplicationProtocol(addr string) error {
|
||
|
config := &tls.Config{
|
||
|
InsecureSkipVerify: true,
|
||
|
NextProtos: []string{"h2c"},
|
||
|
}
|
||
|
conn, err := tls.Dial("tcp", addr, config)
|
||
|
if err != nil {
|
||
|
return err
|
||
|
}
|
||
|
defer conn.Close()
|
||
|
|
||
|
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)
|
||
|
}
|
||
|
return err
|
||
|
}
|
||
|
return nil
|
||
|
}
|