]> Cypherpunks repositories - gostls13.git/commitdiff
mime/multipart: test for overreading on a stream
authorQuentin Smith <quentin@golang.org>
Tue, 25 Oct 2016 19:41:14 +0000 (15:41 -0400)
committerBrad Fitzpatrick <bradfitz@golang.org>
Mon, 7 Nov 2016 19:32:11 +0000 (19:32 +0000)
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>

src/mime/multipart/multipart_test.go

index d74ef61b88d847f6fddbde117c2e5a29bc151147..7fbee90ac38f3fd0145ce9e58870f852dd6d04e3 100644 (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.