emersion / go-message

✉️ A streaming Go library for the Internet Message Format and mail messages
MIT License
382 stars 111 forks source link

proposal: mime: handling duplicate media parameters #140

Closed iredmail closed 2 years ago

iredmail commented 2 years ago

Dear all,

I recently experience an issue with duplicate parameter name in mail header:

Content-Type: multipart/alternative; boundary="----RTIR0GV26TDW15Q5CVX979LBL6XN18"; boundary="----RTIR0GV26TDW15Q5CVX979LBL6XN18"

go-message reports mime: duplicate parameter name.

It's actually a Go mime package "issue", there's a proposal to handle it, but not accepted due to Timed out in state WaitingForInfo: https://github.com/golang/go/issues/28618 Also an open one: https://github.com/golang/go/issues/47602

Since it's not that easy to push Go team to "fix" it, I wonder whether you're willing to handle this in header.go as a workaround: https://github.com/emersion/go-message/blob/master/header.go#L11

If it's ok to go, i'd like to send a PR for this. :)

Draft patch:

diff --git a/header.go b/header.go
index fb92dbb..4d76856 100644
--- a/header.go
+++ b/header.go
@@ -2,13 +2,42 @@ package message

 import (
    "mime"
+   "strings"

    "spider/external/go-message/textproto"
 )

+func removeDuplicateParam(s string) string {
+   var ns string
+   pkv := make(map[string]string)
+
+   // Use first parameter
+   parts := strings.Split(s, ";")
+   for _, p := range parts {
+       pp := strings.TrimSpace(p)
+       kv := strings.Split(pp, "=")
+
+       if len(kv) >= 2 {
+           if _, exists := pkv[kv[0]]; exists {
+               continue
+           } else {
+               pkv[kv[0]] = kv[1]
+               ns += p + ";"
+           }
+       } else {
+           ns += p + ";"
+       }
+   }
+
+   return ns
+}
+
 func parseHeaderWithParams(s string) (f string, params map[string]string, err error) {
    f, params, err = mime.ParseMediaType(s)
    if err != nil {
+       if err.Error() == "mime: duplicate parameter name" {
+           s = removeDuplicateParam(s)
+           return mime.ParseMediaType(s)
+       }
        return s, nil, err
    }
    for k, v := range params {