mirror of
https://github.com/golang/go
synced 2024-11-15 10:50:37 -07:00
[release-branch.go1] mime/multipart: report io.EOF correctly on part ending without newlines
««« backport 4ecca118488b 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
c619931610
commit
b4ea696b49
@ -185,6 +185,14 @@ func (r *Reader) NextPart() (*Part, error) {
|
|||||||
expectNewPart := false
|
expectNewPart := false
|
||||||
for {
|
for {
|
||||||
line, err := r.bufReader.ReadSlice('\n')
|
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 {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("multipart: NextPart: %v", err)
|
return nil, fmt.Errorf("multipart: NextPart: %v", err)
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"io/ioutil"
|
"io/ioutil"
|
||||||
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"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