@@ -355,13 +355,46 @@ func Test_Ctx_Body(t *testing.T) {
355
355
require .Equal (t , []byte ("john=doe" ), c .Body ())
356
356
}
357
357
358
+ // go test -v -run=^$ -bench=Benchmark_Ctx_Body -benchmem -count=4
358
359
func Benchmark_Ctx_Body (b * testing.B ) {
359
360
const input = "john=doe"
360
361
361
362
app := New ()
362
363
c := app .NewCtx (& fasthttp.RequestCtx {}).(* DefaultCtx ) //nolint:errcheck, forcetypeassert // not needed
363
364
364
365
c .Request ().SetBody ([]byte (input ))
366
+ b .ReportAllocs ()
367
+ b .ResetTimer ()
368
+ for i := 0 ; i < b .N ; i ++ {
369
+ _ = c .Body ()
370
+ }
371
+
372
+ require .Equal (b , []byte (input ), c .Body ())
373
+ }
374
+
375
+ // go test -run Test_Ctx_Body_Immutable
376
+ func Test_Ctx_Body_Immutable (t * testing.T ) {
377
+ t .Parallel ()
378
+ app := New ()
379
+ app .config .Immutable = true
380
+ c := app .NewCtx (& fasthttp.RequestCtx {}).(* DefaultCtx ) //nolint:errcheck, forcetypeassert // not needed
381
+
382
+ c .Request ().SetBody ([]byte ("john=doe" ))
383
+ require .Equal (t , []byte ("john=doe" ), c .Body ())
384
+ }
385
+
386
+ // go test -v -run=^$ -bench=Benchmark_Ctx_Body_Immutable -benchmem -count=4
387
+ func Benchmark_Ctx_Body_Immutable (b * testing.B ) {
388
+ const input = "john=doe"
389
+
390
+ app := New ()
391
+ app .config .Immutable = true
392
+ c := app .NewCtx (& fasthttp.RequestCtx {}).(* DefaultCtx ) //nolint:errcheck, forcetypeassert // not needed
393
+
394
+ c .Request ().SetBody ([]byte (input ))
395
+ b .ReportAllocs ()
396
+ b .ResetTimer ()
397
+
365
398
for i := 0 ; i < b .N ; i ++ {
366
399
_ = c .Body ()
367
400
}
@@ -539,9 +572,205 @@ func Benchmark_Ctx_Body_With_Compression(b *testing.B) {
539
572
},
540
573
}
541
574
575
+ b .ReportAllocs ()
576
+ b .ResetTimer ()
577
+ for _ , ct := range compressionTests {
578
+ b .Run (ct .contentEncoding , func (b * testing.B ) {
579
+ app := New ()
580
+ const input = "john=doe"
581
+ c := app .NewCtx (& fasthttp.RequestCtx {})
582
+
583
+ c .Request ().Header .Set ("Content-Encoding" , ct .contentEncoding )
584
+ compressedBody , err := ct .compressWriter ([]byte (input ))
585
+ require .NoError (b , err )
586
+
587
+ c .Request ().SetBody (compressedBody )
588
+ for i := 0 ; i < b .N ; i ++ {
589
+ _ = c .Body ()
590
+ }
591
+
592
+ require .Equal (b , []byte (input ), c .Body ())
593
+ })
594
+ }
595
+ }
596
+
597
+ // go test -run Test_Ctx_Body_With_Compression_Immutable
598
+ func Test_Ctx_Body_With_Compression_Immutable (t * testing.T ) {
599
+ t .Parallel ()
600
+ tests := []struct {
601
+ name string
602
+ contentEncoding string
603
+ body []byte
604
+ expectedBody []byte
605
+ }{
606
+ {
607
+ name : "gzip" ,
608
+ contentEncoding : "gzip" ,
609
+ body : []byte ("john=doe" ),
610
+ expectedBody : []byte ("john=doe" ),
611
+ },
612
+ {
613
+ name : "unsupported_encoding" ,
614
+ contentEncoding : "undefined" ,
615
+ body : []byte ("keeps_ORIGINAL" ),
616
+ expectedBody : []byte ("keeps_ORIGINAL" ),
617
+ },
618
+ {
619
+ name : "gzip then unsupported" ,
620
+ contentEncoding : "gzip, undefined" ,
621
+ body : []byte ("Go, be gzipped" ),
622
+ expectedBody : []byte ("Go, be gzipped" ),
623
+ },
624
+ {
625
+ name : "invalid_deflate" ,
626
+ contentEncoding : "gzip,deflate" ,
627
+ body : []byte ("I'm not correctly compressed" ),
628
+ expectedBody : []byte (zlib .ErrHeader .Error ()),
629
+ },
630
+ }
631
+
632
+ for _ , testObject := range tests {
633
+ tCase := testObject // Duplicate object to ensure it will be unique across all runs
634
+ t .Run (tCase .name , func (t * testing.T ) {
635
+ t .Parallel ()
636
+ app := New ()
637
+ app .config .Immutable = true
638
+ c := app .NewCtx (& fasthttp.RequestCtx {}).(* DefaultCtx ) //nolint:errcheck, forcetypeassert // not needed
639
+ c .Request ().Header .Set ("Content-Encoding" , tCase .contentEncoding )
640
+
641
+ if strings .Contains (tCase .contentEncoding , "gzip" ) {
642
+ var b bytes.Buffer
643
+ gz := gzip .NewWriter (& b )
644
+
645
+ _ , err := gz .Write (tCase .body )
646
+ require .NoError (t , err )
647
+
648
+ err = gz .Flush ()
649
+ require .NoError (t , err )
650
+
651
+ err = gz .Close ()
652
+ require .NoError (t , err )
653
+ tCase .body = b .Bytes ()
654
+ }
655
+
656
+ c .Request ().SetBody (tCase .body )
657
+ body := c .Body ()
658
+ require .Equal (t , tCase .expectedBody , body )
659
+
660
+ // Check if body raw is the same as previous before decompression
661
+ require .Equal (
662
+ t , tCase .body , c .Request ().Body (),
663
+ "Body raw must be the same as set before" ,
664
+ )
665
+ })
666
+ }
667
+ }
668
+
669
+ // go test -v -run=^$ -bench=Benchmark_Ctx_Body_With_Compression_Immutable -benchmem -count=4
670
+ func Benchmark_Ctx_Body_With_Compression_Immutable (b * testing.B ) {
671
+ encodingErr := errors .New ("failed to encoding data" )
672
+
673
+ var (
674
+ compressGzip = func (data []byte ) ([]byte , error ) {
675
+ var buf bytes.Buffer
676
+ writer := gzip .NewWriter (& buf )
677
+ if _ , err := writer .Write (data ); err != nil {
678
+ return nil , encodingErr
679
+ }
680
+ if err := writer .Flush (); err != nil {
681
+ return nil , encodingErr
682
+ }
683
+ if err := writer .Close (); err != nil {
684
+ return nil , encodingErr
685
+ }
686
+ return buf .Bytes (), nil
687
+ }
688
+ compressDeflate = func (data []byte ) ([]byte , error ) {
689
+ var buf bytes.Buffer
690
+ writer := zlib .NewWriter (& buf )
691
+ if _ , err := writer .Write (data ); err != nil {
692
+ return nil , encodingErr
693
+ }
694
+ if err := writer .Flush (); err != nil {
695
+ return nil , encodingErr
696
+ }
697
+ if err := writer .Close (); err != nil {
698
+ return nil , encodingErr
699
+ }
700
+ return buf .Bytes (), nil
701
+ }
702
+ )
703
+ compressionTests := []struct {
704
+ contentEncoding string
705
+ compressWriter func ([]byte ) ([]byte , error )
706
+ }{
707
+ {
708
+ contentEncoding : "gzip" ,
709
+ compressWriter : compressGzip ,
710
+ },
711
+ {
712
+ contentEncoding : "gzip,invalid" ,
713
+ compressWriter : compressGzip ,
714
+ },
715
+ {
716
+ contentEncoding : "deflate" ,
717
+ compressWriter : compressDeflate ,
718
+ },
719
+ {
720
+ contentEncoding : "gzip,deflate" ,
721
+ compressWriter : func (data []byte ) ([]byte , error ) {
722
+ var (
723
+ buf bytes.Buffer
724
+ writer interface {
725
+ io.WriteCloser
726
+ Flush () error
727
+ }
728
+ err error
729
+ )
730
+
731
+ // deflate
732
+ {
733
+ writer = zlib .NewWriter (& buf )
734
+ if _ , err = writer .Write (data ); err != nil {
735
+ return nil , encodingErr
736
+ }
737
+ if err = writer .Flush (); err != nil {
738
+ return nil , encodingErr
739
+ }
740
+ if err = writer .Close (); err != nil {
741
+ return nil , encodingErr
742
+ }
743
+ }
744
+
745
+ data = make ([]byte , buf .Len ())
746
+ copy (data , buf .Bytes ())
747
+ buf .Reset ()
748
+
749
+ // gzip
750
+ {
751
+ writer = gzip .NewWriter (& buf )
752
+ if _ , err = writer .Write (data ); err != nil {
753
+ return nil , encodingErr
754
+ }
755
+ if err = writer .Flush (); err != nil {
756
+ return nil , encodingErr
757
+ }
758
+ if err = writer .Close (); err != nil {
759
+ return nil , encodingErr
760
+ }
761
+ }
762
+
763
+ return buf .Bytes (), nil
764
+ },
765
+ },
766
+ }
767
+
768
+ b .ReportAllocs ()
769
+ b .ResetTimer ()
542
770
for _ , ct := range compressionTests {
543
771
b .Run (ct .contentEncoding , func (b * testing.B ) {
544
772
app := New ()
773
+ app .config .Immutable = true
545
774
const input = "john=doe"
546
775
c := app .NewCtx (& fasthttp.RequestCtx {})
547
776
0 commit comments