@@ -18,6 +18,43 @@ import (
1818 stringsutil "github.com/projectdiscovery/utils/strings"
1919)
2020
21+ // limitedBuffer wraps [bytes.Buffer] to prevent capacity growth beyond maxCap.
22+ // This prevents bytes.Buffer.ReadFrom() from over-allocating when it doesn't
23+ // know the final size.
24+ type limitedBuffer struct {
25+ buf * bytes.Buffer
26+ maxCap int
27+ }
28+
29+ func (lb * limitedBuffer ) ReadFrom (r io.Reader ) (n int64 , err error ) {
30+ const chunkSize = 32 * 1024 // 32KB chunks
31+ chunk := make ([]byte , chunkSize )
32+
33+ for {
34+ available := lb .buf .Cap () - lb .buf .Len ()
35+ if available < chunkSize && lb .buf .Cap () < lb .maxCap {
36+ needed := min (lb .buf .Len ()+ chunkSize , lb .maxCap )
37+ lb .buf .Grow (needed - lb .buf .Len ())
38+ }
39+
40+ nr , readErr := r .Read (chunk )
41+ if nr > 0 {
42+ nw , writeErr := lb .buf .Write (chunk [:nr ])
43+ n += int64 (nw )
44+ if writeErr != nil {
45+ return n , writeErr
46+ }
47+ }
48+
49+ if readErr != nil {
50+ if readErr == io .EOF {
51+ return n , nil
52+ }
53+ return n , readErr
54+ }
55+ }
56+ }
57+
2158// readNNormalizeRespBody performs normalization on the http response object.
2259// and fills body buffer with actual response body.
2360func readNNormalizeRespBody (rc * ResponseChain , body * bytes.Buffer ) (err error ) {
@@ -39,10 +76,13 @@ func readNNormalizeRespBody(rc *ResponseChain, body *bytes.Buffer) (err error) {
3976 if err != nil {
4077 wrapped = origBody
4178 }
42- limitReader := io .LimitReader (wrapped , 2 * MaxBodyRead )
79+ limitReader := io .LimitReader (wrapped , rc . maxBodySize )
4380
44- // read response body to buffer
45- _ , err = body .ReadFrom (limitReader )
81+ // Read body using ReadFrom for efficiency, but cap growth at maxBodySize.
82+ // We use a custom limitedBuffer wrapper to prevent bytes.Buffer from
83+ // over-allocating (it normally grows to 2x when size is unknown).
84+ limitedBuf := & limitedBuffer {buf : body , maxCap : int (rc .maxBodySize )}
85+ _ , err = limitedBuf .ReadFrom (limitReader )
4686 if err != nil {
4787 if strings .Contains (err .Error (), "gzip: invalid header" ) {
4888 // its invalid gzip but we will still use it from original body
0 commit comments