159 строки
3.4 KiB
Go
159 строки
3.4 KiB
Go
package spec
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"fmt"
|
|
|
|
"github.com/fatih/color"
|
|
"github.com/summerwind/h2spec/config"
|
|
|
|
"golang.org/x/net/http2"
|
|
"golang.org/x/net/http2/hpack"
|
|
)
|
|
|
|
var (
|
|
gray = color.New(color.FgHiBlack).SprintFunc()
|
|
green = color.New(color.FgGreen).SprintFunc()
|
|
red = color.New(color.FgRed).SprintFunc()
|
|
yellow = color.New(color.FgYellow).SprintFunc()
|
|
cyan = color.New(color.FgCyan).SprintFunc()
|
|
)
|
|
|
|
// DummyString returns a dummy string with specified length.
|
|
func DummyString(len int) string {
|
|
var buffer bytes.Buffer
|
|
for i := 0; i < len; i++ {
|
|
buffer.WriteString("x")
|
|
}
|
|
return buffer.String()
|
|
}
|
|
|
|
// DummyBytes returns a array of byte with specified length.
|
|
func DummyBytes(len int) []byte {
|
|
var buffer bytes.Buffer
|
|
for i := 0; i < len; i++ {
|
|
buffer.WriteString("x")
|
|
}
|
|
return buffer.Bytes()
|
|
}
|
|
|
|
// HeaderField returns a header field of HPACK with specified
|
|
// name and value.
|
|
func HeaderField(name, value string) hpack.HeaderField {
|
|
return hpack.HeaderField{Name: name, Value: value}
|
|
}
|
|
|
|
// CommonHeaders returns a array of header field of HPACK contained
|
|
// common http headers used in various test case.
|
|
func CommonHeaders(c *config.Config) []hpack.HeaderField {
|
|
var scheme, authority string
|
|
defaultPort := false
|
|
|
|
if c.TLS {
|
|
scheme = "https"
|
|
if c.Port == 443 {
|
|
defaultPort = true
|
|
}
|
|
} else {
|
|
scheme = "http"
|
|
if c.Port == 80 {
|
|
defaultPort = true
|
|
}
|
|
}
|
|
|
|
if defaultPort {
|
|
authority = c.Host
|
|
} else {
|
|
authority = c.Addr()
|
|
}
|
|
|
|
return []hpack.HeaderField{
|
|
HeaderField(":method", "GET"),
|
|
HeaderField(":scheme", scheme),
|
|
HeaderField(":path", "/"),
|
|
HeaderField(":authority", authority),
|
|
}
|
|
}
|
|
|
|
// CommonHeaders returns a array of header field of HPACK contained
|
|
// common http headers used in various test case.
|
|
func CommonRespHeaders(c *config.Config) []hpack.HeaderField {
|
|
return []hpack.HeaderField{
|
|
HeaderField(":status", "200"),
|
|
HeaderField("access-control-allow-origin", "*"),
|
|
}
|
|
}
|
|
|
|
// DummyHeaders returns a array of header field of HPACK contained
|
|
// dummy string values.
|
|
func DummyHeaders(c *config.Config, len int) []hpack.HeaderField {
|
|
headers := make([]hpack.HeaderField, 0, len)
|
|
dummy := DummyString(c.MaxHeaderLen)
|
|
|
|
for i := 0; i < len; i++ {
|
|
name := fmt.Sprintf("x-dummy%d", i)
|
|
headers = append(headers, HeaderField(name, dummy))
|
|
}
|
|
|
|
return headers
|
|
}
|
|
|
|
func DummyRespHeaders(c *config.Config, len int) []hpack.HeaderField {
|
|
headers := make([]hpack.HeaderField, 0, len)
|
|
dummy := DummyString(c.MaxHeaderLen)
|
|
|
|
for i := 0; i < len; i++ {
|
|
name := fmt.Sprintf("x-dummy%d", i)
|
|
headers = append(headers, HeaderField(name, dummy))
|
|
}
|
|
|
|
return headers
|
|
}
|
|
|
|
// ServerDataLength returns the total length of the DATA frame of /.
|
|
func ServerDataLength(c *config.Config) (int, error) {
|
|
conn, err := Dial(c)
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
err = conn.Handshake()
|
|
if err != nil {
|
|
return 0, err
|
|
}
|
|
|
|
headers := CommonHeaders(c)
|
|
hp := http2.HeadersFrameParam{
|
|
StreamID: 1,
|
|
EndStream: true,
|
|
EndHeaders: true,
|
|
BlockFragment: conn.EncodeHeaders(headers),
|
|
}
|
|
conn.WriteHeaders(hp)
|
|
|
|
len := 0
|
|
done := false
|
|
for !conn.Closed {
|
|
ev := conn.WaitEvent()
|
|
|
|
switch event := ev.(type) {
|
|
case DataFrameEvent:
|
|
len += int(event.Header().Length)
|
|
done = event.StreamEnded()
|
|
case HeadersFrameEvent:
|
|
done = event.StreamEnded()
|
|
}
|
|
|
|
if done {
|
|
break
|
|
}
|
|
}
|
|
|
|
if !done {
|
|
return 0, errors.New("Unable to get server data length")
|
|
}
|
|
|
|
return len, nil
|
|
}
|