diff --git a/internal/multipart/component.go b/internal/multipart/component.go index 8acc47f..5f74ef4 100644 --- a/internal/multipart/component.go +++ b/internal/multipart/component.go @@ -16,13 +16,12 @@ func (comp *Component) parseHeaders(_raw []byte) error { } // 2. trim each line + remove 'Content-Disposition' prefix - trimmed := strings.Trim(_lines[0], " \t") - header := trimmed + header := strings.Trim(_lines[0], " \t\r") - if !strings.HasPrefix(trimmed, "Content-Disposition: form-data;") { + if !strings.HasPrefix(header, "Content-Disposition: form-data;") { return ErrNoHeader } - header = strings.Trim(trimmed[len("Content-Disposition: form-data;"):], " \t") + header = strings.Trim(header[len("Content-Disposition: form-data;"):], " \t\r") if len(header) < 1 { return ErrNoHeader @@ -53,7 +52,7 @@ func (comp *Component) parseHeaders(_raw []byte) error { for _, l := range _lines[1:] { if strings.HasPrefix(l, "Content-Type: ") { - comp.ContentType = strings.Trim(l[len("Content-Type: "):], " \t") + comp.ContentType = strings.Trim(l[len("Content-Type: "):], " \t\r") break } @@ -89,8 +88,9 @@ func (comp *Component) read(_reader *bufio.Reader, _boundary string) error { // remove last CR (newline) if strings.HasSuffix(string(comp.Data), "\n") { comp.Data = comp.Data[0 : len(comp.Data)-1] - } else if strings.HasSuffix(string(comp.Data), "\r\n") { - comp.Data = comp.Data[0 : len(comp.Data)-2] + } + if strings.HasSuffix(string(comp.Data), "\r") { + comp.Data = comp.Data[0 : len(comp.Data)-1] } return err } @@ -101,8 +101,9 @@ func (comp *Component) read(_reader *bufio.Reader, _boundary string) error { // remove last CR (newline) if strings.HasSuffix(string(comp.Data), "\n") { comp.Data = comp.Data[0 : len(comp.Data)-1] - } else if strings.HasSuffix(string(comp.Data), "\r\n") { - comp.Data = comp.Data[0 : len(comp.Data)-2] + } + if strings.HasSuffix(string(comp.Data), "\r") { + comp.Data = comp.Data[0 : len(comp.Data)-1] } // io.EOF if last boundary diff --git a/internal/multipart/reader_test.go b/internal/multipart/reader_test.go index 641a10b..f1c385e 100644 --- a/internal/multipart/reader_test.go +++ b/internal/multipart/reader_test.go @@ -9,7 +9,6 @@ func TestSimple(t *testing.T) { test := struct { Input []byte Boundary string - Length int }{ Input: []byte(`--BoUnDaRy Content-Disposition: form-data; name="somevar" @@ -70,6 +69,87 @@ facebook.com } +func TestSimpleWithCRLF(t *testing.T) { + + type tcase struct { + Input []byte + Boundary string + } + _test := tcase{ + Input: []byte(`--BoUnDaRy +Content-Disposition: form-data; name="somevar" + +google.com +--BoUnDaRy +Content-Disposition: form-data; name="somefile"; filename="somefilename.pdf" +Content-Type: application/pdf + +facebook.com +--BoUnDaRy--`), + Boundary: "BoUnDaRy", + } + + test := tcase{ + Input: make([]byte, 0), + Boundary: _test.Boundary, + } + + // replace all \n with \r\n + for _, char := range _test.Input { + if char == '\n' { + test.Input = append(test.Input, []byte("\r\n")...) + continue + } + + test.Input = append(test.Input, char) + } + + mpr, err := NewReader(bytes.NewReader(test.Input), test.Boundary) + + if err != nil { + t.Fatalf("Unexpected error <%s>", err) + } + + if err = mpr.Parse(); err != nil { + t.Fatalf("Unexpected error <%s>", err) + } + + // 1. Check var + somevar := mpr.Get("somevar") + if somevar == nil { + t.Fatalf("Expected data {%s} to exist", "somevar") + } + if somevar.ContentType != "raw" { + t.Fatalf("Expected ContentType to be {raw}, got {%s}", somevar.ContentType) + } + + if string(somevar.Data) != "google.com" { + t.Fatalf("Expected data to be {%s}, got {%s}", "google.com", somevar.Data) + } + + // 2. Check file + somefile := mpr.Get("somefile") + if somefile == nil { + t.Fatalf("Expected data {%s} to exist", "somefile") + } + if somefile.ContentType != "application/pdf" { + t.Fatalf("Expected ContentType to be {application/pdf}, got {%s}", somevar.ContentType) + } + + if string(somefile.Data) != "facebook.com" { + t.Fatalf("Expected data to be {%s}, got {%s}", "facebook.com", somefile.Data) + } + + filename := somefile.GetHeader("filename") + if len(filename) < 1 { + t.Fatalf("Expected data to have header 'filename'") + } + if filename != "somefilename.pdf" { + t.Fatalf("Expected filename to be {%s}, got {%s}", "somefilename.pdf", filename) + } + +} + func TestNoName(t *testing.T) { tests := []struct { Input []byte