1
0
mirror of https://github.com/golang/go synced 2024-11-23 19:40:08 -07:00

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>
This commit is contained in:
Quentin Smith 2016-10-25 15:41:14 -04:00 committed by Brad Fitzpatrick
parent 44febb28b6
commit 9e4a70e8fd

View File

@ -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.