From e45b3213cd6e8d7f983b63edd1785b12e7ce66ec Mon Sep 17 00:00:00 2001 From: Evan Martin Date: Sat, 9 Jul 2011 15:18:31 -0700 Subject: [PATCH] multipart: use textproto to handle multiline header R=bradfitz CC=golang-dev https://golang.org/cl/4686044 --- src/pkg/mime/multipart/multipart.go | 23 +++++---------------- src/pkg/mime/multipart/multipart_test.go | 26 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/pkg/mime/multipart/multipart.go b/src/pkg/mime/multipart/multipart.go index 4711fd78ba..630aaf5ed2 100644 --- a/src/pkg/mime/multipart/multipart.go +++ b/src/pkg/mime/multipart/multipart.go @@ -21,7 +21,6 @@ import ( "mime" "net/textproto" "os" - "regexp" ) // TODO(bradfitz): inline these once the compiler can inline them in @@ -29,8 +28,6 @@ import ( var lf = []byte("\n") var crlf = []byte("\r\n") -var headerRegexp *regexp.Regexp = regexp.MustCompile("^([a-zA-Z0-9\\-]+): *([^\r\n]+)") - var emptyParams = make(map[string]string) // A Part represents a single part in a multipart body. @@ -106,22 +103,12 @@ func newPart(mr *Reader) (*Part, os.Error) { } func (bp *Part) populateHeaders() os.Error { - for { - lineBytes, err := bp.mr.bufReader.ReadSlice('\n') - if err != nil { - return err - } - line := string(lineBytes) - if line == "\n" || line == "\r\n" { - return nil - } - if matches := headerRegexp.FindStringSubmatch(line); len(matches) == 3 { - bp.Header.Add(matches[1], matches[2]) - continue - } - return os.NewError("Unexpected header line found parsing multipart body") + r := textproto.NewReader(bp.mr.bufReader) + header, err := r.ReadMIMEHeader() + if err == nil { + bp.Header = header } - panic("unreachable") + return err } // Read reads the body of a part, after its headers and before the diff --git a/src/pkg/mime/multipart/multipart_test.go b/src/pkg/mime/multipart/multipart_test.go index 1357466acd..3f3b8b1a0e 100644 --- a/src/pkg/mime/multipart/multipart_test.go +++ b/src/pkg/mime/multipart/multipart_test.go @@ -352,3 +352,29 @@ func (s *slowReader) Read(p []byte) (int, os.Error) { } return s.r.Read(p[:1]) } + +func TestLineContinuation(t *testing.T) { + // This body, extracted from an email, contains headers that span multiple + // lines. + + // TODO: The original mail ended with a double-newline before the + // final delimiter; this was manually edited to use a CRLF. + testBody := + "\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: 7bit\nContent-Type: text/plain;\n\tcharset=US-ASCII;\n\tdelsp=yes;\n\tformat=flowed\n\nI'm finding the same thing happening on my system (10.4.1).\n\n\n--Apple-Mail-2-292336769\nContent-Transfer-Encoding: quoted-printable\nContent-Type: text/html;\n\tcharset=ISO-8859-1\n\nI'm finding the same thing =\nhappening on my system (10.4.1).=A0 But I built it with XCode =\n2.0.=\n\r\n--Apple-Mail-2-292336769--\n" + + r := NewReader(strings.NewReader(testBody), "Apple-Mail-2-292336769") + + for i := 0; i < 2; i++ { + part, err := r.NextPart() + if err != nil { + t.Fatalf("didn't get a part") + } + n, err := io.Copy(ioutil.Discard, part) + if err != nil { + t.Errorf("error reading part: %v", err) + } + if n <= 0 { + t.Errorf("read %d bytes; expected >0", n) + } + } +} -- 2.50.0