in transport/httpcommon/httpcommon.go [443:485]
func ReadAllWithLimit(resp *http.Response, limit int64) ([]byte, error) {
if resp == nil {
return nil, errors.New("response cannot be nil")
}
switch {
// nothing to read according to the server or limit
case resp.ContentLength == 0 || limit == 0 || resp.StatusCode == http.StatusNoContent:
return []byte{}, nil
// here if the limit is negative, e.g. `-1` it's ignored,
// limit == 0 is handled above
case limit > 0 && resp.ContentLength > limit:
return nil, fmt.Errorf("received Content-Length %d exceeds the set limit %d: %w", resp.ContentLength, limit, ErrResponseLimit)
// if we know the body length, we can allocate the buffer only once for the most efficient read
case resp.ContentLength >= 0:
body := make([]byte, resp.ContentLength)
_, err := io.ReadFull(resp.Body, body)
if err != nil {
return nil, fmt.Errorf("failed to read the response body with a known length %d: %w", resp.ContentLength, err)
}
return body, nil
default:
// using `bytes.NewBuffer` + `io.Copy` is much faster than `io.ReadAll`
// see https://github.com/elastic/beats/issues/36151#issuecomment-1931696767
buf := bytes.NewBuffer(nil)
var err error
if limit > 0 {
_, err = io.Copy(buf, io.LimitReader(resp.Body, limit))
} else {
_, err = io.Copy(buf, resp.Body)
}
if err != nil {
return nil, fmt.Errorf("failed to read the response body with unknown length: %w", err)
}
body := buf.Bytes()
if body == nil {
body = []byte{}
}
return body, nil
}
}