Skip to content

Commit

Permalink
Implementation which does not depend on successive function calls (#121)
Browse files Browse the repository at this point in the history
* Refactor rfc2047AttributeName to handle n-number of occurrences and appropriately manage quoting the final parameter value

* Check for missing token after slash, apply defaults if true
  • Loading branch information
requaos authored and jhillyerd committed Jan 28, 2019
1 parent afba0dd commit 8df923e
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 17 deletions.
77 changes: 62 additions & 15 deletions header.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ const (
cdInline = "inline"

// Standard MIME content types
ctAppPrefix = "application/"
ctAppOctetStream = "application/octet-stream"
ctMultipartAltern = "multipart/alternative"
ctMultipartMixed = "multipart/mixed"
ctMultipartPrefix = "multipart/"
ctMultipartRelated = "multipart/related"
ctTextPrefix = "text/"
ctTextPlain = "text/plain"
ctTextHTML = "text/html"

Expand Down Expand Up @@ -269,6 +271,20 @@ func fixMangledMediaType(mtype, sep string) string {
// The content type is completely missing. Put in a placeholder.
p = ctPlaceholder
}
// Check for missing token after slash
if strings.HasSuffix(p, "/") {
switch p {
case ctTextPrefix:
p = ctTextPlain
case ctAppPrefix:
p = ctAppOctetStream
case ctMultipartPrefix:
p = ctMultipartMixed
default:
// Safe default
p = ctAppOctetStream
}
}
default:
if !strings.Contains(p, "=") {
p = p + "=" + pvPlaceholder
Expand All @@ -277,8 +293,8 @@ func fixMangledMediaType(mtype, sep string) string {
// RFC-2047 encoded attribute name
p = rfc2047AttributeName(p)

pair := strings.Split(p, "=")
if strings.Contains(mtype, pair[0]+"=") {
pair := strings.SplitAfter(p, "=")
if strings.Contains(mtype, pair[0]) {
// Ignore repeated parameters.
continue
}
Expand Down Expand Up @@ -505,20 +521,51 @@ func whiteSpaceRune(r rune) bool {
// rfc2047AttributeName checks if the attribute name is encoded in RFC2047 format
// RFC2047 Example:
// `=?UTF-8?B?bmFtZT0iw7DCn8KUwoo=?=`
func rfc2047AttributeName(s string) string {
if !strings.Contains(s, "?=") {
return s
func rfc2047AttributeName(name string) string {
if !strings.Contains(name, "?=") {
return name
}
pair := strings.SplitAfter(s, "?=")
// lets assume that the attribute was encoded because of unicode characters being present
// then the attribute value should be quoted
keyValuePair := strings.SplitAfter(decodeHeader(pair[0]), "=")
// only quote the parameter value if it isn't already quoted
if len(keyValuePair) > 1 {
if !strings.HasPrefix(keyValuePair[1], "\"") {
keyValuePair[1] = fmt.Sprintf("\"%s", keyValuePair[1])
// copy the string so we can return the original if we encounter any issues
s := name

// handle n-number of RFC2047 chunk occurrences
count := strings.Count(name, "?=")
result := &strings.Builder{}
var beginning, ending int
for i := 0; i < count; i++ {
beginning = strings.Index(s, "=?")
ending = strings.Index(s, "?=")

if beginning == -1 || ending == -1 {
// the RFC2047 chunk is either malformed or is not an RFC2047 chunk
return name
}

_, err := result.WriteString(s[:beginning])
if err != nil {
return name
}
_, err = result.WriteString(decodeHeader(s[beginning : ending+2]))
if err != nil {
return name
}

s = s[ending+2:]
}
_, err := result.WriteString(s)
if err != nil {
return name
}
keyValuePair := strings.SplitAfter(result.String(), "=")
if len(keyValuePair) < 2 {
return result.String()
}
// Add quotes as needed
if !strings.HasPrefix(keyValuePair[1], "\"") {
keyValuePair[1] = fmt.Sprintf("\"%s", keyValuePair[1])
}
if !strings.HasSuffix(keyValuePair[1], "\"") {
keyValuePair[1] = fmt.Sprintf("%s\"", keyValuePair[1])
}
pair[0] = strings.Join(keyValuePair, "")
return strings.Join(pair, "")
return strings.Join(keyValuePair, "")
}
9 changes: 7 additions & 2 deletions header_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,12 @@ func TestFixMangledMediaType(t *testing.T) {
{
input: "application/octet-stream;=?UTF-8?B?bmFtZT0iw7DCn8KUwoo=?=You've got a new voice miss call.msg",
sep: ";",
want: "application/octet-stream;name=\"ð\u009f\u0094\u008aYou've got a new voice miss call.msg",
want: "application/octet-stream;name=\"ð\u009f\u0094\u008aYou've got a new voice miss call.msg\"",
},
{
input: "application/; name=\"Voice message from =?UTF-8?B?4piOICsxIDI1MS0yNDUtODA0NC5tc2c=?=\";",
sep: ";",
want: "application/octet-stream; name=\"Voice message from ☎ +1 251-245-8044.msg\"",
},
{
input: "application/pdf name=\"file.pdf\"",
Expand All @@ -197,7 +202,7 @@ func TestFixMangledMediaType(t *testing.T) {
{
input: "application/octet-stream; =?UTF-8?B?bmFtZT3DsMKfwpTCii5tc2c=?=",
sep: " ",
want: "application/octet-stream;name=\"🔊.msg",
want: "application/octet-stream;name=\"🔊.msg\"",
},
{
input: "one/two name=\"file.two\" name=\"file.two\"",
Expand Down

0 comments on commit 8df923e

Please sign in to comment.