github.com/apernet/quic-go@v0.43.1-0.20240515053213-5e9e635fd9f0/http3/frames_test.go (about)

     1  package http3
     2  
     3  import (
     4  	"bytes"
     5  	"errors"
     6  	"fmt"
     7  	"io"
     8  
     9  	"github.com/apernet/quic-go/quicvarint"
    10  
    11  	. "github.com/onsi/ginkgo/v2"
    12  	. "github.com/onsi/gomega"
    13  )
    14  
    15  type errReader struct{ err error }
    16  
    17  func (e errReader) Read([]byte) (int, error) { return 0, e.err }
    18  
    19  var _ = Describe("Frames", func() {
    20  	It("skips unknown frames", func() {
    21  		b := quicvarint.Append(nil, 0xdeadbeef) // type byte
    22  		b = quicvarint.Append(b, 0x42)
    23  		b = append(b, make([]byte, 0x42)...)
    24  		b = (&dataFrame{Length: 0x1234}).Append(b)
    25  		r := bytes.NewReader(b)
    26  		frame, err := parseNextFrame(r, nil)
    27  		Expect(err).ToNot(HaveOccurred())
    28  		Expect(frame).To(BeAssignableToTypeOf(&dataFrame{}))
    29  		Expect(frame.(*dataFrame).Length).To(Equal(uint64(0x1234)))
    30  	})
    31  
    32  	Context("DATA frames", func() {
    33  		It("parses", func() {
    34  			data := quicvarint.Append(nil, 0) // type byte
    35  			data = quicvarint.Append(data, 0x1337)
    36  			frame, err := parseNextFrame(bytes.NewReader(data), nil)
    37  			Expect(err).ToNot(HaveOccurred())
    38  			Expect(frame).To(BeAssignableToTypeOf(&dataFrame{}))
    39  			Expect(frame.(*dataFrame).Length).To(Equal(uint64(0x1337)))
    40  		})
    41  
    42  		It("writes", func() {
    43  			b := (&dataFrame{Length: 0xdeadbeef}).Append(nil)
    44  			frame, err := parseNextFrame(bytes.NewReader(b), nil)
    45  			Expect(err).ToNot(HaveOccurred())
    46  			Expect(err).ToNot(HaveOccurred())
    47  			Expect(frame).To(BeAssignableToTypeOf(&dataFrame{}))
    48  			Expect(frame.(*dataFrame).Length).To(Equal(uint64(0xdeadbeef)))
    49  		})
    50  	})
    51  
    52  	Context("HEADERS frames", func() {
    53  		It("parses", func() {
    54  			data := quicvarint.Append(nil, 1) // type byte
    55  			data = quicvarint.Append(data, 0x1337)
    56  			frame, err := parseNextFrame(bytes.NewReader(data), nil)
    57  			Expect(err).ToNot(HaveOccurred())
    58  			Expect(frame).To(BeAssignableToTypeOf(&headersFrame{}))
    59  			Expect(frame.(*headersFrame).Length).To(Equal(uint64(0x1337)))
    60  		})
    61  
    62  		It("writes", func() {
    63  			b := (&headersFrame{Length: 0xdeadbeef}).Append(nil)
    64  			frame, err := parseNextFrame(bytes.NewReader(b), nil)
    65  			Expect(err).ToNot(HaveOccurred())
    66  			Expect(err).ToNot(HaveOccurred())
    67  			Expect(frame).To(BeAssignableToTypeOf(&headersFrame{}))
    68  			Expect(frame.(*headersFrame).Length).To(Equal(uint64(0xdeadbeef)))
    69  		})
    70  	})
    71  
    72  	Context("SETTINGS frames", func() {
    73  		It("parses", func() {
    74  			settings := quicvarint.Append(nil, 13)
    75  			settings = quicvarint.Append(settings, 37)
    76  			settings = quicvarint.Append(settings, 0xdead)
    77  			settings = quicvarint.Append(settings, 0xbeef)
    78  			data := quicvarint.Append(nil, 4) // type byte
    79  			data = quicvarint.Append(data, uint64(len(settings)))
    80  			data = append(data, settings...)
    81  			frame, err := parseNextFrame(bytes.NewReader(data), nil)
    82  			Expect(err).ToNot(HaveOccurred())
    83  			Expect(frame).To(BeAssignableToTypeOf(&settingsFrame{}))
    84  			sf := frame.(*settingsFrame)
    85  			Expect(sf.Other).To(HaveKeyWithValue(uint64(13), uint64(37)))
    86  			Expect(sf.Other).To(HaveKeyWithValue(uint64(0xdead), uint64(0xbeef)))
    87  		})
    88  
    89  		It("rejects duplicate settings", func() {
    90  			settings := quicvarint.Append(nil, 13)
    91  			settings = quicvarint.Append(settings, 37)
    92  			settings = quicvarint.Append(settings, 13)
    93  			settings = quicvarint.Append(settings, 38)
    94  			data := quicvarint.Append(nil, 4) // type byte
    95  			data = quicvarint.Append(data, uint64(len(settings)))
    96  			data = append(data, settings...)
    97  			_, err := parseNextFrame(bytes.NewReader(data), nil)
    98  			Expect(err).To(MatchError("duplicate setting: 13"))
    99  		})
   100  
   101  		It("writes", func() {
   102  			sf := &settingsFrame{Other: map[uint64]uint64{
   103  				1:  2,
   104  				99: 999,
   105  				13: 37,
   106  			}}
   107  			frame, err := parseNextFrame(bytes.NewReader(sf.Append(nil)), nil)
   108  			Expect(err).ToNot(HaveOccurred())
   109  			Expect(frame).To(Equal(sf))
   110  		})
   111  
   112  		It("errors on EOF", func() {
   113  			sf := &settingsFrame{Other: map[uint64]uint64{
   114  				13:         37,
   115  				0xdeadbeef: 0xdecafbad,
   116  			}}
   117  			data := sf.Append(nil)
   118  
   119  			_, err := parseNextFrame(bytes.NewReader(data), nil)
   120  			Expect(err).ToNot(HaveOccurred())
   121  
   122  			for i := range data {
   123  				b := make([]byte, i)
   124  				copy(b, data[:i])
   125  				_, err := parseNextFrame(bytes.NewReader(b), nil)
   126  				Expect(err).To(MatchError(io.EOF))
   127  			}
   128  		})
   129  
   130  		Context("HTTP Datagrams", func() {
   131  			It("reads the SETTINGS_H3_DATAGRAM value", func() {
   132  				settings := quicvarint.Append(nil, settingDatagram)
   133  				settings = quicvarint.Append(settings, 1)
   134  				data := quicvarint.Append(nil, 4) // type byte
   135  				data = quicvarint.Append(data, uint64(len(settings)))
   136  				data = append(data, settings...)
   137  				f, err := parseNextFrame(bytes.NewReader(data), nil)
   138  				Expect(err).ToNot(HaveOccurred())
   139  				Expect(f).To(BeAssignableToTypeOf(&settingsFrame{}))
   140  				sf := f.(*settingsFrame)
   141  				Expect(sf.Datagram).To(BeTrue())
   142  			})
   143  
   144  			It("rejects duplicate SETTINGS_H3_DATAGRAM entries", func() {
   145  				settings := quicvarint.Append(nil, settingDatagram)
   146  				settings = quicvarint.Append(settings, 1)
   147  				settings = quicvarint.Append(settings, settingDatagram)
   148  				settings = quicvarint.Append(settings, 1)
   149  				data := quicvarint.Append(nil, 4) // type byte
   150  				data = quicvarint.Append(data, uint64(len(settings)))
   151  				data = append(data, settings...)
   152  				_, err := parseNextFrame(bytes.NewReader(data), nil)
   153  				Expect(err).To(MatchError(fmt.Sprintf("duplicate setting: %d", settingDatagram)))
   154  			})
   155  
   156  			It("rejects invalid values for the SETTINGS_H3_DATAGRAM entry", func() {
   157  				settings := quicvarint.Append(nil, settingDatagram)
   158  				settings = quicvarint.Append(settings, 1337)
   159  				data := quicvarint.Append(nil, 4) // type byte
   160  				data = quicvarint.Append(data, uint64(len(settings)))
   161  				data = append(data, settings...)
   162  				_, err := parseNextFrame(bytes.NewReader(data), nil)
   163  				Expect(err).To(MatchError("invalid value for SETTINGS_H3_DATAGRAM: 1337"))
   164  			})
   165  
   166  			It("writes the SETTINGS_H3_DATAGRAM setting", func() {
   167  				sf := &settingsFrame{Datagram: true}
   168  				frame, err := parseNextFrame(bytes.NewReader(sf.Append(nil)), nil)
   169  				Expect(err).ToNot(HaveOccurred())
   170  				Expect(frame).To(Equal(sf))
   171  			})
   172  		})
   173  
   174  		Context("Extended Connect", func() {
   175  			It("reads the SETTINGS_ENABLE_CONNECT_PROTOCOL value", func() {
   176  				settings := quicvarint.Append(nil, settingExtendedConnect)
   177  				settings = quicvarint.Append(settings, 1)
   178  				data := quicvarint.Append(nil, 4) // type byte
   179  				data = quicvarint.Append(data, uint64(len(settings)))
   180  				data = append(data, settings...)
   181  				f, err := parseNextFrame(bytes.NewReader(data), nil)
   182  				Expect(err).ToNot(HaveOccurred())
   183  				Expect(f).To(BeAssignableToTypeOf(&settingsFrame{}))
   184  				sf := f.(*settingsFrame)
   185  				Expect(sf.ExtendedConnect).To(BeTrue())
   186  			})
   187  
   188  			It("rejects duplicate SETTINGS_ENABLE_CONNECT_PROTOCOL entries", func() {
   189  				settings := quicvarint.Append(nil, settingExtendedConnect)
   190  				settings = quicvarint.Append(settings, 1)
   191  				settings = quicvarint.Append(settings, settingExtendedConnect)
   192  				settings = quicvarint.Append(settings, 1)
   193  				data := quicvarint.Append(nil, 4) // type byte
   194  				data = quicvarint.Append(data, uint64(len(settings)))
   195  				data = append(data, settings...)
   196  				_, err := parseNextFrame(bytes.NewReader(data), nil)
   197  				Expect(err).To(MatchError(fmt.Sprintf("duplicate setting: %d", settingExtendedConnect)))
   198  			})
   199  
   200  			It("rejects invalid values for the SETTINGS_ENABLE_CONNECT_PROTOCOL entry", func() {
   201  				settings := quicvarint.Append(nil, settingExtendedConnect)
   202  				settings = quicvarint.Append(settings, 1337)
   203  				data := quicvarint.Append(nil, 4) // type byte
   204  				data = quicvarint.Append(data, uint64(len(settings)))
   205  				data = append(data, settings...)
   206  				_, err := parseNextFrame(bytes.NewReader(data), nil)
   207  				Expect(err).To(MatchError("invalid value for SETTINGS_ENABLE_CONNECT_PROTOCOL: 1337"))
   208  			})
   209  
   210  			It("writes the SETTINGS_ENABLE_CONNECT_PROTOCOL setting", func() {
   211  				sf := &settingsFrame{ExtendedConnect: true}
   212  				frame, err := parseNextFrame(bytes.NewReader(sf.Append(nil)), nil)
   213  				Expect(err).ToNot(HaveOccurred())
   214  				Expect(frame).To(Equal(sf))
   215  			})
   216  		})
   217  	})
   218  
   219  	Context("hijacking", func() {
   220  		It("reads a frame without hijacking the stream", func() {
   221  			buf := bytes.NewBuffer(quicvarint.Append(nil, 1337))
   222  			customFrameContents := []byte("foobar")
   223  			buf.Write(customFrameContents)
   224  
   225  			var called bool
   226  			_, err := parseNextFrame(buf, func(ft FrameType, e error) (hijacked bool, err error) {
   227  				Expect(e).ToNot(HaveOccurred())
   228  				Expect(ft).To(BeEquivalentTo(1337))
   229  				called = true
   230  				b := make([]byte, 3)
   231  				_, err = io.ReadFull(buf, b)
   232  				Expect(err).ToNot(HaveOccurred())
   233  				Expect(string(b)).To(Equal("foo"))
   234  				return true, nil
   235  			})
   236  			Expect(err).To(MatchError(errHijacked))
   237  			Expect(called).To(BeTrue())
   238  		})
   239  
   240  		It("passes on errors that occur when reading the frame type", func() {
   241  			testErr := errors.New("test error")
   242  			var called bool
   243  			_, err := parseNextFrame(errReader{err: testErr}, func(ft FrameType, e error) (hijacked bool, err error) {
   244  				Expect(e).To(MatchError(testErr))
   245  				Expect(ft).To(BeZero())
   246  				called = true
   247  				return true, nil
   248  			})
   249  			Expect(err).To(MatchError(errHijacked))
   250  			Expect(called).To(BeTrue())
   251  		})
   252  
   253  		It("reads a frame without hijacking the stream", func() {
   254  			b := quicvarint.Append(nil, 1337)
   255  			customFrameContents := []byte("custom frame")
   256  			b = quicvarint.Append(b, uint64(len(customFrameContents)))
   257  			b = append(b, customFrameContents...)
   258  			b = (&dataFrame{Length: 6}).Append(b)
   259  			b = append(b, []byte("foobar")...)
   260  
   261  			var called bool
   262  			frame, err := parseNextFrame(bytes.NewReader(b), func(ft FrameType, e error) (hijacked bool, err error) {
   263  				Expect(e).ToNot(HaveOccurred())
   264  				Expect(ft).To(BeEquivalentTo(1337))
   265  				called = true
   266  				return false, nil
   267  			})
   268  			Expect(err).ToNot(HaveOccurred())
   269  			Expect(frame).To(Equal(&dataFrame{Length: 6}))
   270  			Expect(called).To(BeTrue())
   271  		})
   272  	})
   273  })