Skip to content

Commit 64ceae7

Browse files
authored
Handle consecutive multipart boundaries (#6)
1 parent 1d7742d commit 64ceae7

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

textproto/multipart.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,13 @@ func newPart(mr *MultipartReader) (*Part, error) {
8484
}
8585

8686
func (bp *Part) populateHeaders() error {
87+
// If there are consecutive boundaries, just return an empty header.
88+
peek, _ := bp.mr.bufReader.Peek(len(bp.mr.dashBoundary))
89+
if bytes.HasPrefix(peek, bp.mr.dashBoundary) {
90+
bp.Header = Header{}
91+
return nil
92+
}
93+
8794
header, err := ReadHeader(bp.mr.bufReader)
8895
if err == nil {
8996
bp.Header = header

textproto/multipart_test.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -760,6 +760,30 @@ val
760760
},
761761
},
762762

763+
// Two consecutive boundaries - represents an empty part between them
764+
{
765+
name: "two consecutive boundaries",
766+
sep: "gc0p4Jq0M2Yt08jU534c0p",
767+
in: "--gc0p4Jq0M2Yt08jU534c0p\r\nContent-Type: text/plain\r\n\r\nfirst part\r\n--gc0p4Jq0M2Yt08jU534c0p\r\n--gc0p4Jq0M2Yt08jU534c0p\r\nContent-Type: text/html\r\n\r\nlast part\r\n--gc0p4Jq0M2Yt08jU534c0p--",
768+
want: []headerBody{
769+
{textproto.MIMEHeader{"Content-Type": {"text/plain"}}, "first part"},
770+
{textproto.MIMEHeader{}, ""}, // Empty part from consecutive boundaries
771+
{textproto.MIMEHeader{"Content-Type": {"text/html"}}, "last part"},
772+
},
773+
},
774+
775+
// Three consecutive boundaries - represents two empty parts
776+
{
777+
name: "three consecutive boundaries",
778+
sep: "gc0p4Jq0M2Yt08jU534c0p",
779+
in: "--gc0p4Jq0M2Yt08jU534c0p\r\n--gc0p4Jq0M2Yt08jU534c0p\r\n--gc0p4Jq0M2Yt08jU534c0p\r\nContent-Type: text/plain\r\n\r\nfinal part body\r\n--gc0p4Jq0M2Yt08jU534c0p--",
780+
want: []headerBody{
781+
{textproto.MIMEHeader{}, ""}, // First empty part
782+
{textproto.MIMEHeader{}, ""}, // Second empty part
783+
{textproto.MIMEHeader{"Content-Type": {"text/plain"}}, "final part body"},
784+
},
785+
},
786+
763787
roundTripParseTest(),
764788
}
765789

@@ -853,3 +877,14 @@ func TestNoBoundary(t *testing.T) {
853877
t.Errorf("NextPart error = %v; want %v", got, want)
854878
}
855879
}
880+
881+
func TestInvalidLineAfterBoundary(t *testing.T) {
882+
testBody := "--MyBoundary\r\nThis is not a valid header line\r\n"
883+
bodyReader := strings.NewReader(testBody)
884+
reader := NewMultipartReader(bodyReader, "MyBoundary")
885+
_, err := reader.NextPart()
886+
887+
if err == nil {
888+
t.Error("Expected an error when parsing invalid line after boundary, got nil")
889+
}
890+
}

0 commit comments

Comments
 (0)