// and the caller has verified already that bytes.HasPrefix(buf, prefix) is true.
//
// matchAfterPrefix returns +1 if the buffer does match the boundary,
-// meaning the prefix is followed by a dash, space, tab, cr, nl, or end of input.
+// meaning the prefix is followed by a double dash, space, tab, cr, nl,
+// or end of input.
// It returns -1 if the buffer definitely does NOT match the boundary,
// meaning the prefix is followed by some other character.
// For example, "--foobar" does not match "--foo".
return 0
}
c := buf[len(prefix)]
- if c == ' ' || c == '\t' || c == '\r' || c == '\n' || c == '-' {
+
+ if c == ' ' || c == '\t' || c == '\r' || c == '\n' {
return +1
}
+
+ // Try to detect boundaryDash
+ if c == '-' {
+ if len(buf) == len(prefix)+1 {
+ if readErr != nil {
+ // Prefix + "-" does not match
+ return -1
+ }
+ return 0
+ }
+ if buf[len(prefix)+1] == '-' {
+ return +1
+ }
+ }
+
return -1
}
}
func TestMultipartTruncated(t *testing.T) {
- testBody := `
+ for _, body := range []string{
+ `
This is a multi-part message. This line is ignored.
--MyBoundary
foo-bar: baz
Oh no, premature EOF!
-`
- body := strings.ReplaceAll(testBody, "\n", "\r\n")
- bodyReader := strings.NewReader(body)
- r := NewReader(bodyReader, "MyBoundary")
+`,
+ `
+This is a multi-part message. This line is ignored.
+--MyBoundary
+foo-bar: baz
- part, err := r.NextPart()
- if err != nil {
- t.Fatalf("didn't get a part")
- }
- _, err = io.Copy(io.Discard, part)
- if err != io.ErrUnexpectedEOF {
- t.Fatalf("expected error io.ErrUnexpectedEOF; got %v", err)
+Oh no, premature EOF!
+--MyBoundary-`,
+ } {
+ body = strings.ReplaceAll(body, "\n", "\r\n")
+ bodyReader := strings.NewReader(body)
+ r := NewReader(bodyReader, "MyBoundary")
+
+ part, err := r.NextPart()
+ if err != nil {
+ t.Fatalf("didn't get a part")
+ }
+ _, err = io.Copy(io.Discard, part)
+ if err != io.ErrUnexpectedEOF {
+ t.Fatalf("expected error io.ErrUnexpectedEOF; got %v", err)
+ }
}
}
},
},
},
+
// Issue 12662: Check that we don't consume the leading \r if the peekBuffer
// ends in '\r\n--separator-'
{
},
},
},
+
// Issue 12662: Same test as above with \r\n at the end
{
name: "peek buffer boundary condition",
},
},
},
+
// Issue 12662v2: We want to make sure that for short buffers that end with
// '\r\n--separator-' we always consume at least one (valid) symbol from the
// peekBuffer
},
},
},
+
// Context: https://github.com/camlistore/camlistore/issues/642
// If the file contents in the form happens to have a size such as:
// size = peekBufferSize - (len("\n--") + len(boundary) + len("\r") + 1), (modulo peekBufferSize)
},
},
+ // Issue 46042; a nested multipart uses the outer separator followed by
+ // a dash.
+ {
+ name: "nested separator prefix is outer separator followed by a dash",
+ sep: "foo",
+ in: strings.Replace(`--foo
+Content-Type: multipart/alternative; boundary="foo-bar"
+
+--foo-bar
+
+Body
+--foo-bar
+
+Body2
+--foo-bar--
+--foo--`, "\n", "\r\n", -1),
+ want: []headerBody{
+ {textproto.MIMEHeader{"Content-Type": {`multipart/alternative; boundary="foo-bar"`}},
+ strings.Replace(`--foo-bar
+
+Body
+--foo-bar
+
+Body2
+--foo-bar--`, "\n", "\r\n", -1),
+ },
+ },
+ },
+
+ // A nested boundary cannot be the outer separator followed by double dash.
+ {
+ name: "nested separator prefix is outer separator followed by double dash",
+ sep: "foo",
+ in: strings.Replace(`--foo
+Content-Type: multipart/alternative; boundary="foo--"
+
+--foo--
+
+Body
+
+--foo--`, "\n", "\r\n", -1),
+ want: []headerBody{
+ {textproto.MIMEHeader{"Content-Type": {`multipart/alternative; boundary="foo--"`}}, ""},
+ },
+ },
+
roundTripParseTest(),
}