@@ -453,13 +453,13 @@ func (f *framer) readFrame() (any, error) {
453453 // Read the data frame directly from the underlying io.Reader to avoid
454454 // copies.
455455 if fh .Type == http2 .FrameData {
456- err = f .readDataFrame (fh , f . pool , & f . dataFrame )
456+ err = f .readDataFrame (fh )
457457 return & f .dataFrame , err
458458 }
459459 return f .fr .ReadFrameForHeader (fh )
460460}
461461
462- func (f * framer ) readDataFrame (fh http2.FrameHeader , pool mem. BufferPool , df * parsedDataFrame ) (err error ) {
462+ func (f * framer ) readDataFrame (fh http2.FrameHeader ) (err error ) {
463463 if fh .StreamID == 0 {
464464 // DATA frames MUST be associated with a stream. If a
465465 // DATA frame is received whose stream identifier
@@ -468,12 +468,25 @@ func (f *framer) readDataFrame(fh http2.FrameHeader, pool mem.BufferPool, df *pa
468468 // PROTOCOL_ERROR.
469469 return fmt .Errorf ("DATA frame with stream ID 0" )
470470 }
471- payload := pool .Get (int (fh .Length ))
472- defer func () {
473- if err != nil {
474- f .pool .Put (payload )
475- }
476- }()
471+ // Converting a *[]byte to a mem.BufferSlice incurs a heap allocation. This
472+ // conversion is performed by mem.NewBuffer. To avoid the extra allocation
473+ // a []byte is allocated directly if required and casted to a
474+ // mem.BufferSlice.
475+ var buf []byte
476+ // poolHandle is the pointer returned by the buffer pool (if it's used.).
477+ var poolHandle * []byte
478+ useBufferPool := ! mem .IsBelowBufferPoolingThreshold (int (fh .Length ))
479+ if useBufferPool {
480+ poolHandle = f .pool .Get (int (fh .Length ))
481+ buf = * poolHandle
482+ defer func () {
483+ if err != nil {
484+ f .pool .Put (poolHandle )
485+ }
486+ }()
487+ } else {
488+ buf = make ([]byte , int (fh .Length ))
489+ }
477490 if fh .Flags .Has (http2 .FlagDataPadded ) {
478491 if fh .Length == 0 {
479492 return io .ErrUnexpectedEOF
@@ -482,28 +495,34 @@ func (f *framer) readDataFrame(fh http2.FrameHeader, pool mem.BufferPool, df *pa
482495 // but it allows the rest of the payload to be read directly to the
483496 // start of the destination slice. This makes it easy to return the
484497 // original slice back to the buffer pool.
485- if _ , err := io .ReadFull (f .reader , ( * payload ) [:1 ]); err != nil {
498+ if _ , err := io .ReadFull (f .reader , buf [:1 ]); err != nil {
486499 return err
487500 }
488- padSize := ( * payload ) [0 ]
489- * payload = ( * payload ) [:len (* payload )- 1 ]
490- if _ , err := io .ReadFull (f .reader , * payload ); err != nil {
501+ padSize := buf [0 ]
502+ buf = buf [:len (buf )- 1 ]
503+ if _ , err := io .ReadFull (f .reader , buf ); err != nil {
491504 return err
492505 }
493- if int (padSize ) > len (* payload ) {
506+ if int (padSize ) > len (buf ) {
494507 // If the length of the padding is greater than the
495508 // length of the frame payload, the recipient MUST
496509 // treat this as a connection error.
497510 // Filed: https://github.com/http2/http2-spec/issues/610
498511 return fmt .Errorf ("pad size larger than data payload" )
499512 }
500- * payload = ( * payload ) [:len (* payload )- int (padSize )]
501- } else if _ , err := io .ReadFull (f .reader , * payload ); err != nil {
513+ buf = buf [:len (buf )- int (padSize )]
514+ } else if _ , err := io .ReadFull (f .reader , buf ); err != nil {
502515 return err
503516 }
504517
505- df .FrameHeader = fh
506- df .data = mem .NewBuffer (payload , pool )
518+ f .dataFrame .FrameHeader = fh
519+ if useBufferPool {
520+ // Update the handle to point to the (potentially re-sliced) buf.
521+ * poolHandle = buf
522+ f .dataFrame .data = mem .NewBuffer (poolHandle , f .pool )
523+ } else {
524+ f .dataFrame .data = mem .SliceBuffer (buf )
525+ }
507526 return nil
508527}
509528
0 commit comments