mirror of
https://github.com/golang/go
synced 2024-11-20 05:44:44 -07:00
mime/multipart: report io.EOF correctly on part ending without newlines
If a part ends with "--boundary--", without a final "\r\n", that's also a graceful EOF, and we should return io.EOF instead of the fmt-wrapped io.EOF from bufio.Reader.ReadSlice. I found this bug parsing an image attachment from gmail. Minimal test case stripped down from the original gmail-generated attachment included. R=golang-dev, r CC=golang-dev https://golang.org/cl/6118043
This commit is contained in:
parent
5fc2af1f77
commit
87eaa4cd0c
@ -185,6 +185,14 @@ func (r *Reader) NextPart() (*Part, error) {
|
||||
expectNewPart := false
|
||||
for {
|
||||
line, err := r.bufReader.ReadSlice('\n')
|
||||
if err == io.EOF && bytes.Equal(line, r.dashBoundaryDash) {
|
||||
// If the buffer ends in "--boundary--" without the
|
||||
// trailing "\r\n", ReadSlice will return an error
|
||||
// (since it's missing the '\n'), but this is a valid
|
||||
// multipart EOF so we need to return io.EOF instead of
|
||||
// a fmt-wrapped one.
|
||||
return nil, io.EOF
|
||||
}
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("multipart: NextPart: %v", err)
|
||||
}
|
||||
|
@ -10,6 +10,7 @@ import (
|
||||
"fmt"
|
||||
"io"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"strings"
|
||||
"testing"
|
||||
)
|
||||
@ -377,3 +378,52 @@ func TestLineContinuation(t *testing.T) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test parsing an image attachment from gmail, which previously failed.
|
||||
func TestNested(t *testing.T) {
|
||||
// nested-mime is the body part of a multipart/mixed email
|
||||
// with boundary e89a8ff1c1e83553e304be640612
|
||||
f, err := os.Open("testdata/nested-mime")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer f.Close()
|
||||
mr := NewReader(f, "e89a8ff1c1e83553e304be640612")
|
||||
p, err := mr.NextPart()
|
||||
if err != nil {
|
||||
t.Fatalf("error reading first section (alternative): %v", err)
|
||||
}
|
||||
|
||||
// Read the inner text/plain and text/html sections of the multipart/alternative.
|
||||
mr2 := NewReader(p, "e89a8ff1c1e83553e004be640610")
|
||||
p, err = mr2.NextPart()
|
||||
if err != nil {
|
||||
t.Fatalf("reading text/plain part: %v", err)
|
||||
}
|
||||
if b, err := ioutil.ReadAll(p); string(b) != "*body*\r\n" || err != nil {
|
||||
t.Fatalf("reading text/plain part: got %q, %v", b, err)
|
||||
}
|
||||
p, err = mr2.NextPart()
|
||||
if err != nil {
|
||||
t.Fatalf("reading text/html part: %v", err)
|
||||
}
|
||||
if b, err := ioutil.ReadAll(p); string(b) != "<b>body</b>\r\n" || err != nil {
|
||||
t.Fatalf("reading text/html part: got %q, %v", b, err)
|
||||
}
|
||||
|
||||
p, err = mr2.NextPart()
|
||||
if err != io.EOF {
|
||||
t.Fatalf("final inner NextPart = %v; want io.EOF", err)
|
||||
}
|
||||
|
||||
// Back to the outer multipart/mixed, reading the image attachment.
|
||||
_, err = mr.NextPart()
|
||||
if err != nil {
|
||||
t.Fatalf("error reading the image attachment at the end: %v", err)
|
||||
}
|
||||
|
||||
_, err = mr.NextPart()
|
||||
if err != io.EOF {
|
||||
t.Fatalf("final outer NextPart = %v; want io.EOF", err)
|
||||
}
|
||||
}
|
||||
|
29
src/pkg/mime/multipart/testdata/nested-mime
vendored
Executable file
29
src/pkg/mime/multipart/testdata/nested-mime
vendored
Executable file
@ -0,0 +1,29 @@
|
||||
--e89a8ff1c1e83553e304be640612
|
||||
Content-Type: multipart/alternative; boundary=e89a8ff1c1e83553e004be640610
|
||||
|
||||
--e89a8ff1c1e83553e004be640610
|
||||
Content-Type: text/plain; charset=UTF-8
|
||||
|
||||
*body*
|
||||
|
||||
--e89a8ff1c1e83553e004be640610
|
||||
Content-Type: text/html; charset=UTF-8
|
||||
|
||||
<b>body</b>
|
||||
|
||||
--e89a8ff1c1e83553e004be640610--
|
||||
--e89a8ff1c1e83553e304be640612
|
||||
Content-Type: image/png; name="x.png"
|
||||
Content-Disposition: attachment;
|
||||
filename="x.png"
|
||||
Content-Transfer-Encoding: base64
|
||||
X-Attachment-Id: f_h1edgigu0
|
||||
|
||||
iVBORw0KGgoAAAANSUhEUgAAAagAAADrCAIAAACza5XhAAAKMWlDQ1BJQ0MgUHJvZmlsZQAASImd
|
||||
lndUU9kWh8+9N71QkhCKlNBraFICSA29SJEuKjEJEErAkAAiNkRUcERRkaYIMijggKNDkbEiioUB
|
||||
8b2kqeGaj4aTNftesu5mob4pr07ecMywRwLBvDCJOksqlUyldAZD7g9fxIZRWWPMvXRNJROJRBIG
|
||||
Y7Vx0mva1HAwYqibdKONXye3dW4iUonhWFJnqK7OaanU1gGkErFYEgaj0cg8wK+zVPh2ziwnHy07
|
||||
U8lYTNapezSzOuevRwLB7CFkqQQCwaJDiBQIBIJFhwh8AoFg0SHUqQUCASRJKkwkhMy/JfODWPEJ
|
||||
BIJFhwh8AoFg0TFnQqQ55GtPFopcJsN97e1nYtNuIBYeGBgYCmYrmE3jZ05iaGAoMX0xzxkWz6Hv
|
||||
yO7WvrlwzA0uLzrD+VkKqViwl9IfTBVNFMyc/x9alloiPPlqhQAAAABJRU5ErkJggg==
|
||||
--e89a8ff1c1e83553e304be640612--
|
Loading…
Reference in New Issue
Block a user