body.go 2.0 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798
  1. package http3
  2. import (
  3. "fmt"
  4. "io"
  5. "github.com/Psiphon-Labs/quic-go"
  6. )
  7. // The body of a http.Request or http.Response.
  8. type body struct {
  9. str quic.Stream
  10. // only set for the http.Response
  11. // The channel is closed when the user is done with this response:
  12. // either when Read() errors, or when Close() is called.
  13. reqDone chan<- struct{}
  14. reqDoneClosed bool
  15. onFrameError func()
  16. bytesRemainingInFrame uint64
  17. }
  18. var _ io.ReadCloser = &body{}
  19. func newRequestBody(str quic.Stream, onFrameError func()) *body {
  20. return &body{
  21. str: str,
  22. onFrameError: onFrameError,
  23. }
  24. }
  25. func newResponseBody(str quic.Stream, done chan<- struct{}, onFrameError func()) *body {
  26. return &body{
  27. str: str,
  28. onFrameError: onFrameError,
  29. reqDone: done,
  30. }
  31. }
  32. func (r *body) Read(b []byte) (int, error) {
  33. n, err := r.readImpl(b)
  34. if err != nil {
  35. r.requestDone()
  36. }
  37. return n, err
  38. }
  39. func (r *body) readImpl(b []byte) (int, error) {
  40. if r.bytesRemainingInFrame == 0 {
  41. parseLoop:
  42. for {
  43. frame, err := parseNextFrame(r.str)
  44. if err != nil {
  45. return 0, err
  46. }
  47. switch f := frame.(type) {
  48. case *headersFrame:
  49. // skip HEADERS frames
  50. continue
  51. case *dataFrame:
  52. r.bytesRemainingInFrame = f.Length
  53. break parseLoop
  54. default:
  55. r.onFrameError()
  56. // parseNextFrame skips over unknown frame types
  57. // Therefore, this condition is only entered when we parsed another known frame type.
  58. return 0, fmt.Errorf("peer sent an unexpected frame: %T", f)
  59. }
  60. }
  61. }
  62. var n int
  63. var err error
  64. if r.bytesRemainingInFrame < uint64(len(b)) {
  65. n, err = r.str.Read(b[:r.bytesRemainingInFrame])
  66. } else {
  67. n, err = r.str.Read(b)
  68. }
  69. r.bytesRemainingInFrame -= uint64(n)
  70. return n, err
  71. }
  72. func (r *body) requestDone() {
  73. if r.reqDoneClosed || r.reqDone == nil {
  74. return
  75. }
  76. close(r.reqDone)
  77. r.reqDoneClosed = true
  78. }
  79. func (r *body) Close() error {
  80. r.requestDone()
  81. // If the EOF was read, CancelRead() is a no-op.
  82. r.str.CancelRead(quic.StreamErrorCode(errorRequestCanceled))
  83. return nil
  84. }