File tree 2 files changed +70
-9
lines changed
2 files changed +70
-9
lines changed Original file line number Diff line number Diff line change @@ -720,23 +720,52 @@ type maxBytesReader struct {
720
720
r io.ReadCloser // underlying reader
721
721
n int64 // max bytes remaining
722
722
stopped bool
723
+ sawEOF bool
724
+ }
725
+
726
+ func (l * maxBytesReader ) tooLarge () (n int , err error ) {
727
+ if ! l .stopped {
728
+ l .stopped = true
729
+ if res , ok := l .w .(* response ); ok {
730
+ res .requestTooLarge ()
731
+ }
732
+ }
733
+ return 0 , errors .New ("http: request body too large" )
723
734
}
724
735
725
736
func (l * maxBytesReader ) Read (p []byte ) (n int , err error ) {
726
- if l .n <= 0 {
727
- if ! l .stopped {
728
- l .stopped = true
729
- if res , ok := l .w .(* response ); ok {
730
- res .requestTooLarge ()
731
- }
737
+ toRead := l .n
738
+ if l .n == 0 {
739
+ if l .sawEOF {
740
+ return l .tooLarge ()
732
741
}
733
- return 0 , errors .New ("http: request body too large" )
742
+ // The underlying io.Reader may not return (0, io.EOF)
743
+ // at EOF if the requested size is 0, so read 1 byte
744
+ // instead. The io.Reader docs are a bit ambiguous
745
+ // about the return value of Read when 0 bytes are
746
+ // requested, and {bytes,strings}.Reader gets it wrong
747
+ // too (it returns (0, nil) even at EOF).
748
+ toRead = 1
734
749
}
735
- if int64 (len (p )) > l . n {
736
- p = p [:l . n ]
750
+ if int64 (len (p )) > toRead {
751
+ p = p [:toRead ]
737
752
}
738
753
n , err = l .r .Read (p )
754
+ if err == io .EOF {
755
+ l .sawEOF = true
756
+ }
757
+ if l .n == 0 {
758
+ // If we had zero bytes to read remaining (but hadn't seen EOF)
759
+ // and we get a byte here, that means we went over our limit.
760
+ if n > 0 {
761
+ return l .tooLarge ()
762
+ }
763
+ return 0 , err
764
+ }
739
765
l .n -= int64 (n )
766
+ if l .n < 0 {
767
+ l .n = 0
768
+ }
740
769
return
741
770
}
742
771
Original file line number Diff line number Diff line change @@ -539,6 +539,38 @@ func TestStarRequest(t *testing.T) {
539
539
}
540
540
}
541
541
542
+ type responseWriterJustWriter struct {
543
+ io.Writer
544
+ }
545
+
546
+ func (responseWriterJustWriter ) Header () Header { panic ("should not be called" ) }
547
+ func (responseWriterJustWriter ) WriteHeader (int ) { panic ("should not be called" ) }
548
+
549
+ // delayedEOFReader never returns (n > 0, io.EOF), instead putting
550
+ // off the io.EOF until a subsequent Read call.
551
+ type delayedEOFReader struct {
552
+ r io.Reader
553
+ }
554
+
555
+ func (dr delayedEOFReader ) Read (p []byte ) (n int , err error ) {
556
+ n , err = dr .r .Read (p )
557
+ if n > 0 && err == io .EOF {
558
+ err = nil
559
+ }
560
+ return
561
+ }
562
+
563
+ func TestIssue10884_MaxBytesEOF (t * testing.T ) {
564
+ dst := ioutil .Discard
565
+ _ , err := io .Copy (dst , MaxBytesReader (
566
+ responseWriterJustWriter {dst },
567
+ ioutil .NopCloser (delayedEOFReader {strings .NewReader ("12345" )}),
568
+ 5 ))
569
+ if err != nil {
570
+ t .Fatal (err )
571
+ }
572
+ }
573
+
542
574
func testMissingFile (t * testing.T , req * Request ) {
543
575
f , fh , err := req .FormFile ("missing" )
544
576
if f != nil {
You can’t perform that action at this time.
0 commit comments