github.com/mikelsr/quic-go@v0.36.1-0.20230701132136-1d9415b66898/http3/http_stream.go (about) 1 package http3 2 3 import ( 4 "fmt" 5 6 "github.com/mikelsr/quic-go" 7 ) 8 9 // A Stream is a HTTP/3 stream. 10 // When writing to and reading from the stream, data is framed in HTTP/3 DATA frames. 11 type Stream quic.Stream 12 13 // The stream conforms to the quic.Stream interface, but instead of writing to and reading directly 14 // from the QUIC stream, it writes to and reads from the HTTP stream. 15 type stream struct { 16 quic.Stream 17 18 buf []byte 19 20 onFrameError func() 21 bytesRemainingInFrame uint64 22 } 23 24 var _ Stream = &stream{} 25 26 func newStream(str quic.Stream, onFrameError func()) *stream { 27 return &stream{ 28 Stream: str, 29 onFrameError: onFrameError, 30 buf: make([]byte, 0, 16), 31 } 32 } 33 34 func (s *stream) Read(b []byte) (int, error) { 35 if s.bytesRemainingInFrame == 0 { 36 parseLoop: 37 for { 38 frame, err := parseNextFrame(s.Stream, nil) 39 if err != nil { 40 return 0, err 41 } 42 switch f := frame.(type) { 43 case *headersFrame: 44 // skip HEADERS frames 45 continue 46 case *dataFrame: 47 s.bytesRemainingInFrame = f.Length 48 break parseLoop 49 default: 50 s.onFrameError() 51 // parseNextFrame skips over unknown frame types 52 // Therefore, this condition is only entered when we parsed another known frame type. 53 return 0, fmt.Errorf("peer sent an unexpected frame: %T", f) 54 } 55 } 56 } 57 58 var n int 59 var err error 60 if s.bytesRemainingInFrame < uint64(len(b)) { 61 n, err = s.Stream.Read(b[:s.bytesRemainingInFrame]) 62 } else { 63 n, err = s.Stream.Read(b) 64 } 65 s.bytesRemainingInFrame -= uint64(n) 66 return n, err 67 } 68 69 func (s *stream) Write(b []byte) (int, error) { 70 s.buf = s.buf[:0] 71 s.buf = (&dataFrame{Length: uint64(len(b))}).Append(s.buf) 72 if _, err := s.Stream.Write(s.buf); err != nil { 73 return 0, err 74 } 75 return s.Stream.Write(b) 76 }