Commit 28c20186 authored by Simon Thulbourn's avatar Simon Thulbourn Committed by Brad Fitzpatrick

mime/multipart: sort header keys to ensure reproducible output

Adds a transparent sort to the mime/multipart package, which is
only used in the CreatePart func. This will ensure the ordering
of the MIMEHeader.

The point of this change was to ensure the output would be consistent
and something that could be depended on.

Fixes #13522

Change-Id: I9584ef9dbe98ce97d536d897326914653f8d9ddf
Reviewed-on: https://go-review.googlesource.com/17497Reviewed-by: default avatarBrad Fitzpatrick <bradfitz@golang.org>
parent 99ef42fe
...@@ -11,6 +11,7 @@ import ( ...@@ -11,6 +11,7 @@ import (
"fmt" "fmt"
"io" "io"
"net/textproto" "net/textproto"
"sort"
"strings" "strings"
) )
...@@ -94,10 +95,14 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) { ...@@ -94,10 +95,14 @@ func (w *Writer) CreatePart(header textproto.MIMEHeader) (io.Writer, error) {
} else { } else {
fmt.Fprintf(&b, "--%s\r\n", w.boundary) fmt.Fprintf(&b, "--%s\r\n", w.boundary)
} }
// TODO(bradfitz): move this to textproto.MimeHeader.Write(w), have it sort
// and clean, like http.Header.Write(w) does. keys := make([]string, 0, len(header))
for k, vv := range header { for k := range header {
for _, v := range vv { keys = append(keys, k)
}
sort.Strings(keys)
for _, k := range keys {
for _, v := range header[k] {
fmt.Fprintf(&b, "%s: %s\r\n", k, v) fmt.Fprintf(&b, "%s: %s\r\n", k, v)
} }
} }
......
...@@ -7,6 +7,7 @@ package multipart ...@@ -7,6 +7,7 @@ package multipart
import ( import (
"bytes" "bytes"
"io/ioutil" "io/ioutil"
"net/textproto"
"strings" "strings"
"testing" "testing"
) )
...@@ -126,3 +127,32 @@ func TestWriterBoundaryGoroutines(t *testing.T) { ...@@ -126,3 +127,32 @@ func TestWriterBoundaryGoroutines(t *testing.T) {
w.Boundary() w.Boundary()
<-done <-done
} }
func TestSortedHeader(t *testing.T) {
var buf bytes.Buffer
w := NewWriter(&buf)
if err := w.SetBoundary("MIMEBOUNDARY"); err != nil {
t.Fatalf("Error setting mime boundary: %v", err)
}
header := textproto.MIMEHeader{
"A": {"2"},
"B": {"5", "7", "6"},
"C": {"4"},
"M": {"3"},
"Z": {"1"},
}
part, err := w.CreatePart(header)
if err != nil {
t.Fatalf("Unable to create part: %v", err)
}
part.Write([]byte("foo"))
w.Close()
want := "--MIMEBOUNDARY\r\nA: 2\r\nB: 5\r\nB: 7\r\nB: 6\r\nC: 4\r\nM: 3\r\nZ: 1\r\n\r\nfoo\r\n--MIMEBOUNDARY--\r\n"
if want != buf.String() {
t.Fatalf("\n got: %q\nwant: %q\n", buf.String(), want)
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment