internal/parser/http2/frame_test.go

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")
	}
}