Repository: jhillyerd/enmime (go)

Issue:
Content-Type with option charset="utf-8" confuses parser
What I did:

Parse envelope with text/plain part of email body in standard UTF-8, but the Content-Type option specifies:

`'text/plain; charset="utf-8"'`

and also the same for the HTML alternative.

I.E lower case.

What I expected:

Parser realizes that utf-8 == UTF-8

What I got:

![image](https://user-images.githubusercontent.com/1309104/127764162-71b9086d-a6cc-4ac7-81d9-f03d5903da6f.png)
![image](https://user-images.githubusercontent.com/1309104/127764223-74e9a746-8233-4d31-913d-ea92bf6186b4.png)


Release or branch I am using:

	github.com/jhillyerd/enmime v0.9.0

(Please attach a sample message if you feel it will help reproduce the issue)

Unfortunately, the email isnon-public, but this is easily reproducible by adding the charset option to any email.


Pull request description:
header: Do not preserve param value unquoted leading whitespace
Fixes #204


Patch:
diff --git a/header.go b/header.go
index b83301e..623f2ca 100644
--- a/header.go
+++ b/header.go
@@ -366,7 +366,7 @@ findValueStart:
 	for i, r = range s {
 		switch r {
 		case ' ', '\t':
-			param.WriteRune(r)
+			// Do not preserve leading whitespace.
 
 		case '"':
 			valueQuotedOriginally = true
@@ -412,10 +412,8 @@ findValueStart:
 		// parameter value starts at the end of the string, make empty
 		// quoted string to play nice with mime.ParseMediaType
 		param.WriteString(`""`)
-
 	} else {
 		// The beginning of the value is not at the end of the string
-
 		for _, v := range []byte{'(', ')', '<', '>', '@', ',', ':', '/', '[', ']', '?', '='} {
 			if s[0] == v {
 				quoteIfUnquoted()


Test patch:
diff --git a/header_test.go b/header_test.go
index 3973dbc..09e1418 100644
--- a/header_test.go
+++ b/header_test.go
@@ -328,12 +328,14 @@ func TestFixUnquotedSpecials(t *testing.T) {
 			want:  "application/octet-stream; param1=\"value\\\"1\\\"\"",
 		},
 		{
+			// Do not preserve unqoted whitespace.
 			input: "application/octet-stream; param1= value1",
-			want:  "application/octet-stream; param1= value1",
+			want:  "application/octet-stream; param1=value1",
 		},
 		{
+			// Do not preserve unqoted whitespace.
 			input: "application/octet-stream; param1=\tvalue1",
-			want:  "application/octet-stream; param1=\tvalue1",
+			want:  "application/octet-stream; param1=value1",
 		},
 		{
 			input: "application/octet-stream; param1=\"value1;\"",
@@ -348,6 +350,17 @@ func TestFixUnquotedSpecials(t *testing.T) {
 			want:  "application/octet-stream; param1=\"value 1\"",
 		},
 		{
+			// Preserve quoted whitespace.
+			input: "application/octet-stream; param1=\" value 1\"",
+			want:  "application/octet-stream; param1=\" value 1\"",
+		},
+		{
+			// Preserve quoted whitespace.
+			input: "application/octet-stream; param1=\"\tvalue 1\"",
+			want:  "application/octet-stream; param1=\"\tvalue 1\"",
+		},
+		{
+			// Preserve quoted whitespace.
 			input: "application/octet-stream; param1=\"value\t1\"",
 			want:  "application/octet-stream; param1=\"value\t1\"",
 		},
@@ -835,7 +848,19 @@ func TestParseMediaType(t *testing.T) {
 			params: map[string]string{"name": "index;a.html", "hash": "8675309"},
 		},
 		{
-			label:  "with whitespace",
+			label:  "with prefix whitespace",
+			input:  "text/plain; charset= \"UTF-8\"; format=flowed",
+			mtype:  "text/plain",
+			params: map[string]string{"charset": "UTF-8", "format": "flowed"},
+		},
+		{
+			label:  "with double prefix whitespace",
+			input:  "text/plain; charset = \"UTF-8\"; format=flowed",
+			mtype:  "text/plain",
+			params: map[string]string{"charset": "UTF-8", "format": "flowed"},
+		},
+		{
+			label:  "with postfix whitespace",
 			input:  "text/plain; charset=\"UTF-8\" ; format=flowed",
 			mtype:  "text/plain",
 			params: map[string]string{"charset": "UTF-8", "format": "flowed"},