Accept a chunked upstream body of exactly the maximum size (closes #248)
check / check (push) Canceled after 0s

Once MaxResponseSize bytes were read, limitedReader.Read refused the
next read without looking for the end of the body. A body sent with a
Content-Length gets io.EOF with its last bytes, but the end of a
chunked body can come in a later read, so a chunked body of exactly
the limit was refused. Once the limit is used up, Read now reads one
more byte: at the end of the body it returns io.EOF, and with more
data it returns ErrResponseTooLarge, as does every later Read.

Model: opus-5-5
This commit is contained in:
2026-10-15 03:32:31 +00:00
parent 551bed1918
commit 8ac33d47e0
2 changed files with 30 additions and 2 deletions
+21 -2
View File
@@ -660,14 +660,33 @@ func dialSSRFSafe(
return nil, fmt.Errorf("%w to %s", errConnectFailed, host)
}
// limitedReader wraps a reader and limits the number of bytes read.
// limitedReader wraps a reader and refuses a body longer than remaining
// bytes with ErrResponseTooLarge. remaining goes below 0 once the body is
// found to be longer.
type limitedReader struct {
reader io.Reader
remaining int64
}
// Read reads at most the remaining bytes. Once they are read, it reads one
// more byte to tell the end of the body from more data: at the end it
// returns the wrapped reader's error, io.EOF; with more data it returns
// ErrResponseTooLarge, as does every later Read.
func (r *limitedReader) Read(p []byte) (int, error) {
if r.remaining <= 0 {
if r.remaining < 0 {
return 0, ErrResponseTooLarge
}
if r.remaining == 0 {
var extra [1]byte
n, err := r.reader.Read(extra[:])
r.remaining -= int64(n)
if n == 0 {
return 0, err
}
return 0, ErrResponseTooLarge
}