diff options
author | Quentin Smith <quentin@golang.org> | 2016-10-25 15:41:14 -0400 |
---|---|---|
committer | Brad Fitzpatrick <bradfitz@golang.org> | 2016-11-07 19:32:11 +0000 |
commit | 9e4a70e8fd3e6fed93fcd6159228b3a8ecae1d80 (patch) | |
tree | 5ee3e1f57057e5179a4e88879ddd1cbda329428e | |
parent | 44febb28b626695e2daa693b1aa9ad7e516518e3 (diff) | |
download | go-9e4a70e8fd3e6fed93fcd6159228b3a8ecae1d80.tar.gz go-9e4a70e8fd3e6fed93fcd6159228b3a8ecae1d80.zip |
mime/multipart: test for overreading on a stream
Some multipart data arrives in a stream, where subsequent parts may not
be ready yet. Read should return a complete part as soon as
possible.
Fixes #15431
Change-Id: Ie8c041b853f3e07f0f2a66fbf4bcab5fe9132a7c
Reviewed-on: https://go-review.googlesource.com/32032
Run-TryBot: Quentin Smith <quentin@golang.org>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
Reviewed-by: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
-rw-r--r-- | src/mime/multipart/multipart_test.go | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/mime/multipart/multipart_test.go b/src/mime/multipart/multipart_test.go index d74ef61b88..7fbee90ac3 100644 --- a/src/mime/multipart/multipart_test.go +++ b/src/mime/multipart/multipart_test.go @@ -324,6 +324,73 @@ func (s *slowReader) Read(p []byte) (int, error) { return s.r.Read(p[:1]) } +type sentinelReader struct { + // done is closed when this reader is read from. + done chan struct{} +} + +func (s *sentinelReader) Read([]byte) (int, error) { + if s.done != nil { + close(s.done) + s.done = nil + } + return 0, io.EOF +} + +// TestMultipartStreamReadahead tests that PartReader does not block +// on reading past the end of a part, ensuring that it can be used on +// a stream like multipart/x-mixed-replace. See golang.org/issue/15431 +func TestMultipartStreamReadahead(t *testing.T) { + testBody1 := ` +This is a multi-part message. This line is ignored. +--MyBoundary +foo-bar: baz + +Body +--MyBoundary +` + testBody2 := `foo-bar: bop + +Body 2 +--MyBoundary-- +` + done1 := make(chan struct{}) + reader := NewReader( + io.MultiReader( + strings.NewReader(testBody1), + &sentinelReader{done1}, + strings.NewReader(testBody2)), + "MyBoundary") + + var i int + readPart := func(hdr textproto.MIMEHeader, body string) { + part, err := reader.NextPart() + if part == nil || err != nil { + t.Fatalf("Part %d: NextPart failed: %v", i, err) + } + + if !reflect.DeepEqual(part.Header, hdr) { + t.Errorf("Part %d: part.Header = %v, want %v", i, part.Header, hdr) + } + data, err := ioutil.ReadAll(part) + expectEq(t, body, string(data), fmt.Sprintf("Part %d body", i)) + if err != nil { + t.Fatalf("Part %d: ReadAll failed: %v", i, err) + } + i++ + } + + readPart(textproto.MIMEHeader{"Foo-Bar": {"baz"}}, "Body") + + select { + case <-done1: + t.Errorf("Reader read past second boundary") + default: + } + + readPart(textproto.MIMEHeader{"Foo-Bar": {"bop"}}, "Body 2") +} + func TestLineContinuation(t *testing.T) { // This body, extracted from an email, contains headers that span multiple // lines. |