From e52c9f205bba7449f41be70dc2e8ba51f558507e Mon Sep 17 00:00:00 2001 From: Julien Cretel Date: Fri, 19 Sep 2025 20:48:52 +0200 Subject: [PATCH 1/5] mime: use strings.CutPrefix where possible --- src/mime/mediatype.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 66684a68b23961..07670df9b7492d 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -103,10 +103,11 @@ func checkMediaTypeDisposition(s string) error { if rest == "" { return nil } - if !strings.HasPrefix(rest, "/") { + var ok bool + if rest, ok = strings.CutPrefix(rest, "/"); !ok { return errors.New("mime: expected slash after first token") } - subtype, rest := consumeToken(rest[1:]) + subtype, rest := consumeToken(rest) if subtype == "" { return errors.New("mime: expected token after slash") } @@ -309,11 +310,11 @@ func consumeValue(v string) (value, rest string) { func consumeMediaParam(v string) (param, value, rest string) { rest = strings.TrimLeftFunc(v, unicode.IsSpace) - if !strings.HasPrefix(rest, ";") { + var ok bool + if rest, ok = strings.CutPrefix(rest, ";"); !ok { return "", "", v } - rest = rest[1:] // consume semicolon rest = strings.TrimLeftFunc(rest, unicode.IsSpace) param, rest = consumeToken(rest) param = strings.ToLower(param) @@ -322,10 +323,9 @@ func consumeMediaParam(v string) (param, value, rest string) { } rest = strings.TrimLeftFunc(rest, unicode.IsSpace) - if !strings.HasPrefix(rest, "=") { + if rest, ok = strings.CutPrefix(rest, "="); !ok { return "", "", v } - rest = rest[1:] // consume equals sign rest = strings.TrimLeftFunc(rest, unicode.IsSpace) value, rest2 := consumeValue(rest) if value == "" && rest2 == rest { From e17a6d1442b03460c7aa358977d29a4cfac55a0b Mon Sep 17 00:00:00 2001 From: Julien Cretel Date: Fri, 19 Sep 2025 20:53:23 +0200 Subject: [PATCH 2/5] mime: replace percentHexUnescape's error result by a bool --- src/mime/mediatype.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 07670df9b7492d..4276130c9e31e4 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -244,8 +244,8 @@ func decode2231Enc(v string) (string, bool) { // TODO: unsupported encoding return "", false } - encv, err := percentHexUnescape(sv[2]) - if err != nil { + encv, ok := percentHexUnescape(sv[2]) + if !ok { return "", false } return encv, true @@ -335,7 +335,7 @@ func consumeMediaParam(v string) (param, value, rest string) { return param, value, rest } -func percentHexUnescape(s string) (string, error) { +func percentHexUnescape(s string) (string, bool) { // Count %, check that they're well-formed. percents := 0 for i := 0; i < len(s); { @@ -349,12 +349,12 @@ func percentHexUnescape(s string) (string, error) { if len(s) > 3 { s = s[0:3] } - return "", fmt.Errorf("mime: bogus characters after %%: %q", s) + return "", false } i += 3 } if percents == 0 { - return s, nil + return s, true } t := make([]byte, len(s)-2*percents) @@ -371,7 +371,7 @@ func percentHexUnescape(s string) (string, error) { i++ } } - return string(t), nil + return string(t), true } func ishex(c byte) bool { From 6fa63b03fbc844366976ec8eb2212f96d134d14b Mon Sep 17 00:00:00 2001 From: Julien Cretel Date: Sun, 21 Sep 2025 15:02:18 +0200 Subject: [PATCH 3/5] mime: remove useless code --- src/mime/mediatype.go | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 4276130c9e31e4..3551364b492df6 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -170,7 +170,6 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e if continuation == nil { continuation = make(map[string]map[string]string) } - var ok bool if pmap, ok = continuation[baseName]; !ok { continuation[baseName] = make(map[string]string) pmap = continuation[baseName] @@ -237,18 +236,13 @@ func decode2231Enc(v string) (string, bool) { // need to decide how to expose it in the API. But I'm not sure // anybody uses it in practice. charset := strings.ToLower(sv[0]) - if len(charset) == 0 { + switch charset { + case "us-ascii", "utf-8": + default: + // Empty or unsupported encoding. return "", false } - if charset != "us-ascii" && charset != "utf-8" { - // TODO: unsupported encoding - return "", false - } - encv, ok := percentHexUnescape(sv[2]) - if !ok { - return "", false - } - return encv, true + return percentHexUnescape(sv[2]) } // consumeToken consumes a token from the beginning of provided @@ -345,10 +339,6 @@ func percentHexUnescape(s string) (string, bool) { } percents++ if i+2 >= len(s) || !ishex(s[i+1]) || !ishex(s[i+2]) { - s = s[i:] - if len(s) > 3 { - s = s[0:3] - } return "", false } i += 3 From 75493d6b784f71418eb22eb1b6aa297b9ebd7549 Mon Sep 17 00:00:00 2001 From: Julien Cretel Date: Sun, 21 Sep 2025 15:45:26 +0200 Subject: [PATCH 4/5] mime: use strings.Cut instead of strings.SplitN --- src/mime/mediatype.go | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 3551364b492df6..2356530aa968c6 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -228,21 +228,25 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e } func decode2231Enc(v string) (string, bool) { - sv := strings.SplitN(v, "'", 3) - if len(sv) != 3 { + charset, v, ok := strings.Cut(v, "'") + if !ok { return "", false } - // TODO: ignoring lang in sv[1] for now. If anybody needs it we'll + // TODO: ignoring the language part for now. If anybody needs it, we'll // need to decide how to expose it in the API. But I'm not sure // anybody uses it in practice. - charset := strings.ToLower(sv[0]) + _, extOtherVals, ok := strings.Cut(v, "'") + if !ok { + return "", false + } + charset = strings.ToLower(charset) switch charset { case "us-ascii", "utf-8": default: // Empty or unsupported encoding. return "", false } - return percentHexUnescape(sv[2]) + return percentHexUnescape(extOtherVals) } // consumeToken consumes a token from the beginning of provided From c44e2a2577386d1d776498d29e31821326e20b92 Mon Sep 17 00:00:00 2001 From: Julien Cretel Date: Sun, 21 Sep 2025 16:27:31 +0200 Subject: [PATCH 5/5] mime: declare errors as non-exported variables --- src/mime/mediatype.go | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/src/mime/mediatype.go b/src/mime/mediatype.go index 2356530aa968c6..c6006b614f319e 100644 --- a/src/mime/mediatype.go +++ b/src/mime/mediatype.go @@ -98,25 +98,32 @@ func FormatMediaType(t string, param map[string]string) string { func checkMediaTypeDisposition(s string) error { typ, rest := consumeToken(s) if typ == "" { - return errors.New("mime: no media type") + return errNoMediaType } if rest == "" { return nil } var ok bool if rest, ok = strings.CutPrefix(rest, "/"); !ok { - return errors.New("mime: expected slash after first token") + return errNoSlashAfterFirstToken } subtype, rest := consumeToken(rest) if subtype == "" { - return errors.New("mime: expected token after slash") + return errNoTokenAfterSlash } if rest != "" { - return errors.New("mime: unexpected content after media subtype") + return errUnexpectedContentAfterMediaSubtype } return nil } +var ( + errNoMediaType = errors.New("mime: no media type") + errNoSlashAfterFirstToken = errors.New("mime: expected slash after first token") + errNoTokenAfterSlash = errors.New("mime: expected token after slash") + errUnexpectedContentAfterMediaSubtype = errors.New("mime: unexpected content after media subtype") +) + // ErrInvalidMediaParameter is returned by [ParseMediaType] if // the media type value was found but there was an error parsing // the optional parameters @@ -177,7 +184,7 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e } if v, exists := pmap[key]; exists && v != value { // Duplicate parameter names are incorrect, but we allow them if they are equal. - return "", nil, errors.New("mime: duplicate parameter name") + return "", nil, errDuplicateParamName } pmap[key] = value v = rest @@ -227,6 +234,8 @@ func ParseMediaType(v string) (mediatype string, params map[string]string, err e return } +var errDuplicateParamName = errors.New("mime: duplicate parameter name") + func decode2231Enc(v string) (string, bool) { charset, v, ok := strings.Cut(v, "'") if !ok {