From 575de93dd395481abeaf9427e04fc83b758dec0e Mon Sep 17 00:00:00 2001 From: Brad Fitzpatrick Date: Mon, 10 Dec 2012 16:30:42 -0500 Subject: [PATCH] mime/multipart: allow setting the Writer boundary Fixes #4490 R=golang-dev, rsc CC=golang-dev https://golang.org/cl/6924044 --- src/pkg/mime/multipart/writer.go | 29 +++++++++++++++++++++- src/pkg/mime/multipart/writer_test.go | 35 +++++++++++++++++++++++++++ 2 files changed, 63 insertions(+), 1 deletion(-) diff --git a/src/pkg/mime/multipart/writer.go b/src/pkg/mime/multipart/writer.go index ec70be492f..e13a956afe 100644 --- a/src/pkg/mime/multipart/writer.go +++ b/src/pkg/mime/multipart/writer.go @@ -30,11 +30,38 @@ func NewWriter(w io.Writer) *Writer { } } -// Boundary returns the Writer's randomly selected boundary string. +// Boundary returns the Writer's boundary. func (w *Writer) Boundary() string { return w.boundary } +// SetBoundary overrides the Writer's default randomly-generated +// boundary separator with an explicit value. +// +// SetBoundary must be called before any parts are created, may only +// contain certain ASCII characters, and must be 1-69 bytes long. +func (w *Writer) SetBoundary(boundary string) error { + if w.lastpart != nil { + return errors.New("mime: SetBoundary called after write") + } + // rfc2046#section-5.1.1 + if len(boundary) < 1 || len(boundary) > 69 { + return errors.New("mime: invalid boundary length") + } + for _, b := range boundary { + if 'A' <= b && b <= 'Z' || 'a' <= b && b <= 'z' || '0' <= b && b <= '9' { + continue + } + switch b { + case '\'', '(', ')', '+', '_', ',', '-', '.', '/', ':', '=', '?': + continue + } + return errors.New("mime: invalid boundary character") + } + w.boundary = boundary + return nil +} + // FormDataContentType returns the Content-Type for an HTTP // multipart/form-data with this Writer's Boundary. func (w *Writer) FormDataContentType() string { diff --git a/src/pkg/mime/multipart/writer_test.go b/src/pkg/mime/multipart/writer_test.go index 494e936c4c..52d68bcb68 100644 --- a/src/pkg/mime/multipart/writer_test.go +++ b/src/pkg/mime/multipart/writer_test.go @@ -7,6 +7,7 @@ package multipart import ( "bytes" "io/ioutil" + "strings" "testing" ) @@ -76,3 +77,37 @@ func TestWriter(t *testing.T) { t.Fatalf("expected end of parts; got %v, %v", part, err) } } + +func TestWriterSetBoundary(t *testing.T) { + var b bytes.Buffer + w := NewWriter(&b) + tests := []struct { + b string + ok bool + }{ + {"abc", true}, + {"", false}, + {"ungültig", false}, + {"!", false}, + {strings.Repeat("x", 69), true}, + {strings.Repeat("x", 70), false}, + {"bad!ascii!", false}, + {"my-separator", true}, + } + for i, tt := range tests { + err := w.SetBoundary(tt.b) + got := err == nil + if got != tt.ok { + t.Errorf("%d. boundary %q = %v (%v); want %v", i, tt.b, got, err, tt.ok) + } else if tt.ok { + got := w.Boundary() + if got != tt.b { + t.Errorf("boundary = %q; want %q", got, tt.b) + } + } + } + w.Close() + if got := b.String(); !strings.Contains(got, "\r\n--my-separator--\r\n") { + t.Errorf("expected my-separator in output. got: %q", got) + } +} -- 2.48.1