github.com/metacubex/quic-go@v0.44.1-0.20240520163451-20b689a59136/crypto_stream_test.go (about)

     1  package quic
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/metacubex/quic-go/internal/protocol"
     7  	"github.com/metacubex/quic-go/internal/qerr"
     8  	"github.com/metacubex/quic-go/internal/wire"
     9  
    10  	. "github.com/onsi/ginkgo/v2"
    11  	. "github.com/onsi/gomega"
    12  )
    13  
    14  var _ = Describe("Crypto Stream", func() {
    15  	var str cryptoStream
    16  
    17  	BeforeEach(func() {
    18  		str = newCryptoStream()
    19  	})
    20  
    21  	Context("handling incoming data", func() {
    22  		It("handles in-order CRYPTO frames", func() {
    23  			Expect(str.HandleCryptoFrame(&wire.CryptoFrame{Data: []byte("foo")})).To(Succeed())
    24  			Expect(str.GetCryptoData()).To(Equal([]byte("foo")))
    25  			Expect(str.GetCryptoData()).To(BeNil())
    26  			Expect(str.HandleCryptoFrame(&wire.CryptoFrame{Data: []byte("bar"), Offset: 3})).To(Succeed())
    27  			Expect(str.GetCryptoData()).To(Equal([]byte("bar")))
    28  			Expect(str.GetCryptoData()).To(BeNil())
    29  		})
    30  
    31  		It("errors if the frame exceeds the maximum offset", func() {
    32  			Expect(str.HandleCryptoFrame(&wire.CryptoFrame{
    33  				Offset: protocol.MaxCryptoStreamOffset - 5,
    34  				Data:   []byte("foobar"),
    35  			})).To(MatchError(&qerr.TransportError{
    36  				ErrorCode:    qerr.CryptoBufferExceeded,
    37  				ErrorMessage: fmt.Sprintf("received invalid offset %d on crypto stream, maximum allowed %d", protocol.MaxCryptoStreamOffset+1, protocol.MaxCryptoStreamOffset),
    38  			}))
    39  		})
    40  
    41  		It("handles out-of-order CRYPTO frames", func() {
    42  			Expect(str.HandleCryptoFrame(&wire.CryptoFrame{Offset: 3, Data: []byte("bar")})).To(Succeed())
    43  			Expect(str.HandleCryptoFrame(&wire.CryptoFrame{Data: []byte("foo")})).To(Succeed())
    44  			Expect(str.GetCryptoData()).To(Equal([]byte("foobar")))
    45  			Expect(str.GetCryptoData()).To(BeNil())
    46  		})
    47  
    48  		Context("finishing", func() {
    49  			It("errors if there's still data to read after finishing", func() {
    50  				Expect(str.HandleCryptoFrame(&wire.CryptoFrame{
    51  					Data:   []byte("foobar"),
    52  					Offset: 10,
    53  				})).To(Succeed())
    54  				Expect(str.Finish()).To(MatchError(&qerr.TransportError{
    55  					ErrorCode:    qerr.ProtocolViolation,
    56  					ErrorMessage: "encryption level changed, but crypto stream has more data to read",
    57  				}))
    58  			})
    59  
    60  			It("works with reordered data", func() {
    61  				f1 := &wire.CryptoFrame{
    62  					Data: []byte("foo"),
    63  				}
    64  				f2 := &wire.CryptoFrame{
    65  					Offset: 3,
    66  					Data:   []byte("bar"),
    67  				}
    68  				Expect(str.HandleCryptoFrame(f2)).To(Succeed())
    69  				Expect(str.HandleCryptoFrame(f1)).To(Succeed())
    70  				Expect(str.Finish()).To(Succeed())
    71  				Expect(str.HandleCryptoFrame(f2)).To(Succeed())
    72  			})
    73  
    74  			It("rejects new crypto data after finishing", func() {
    75  				Expect(str.Finish()).To(Succeed())
    76  				Expect(str.HandleCryptoFrame(&wire.CryptoFrame{
    77  					Data: []byte("foo"),
    78  				})).To(MatchError(&qerr.TransportError{
    79  					ErrorCode:    qerr.ProtocolViolation,
    80  					ErrorMessage: "received crypto data after change of encryption level",
    81  				}))
    82  			})
    83  
    84  			It("ignores crypto data below the maximum offset received before finishing", func() {
    85  				Expect(str.HandleCryptoFrame(&wire.CryptoFrame{
    86  					Data: []byte("foobar"),
    87  				})).To(Succeed())
    88  				Expect(str.GetCryptoData()).To(Equal([]byte("foobar")))
    89  				Expect(str.Finish()).To(Succeed())
    90  				Expect(str.HandleCryptoFrame(&wire.CryptoFrame{
    91  					Offset: 2,
    92  					Data:   []byte("foo"),
    93  				})).To(Succeed())
    94  			})
    95  		})
    96  	})
    97  
    98  	Context("writing data", func() {
    99  		It("says if it has data", func() {
   100  			Expect(str.HasData()).To(BeFalse())
   101  			_, err := str.Write([]byte("foobar"))
   102  			Expect(err).ToNot(HaveOccurred())
   103  			Expect(str.HasData()).To(BeTrue())
   104  		})
   105  
   106  		It("pops crypto frames", func() {
   107  			_, err := str.Write([]byte("foobar"))
   108  			Expect(err).ToNot(HaveOccurred())
   109  			f := str.PopCryptoFrame(1000)
   110  			Expect(f).ToNot(BeNil())
   111  			Expect(f.Offset).To(BeZero())
   112  			Expect(f.Data).To(Equal([]byte("foobar")))
   113  		})
   114  
   115  		It("coalesces multiple writes", func() {
   116  			_, err := str.Write([]byte("foo"))
   117  			Expect(err).ToNot(HaveOccurred())
   118  			_, err = str.Write([]byte("bar"))
   119  			Expect(err).ToNot(HaveOccurred())
   120  			f := str.PopCryptoFrame(1000)
   121  			Expect(f).ToNot(BeNil())
   122  			Expect(f.Offset).To(BeZero())
   123  			Expect(f.Data).To(Equal([]byte("foobar")))
   124  		})
   125  
   126  		It("respects the maximum size", func() {
   127  			frameHeaderLen := (&wire.CryptoFrame{}).Length(protocol.Version1)
   128  			_, err := str.Write([]byte("foobar"))
   129  			Expect(err).ToNot(HaveOccurred())
   130  			f := str.PopCryptoFrame(frameHeaderLen + 3)
   131  			Expect(f).ToNot(BeNil())
   132  			Expect(f.Offset).To(BeZero())
   133  			Expect(f.Data).To(Equal([]byte("foo")))
   134  			f = str.PopCryptoFrame(frameHeaderLen + 3)
   135  			Expect(f).ToNot(BeNil())
   136  			Expect(f.Offset).To(Equal(protocol.ByteCount(3)))
   137  			Expect(f.Data).To(Equal([]byte("bar")))
   138  		})
   139  	})
   140  })