@@ -11,7 +11,7 @@ import (
1111 "path/filepath"
1212 "sync"
1313
14- "github.com/gofiber/utils/v2"
14+ utils "github.com/gofiber/utils/v2"
1515 "github.com/valyala/fasthttp"
1616)
1717
@@ -89,22 +89,38 @@ func (r *Response) Body() []byte {
8989 return r .RawResponse .Body ()
9090}
9191
92+ // BodyStream returns the response body as a stream reader.
93+ // Note: When using BodyStream(), the response body is not copied to memory,
94+ // so calling Body() afterwards may return an empty slice.
95+ func (r * Response ) BodyStream () io.Reader {
96+ if stream := r .RawResponse .BodyStream (); stream != nil {
97+ return stream
98+ }
99+ // If streaming is not enabled, return a bytes.Reader from the regular body
100+ return bytes .NewReader (r .RawResponse .Body ())
101+ }
102+
103+ // IsStreaming returns true if the response body is being streamed.
104+ func (r * Response ) IsStreaming () bool {
105+ return r .RawResponse .BodyStream () != nil
106+ }
107+
92108// String returns the response body as a trimmed string.
93109func (r * Response ) String () string {
94110 return utils .Trim (string (r .Body ()), ' ' )
95111}
96112
97- // JSON unmarshal the response body into the given interface{} using JSON.
113+ // JSON unmarshals the response body into the given interface{} using JSON.
98114func (r * Response ) JSON (v any ) error {
99115 return r .client .jsonUnmarshal (r .Body (), v )
100116}
101117
102- // CBOR unmarshal the response body into the given interface{} using CBOR.
118+ // CBOR unmarshals the response body into the given interface{} using CBOR.
103119func (r * Response ) CBOR (v any ) error {
104120 return r .client .cborUnmarshal (r .Body (), v )
105121}
106122
107- // XML unmarshal the response body into the given interface{} using XML.
123+ // XML unmarshals the response body into the given interface{} using XML.
108124func (r * Response ) XML (v any ) error {
109125 return r .client .xmlUnmarshal (r .Body (), v )
110126}
@@ -136,21 +152,30 @@ func (r *Response) Save(v any) error {
136152 }
137153 defer func () { _ = outFile .Close () }() //nolint:errcheck // not needed
138154
139- if _ , err = io .Copy (outFile , bytes .NewReader (r .Body ())); err != nil {
155+ if r .IsStreaming () {
156+ _ , err = io .Copy (outFile , r .BodyStream ())
157+ } else {
158+ _ , err = io .Copy (outFile , bytes .NewReader (r .Body ()))
159+ }
160+
161+ if err != nil {
140162 return fmt .Errorf ("failed to write response body to file: %w" , err )
141163 }
142164
143165 return nil
144166
145167 case io.Writer :
146- if _ , err := io .Copy (p , bytes .NewReader (r .Body ())); err != nil {
147- return fmt .Errorf ("failed to write response body to io.Writer: %w" , err )
168+ var err error
169+ if r .IsStreaming () {
170+ _ , err = io .Copy (p , r .BodyStream ())
171+ } else {
172+ _ , err = io .Copy (p , bytes .NewReader (r .Body ()))
148173 }
149- defer func () {
150- if pc , ok := p .(io. WriteCloser ); ok {
151- _ = pc . Close () //nolint:errcheck // not needed
152- }
153- }()
174+
175+ if err != nil {
176+ return fmt . Errorf ( "failed to write response body to writer: %w" , err )
177+ }
178+
154179 return nil
155180
156181 default :
0 commit comments