package http2
import (
"bytes"
"encoding/binary"
"testing"
)
func buildFrame(length int, ftype FrameType, flags Flags, sid uint32, payload []byte) []byte {
hdr := make([]byte, 9)
hdr[0] = byte(length >> 16)
hdr[1] = byte(length >> 8)
hdr[2] = byte(length)
hdr[3] = byte(ftype)
hdr[4] = byte(flags)
binary.BigEndian.PutUint32(hdr[5:9], sid&0x7fffffff)
return append(hdr, payload...)
}
func TestReadFrame(t *testing.T) {
cases := []struct {
name string
ft FrameType
body []byte
}{
{"settings_ack", FrameSettings, nil},
{"data_small", FrameData, []byte("hello")},
{"headers_block", FrameHeaders, []byte{0x82, 0x86, 0x84}},
}
for _, tc := range cases {
t.Run(tc.name, func(t *testing.T) {
buf := buildFrame(len(tc.body), tc.ft, 0, 1, tc.body)
f, err := ReadFrame(bytes.NewReader(buf))
if err != nil {
t.Fatal(err)
}
if f.Type != tc.ft {
t.Errorf("type=%s want %s", f.Type, tc.ft)
}
if !bytes.Equal(f.Payload, tc.body) {
t.Errorf("payload mismatch")
}
})
}
}
func TestDataPayloadPadded(t *testing.T) {
// 1-byte padlen(=2) + "hi" + 2 padding bytes.
raw := []byte{2, 'h', 'i', 0, 0}
buf := buildFrame(len(raw), FrameData, FlagPadded, 3, raw)
f, err := ReadFrame(bytes.NewReader(buf))
if err != nil {
t.Fatal(err)
}
data, err := f.DataPayload()
if err != nil {
t.Fatal(err)
}
if string(data) != "hi" {
t.Fatalf("data=%q", data)
}
}
func TestHeadersFragmentWithPriority(t *testing.T) {
payload := append([]byte{0, 0, 0, 0, 0}, 0x82) // stream dep + weight + 1 byte hpack
buf := buildFrame(len(payload), FrameHeaders, FlagPriority, 5, payload)
f, _ := ReadFrame(bytes.NewReader(buf))
frag, err := f.HeadersFragment()
if err != nil {
t.Fatal(err)
}
if !bytes.Equal(frag, []byte{0x82}) {
t.Errorf("fragment = %x", frag)
}
}
func TestFrameSizeLimit(t *testing.T) {
// Length field of 1<<17 exceeds maxFrameSize.
buf := []byte{2, 0, 0, byte(FrameData), 0, 0, 0, 0, 1}
if _, err := ReadFrame(bytes.NewReader(buf)); err == nil {
t.Fatal("expected ErrFrameSize")
}
}