Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

net/http: add MaxBytesError #49359

Closed
wants to merge 5 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
3 changes: 3 additions & 0 deletions api/next/30715.txt
@@ -0,0 +1,3 @@
pkg net/http, type MaxBytesError struct #30715
pkg net/http, type MaxBytesError struct, Limit int64 #30715
pkg net/http, method (*MaxBytesError) Error() string #30715
21 changes: 17 additions & 4 deletions src/net/http/request.go
Expand Up @@ -1124,21 +1124,34 @@ func readRequest(b *bufio.Reader) (req *Request, err error) {
// MaxBytesReader is similar to io.LimitReader but is intended for
// limiting the size of incoming request bodies. In contrast to
// io.LimitReader, MaxBytesReader's result is a ReadCloser, returns a
// non-EOF error for a Read beyond the limit, and closes the
// MaxBytesError for a Read beyond the limit, and closes the
// underlying reader when its Close method is called.
//
// MaxBytesReader prevents clients from accidentally or maliciously
// sending a large request and wasting server resources.
// sending a large request and wasting server resources. If possible,
// it tells the ResponseWriter to close the connection after the limit
// has been reached.
func MaxBytesReader(w ResponseWriter, r io.ReadCloser, n int64) io.ReadCloser {
if n < 0 { // Treat negative limits as equivalent to 0.
n = 0
}
return &maxBytesReader{w: w, r: r, n: n}
return &maxBytesReader{w: w, r: r, i: n, n: n}
}

// MaxBytesError is returned by MaxBytesReader when its read limit is exceeded.
type MaxBytesError struct {
Limit int64
}

func (e *MaxBytesError) Error() string {
// Due to Hyrum's law, this text cannot be changed.
return "http: request body too large"
}

type maxBytesReader struct {
w ResponseWriter
r io.ReadCloser // underlying reader
i int64 // max bytes initially, for MaxBytesError
n int64 // max bytes remaining
err error // sticky error
}
Expand Down Expand Up @@ -1180,7 +1193,7 @@ func (l *maxBytesReader) Read(p []byte) (n int, err error) {
if res, ok := l.w.(requestTooLarger); ok {
res.requestTooLarge()
}
l.err = errors.New("http: request body too large")
l.err = &MaxBytesError{l.i}
return n, l.err
}

Expand Down
7 changes: 7 additions & 0 deletions src/net/http/serve_test.go
Expand Up @@ -3035,6 +3035,13 @@ func testRequestBodyLimit(t *testing.T, h2 bool) {
if n != limit {
t.Errorf("io.Copy = %d, want %d", n, limit)
}
mbErr, ok := err.(*MaxBytesError)
if !ok {
t.Errorf("expected MaxBytesError, got %T", err)
}
if mbErr.Limit != limit {
t.Errorf("MaxBytesError.Limit = %d, want %d", mbErr.Limit, limit)
}
}))
defer cst.close()

Expand Down