mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
net/http: fix MaxBytesReader at EOF
Fixes #10884 Change-Id: I7cab3c96548867612f579d2cd4ec736309787443 Reviewed-on: https://go-review.googlesource.com/11961 Reviewed-by: Andrew Gerrand <adg@golang.org> Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
143822585e
commit
d6e6baa702
2 changed files with 70 additions and 9 deletions
|
|
@ -720,23 +720,52 @@ type maxBytesReader struct {
|
||||||
r io.ReadCloser // underlying reader
|
r io.ReadCloser // underlying reader
|
||||||
n int64 // max bytes remaining
|
n int64 // max bytes remaining
|
||||||
stopped bool
|
stopped bool
|
||||||
|
sawEOF bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (l *maxBytesReader) tooLarge() (n int, err error) {
|
||||||
|
if !l.stopped {
|
||||||
|
l.stopped = true
|
||||||
|
if res, ok := l.w.(*response); ok {
|
||||||
|
res.requestTooLarge()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0, errors.New("http: request body too large")
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
|
func (l *maxBytesReader) Read(p []byte) (n int, err error) {
|
||||||
if l.n <= 0 {
|
toRead := l.n
|
||||||
if !l.stopped {
|
if l.n == 0 {
|
||||||
l.stopped = true
|
if l.sawEOF {
|
||||||
if res, ok := l.w.(*response); ok {
|
return l.tooLarge()
|
||||||
res.requestTooLarge()
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
return 0, errors.New("http: request body too large")
|
// The underlying io.Reader may not return (0, io.EOF)
|
||||||
|
// at EOF if the requested size is 0, so read 1 byte
|
||||||
|
// instead. The io.Reader docs are a bit ambiguous
|
||||||
|
// about the return value of Read when 0 bytes are
|
||||||
|
// requested, and {bytes,strings}.Reader gets it wrong
|
||||||
|
// too (it returns (0, nil) even at EOF).
|
||||||
|
toRead = 1
|
||||||
}
|
}
|
||||||
if int64(len(p)) > l.n {
|
if int64(len(p)) > toRead {
|
||||||
p = p[:l.n]
|
p = p[:toRead]
|
||||||
}
|
}
|
||||||
n, err = l.r.Read(p)
|
n, err = l.r.Read(p)
|
||||||
|
if err == io.EOF {
|
||||||
|
l.sawEOF = true
|
||||||
|
}
|
||||||
|
if l.n == 0 {
|
||||||
|
// If we had zero bytes to read remaining (but hadn't seen EOF)
|
||||||
|
// and we get a byte here, that means we went over our limit.
|
||||||
|
if n > 0 {
|
||||||
|
return l.tooLarge()
|
||||||
|
}
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
l.n -= int64(n)
|
l.n -= int64(n)
|
||||||
|
if l.n < 0 {
|
||||||
|
l.n = 0
|
||||||
|
}
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -539,6 +539,38 @@ func TestStarRequest(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type responseWriterJustWriter struct {
|
||||||
|
io.Writer
|
||||||
|
}
|
||||||
|
|
||||||
|
func (responseWriterJustWriter) Header() Header { panic("should not be called") }
|
||||||
|
func (responseWriterJustWriter) WriteHeader(int) { panic("should not be called") }
|
||||||
|
|
||||||
|
// delayedEOFReader never returns (n > 0, io.EOF), instead putting
|
||||||
|
// off the io.EOF until a subsequent Read call.
|
||||||
|
type delayedEOFReader struct {
|
||||||
|
r io.Reader
|
||||||
|
}
|
||||||
|
|
||||||
|
func (dr delayedEOFReader) Read(p []byte) (n int, err error) {
|
||||||
|
n, err = dr.r.Read(p)
|
||||||
|
if n > 0 && err == io.EOF {
|
||||||
|
err = nil
|
||||||
|
}
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssue10884_MaxBytesEOF(t *testing.T) {
|
||||||
|
dst := ioutil.Discard
|
||||||
|
_, err := io.Copy(dst, MaxBytesReader(
|
||||||
|
responseWriterJustWriter{dst},
|
||||||
|
ioutil.NopCloser(delayedEOFReader{strings.NewReader("12345")}),
|
||||||
|
5))
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func testMissingFile(t *testing.T, req *Request) {
|
func testMissingFile(t *testing.T, req *Request) {
|
||||||
f, fh, err := req.FormFile("missing")
|
f, fh, err := req.FormFile("missing")
|
||||||
if f != nil {
|
if f != nil {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue