From 59e85809f7e95f91fd2b07c3514601e4ca83ba3c Mon Sep 17 00:00:00 2001 From: Winni Neessen Date: Sat, 10 Feb 2024 13:22:38 +0100 Subject: [PATCH] Refactor multipart encoding handling and improve content parsing Refactored the processing of multipart encoding to be robust and easily maintainable. The changes include setting 'QP' encoding as default when the Content-Transfer-Encoding header is empty, accounting for the removal of this header by the standard Go multipart package. Also, parser functions for content type and charset are now independently handling the headers, replacing the split-string approach, thus improving efficiency and code readability. --- eml.go | 28 +++++++++++++--------------- 1 file changed, 13 insertions(+), 15 deletions(-) diff --git a/eml.go b/eml.go index 17c5635..632102d 100644 --- a/eml.go +++ b/eml.go @@ -261,24 +261,33 @@ func parseEMLMultipartAlternative(params map[string]string, bodybuf *bytes.Buffe _ = mpart.Close() return fmt.Errorf("failed to read multipart: %w", err) } + fmt.Printf("CTE: %+v", params) mpContentType, ok := mpart.Header[HeaderContentType.String()] if !ok { return fmt.Errorf("failed to get content-type from part") } - mpContentTypeSplit := strings.Split(mpContentType[0], "; ") - p := m.newPart(ContentType(mpContentTypeSplit[0])) - parseEMLMultiPartCharset(mpContentTypeSplit, p) + conType, charSet := parseContentType(mpContentType[0]) + p := m.newPart(ContentType(conType)) + p.SetCharset(Charset(charSet)) mpTransferEnc, ok := mpart.Header[HeaderContentTransferEnc.String()] if !ok { - return fmt.Errorf("failed to get content-transfer-encoding from part") + // If CTE is empty we can assume that it's a quoted-printable CTE since the + // GO stdlib multipart packages deletes that header + // See: https://cs.opensource.google/go/go/+/refs/tags/go1.22.0:src/mime/multipart/multipart.go;l=161 + mpTransferEnc = []string{EncodingQP.String()} } + switch { case strings.EqualFold(mpTransferEnc[0], EncodingB64.String()): if err := handleEMLMultiPartBase64Encoding(mpdata, p); err != nil { return fmt.Errorf("failed to handle multipart base64 transfer-encoding: %w", err) } + case strings.EqualFold(mpTransferEnc[0], EncodingQP.String()): + p.SetContent(string(mpdata)) + default: + return fmt.Errorf("unsupported Content-Transfer-Encoding") } m.parts = append(m.parts, p) @@ -291,17 +300,6 @@ func parseEMLMultipartAlternative(params map[string]string, bodybuf *bytes.Buffe return nil } -// parseEMLMultiPartCharset parses the Charset from a ContentType header and assigns it to a Part -// TODO: This might be redundant to parseContentType -func parseEMLMultiPartCharset(mpContentTypeSplit []string, p *Part) { - if len(mpContentTypeSplit) > 1 && strings.HasPrefix(strings.ToLower(mpContentTypeSplit[1]), "charset=") { - valSplit := strings.Split(mpContentTypeSplit[1], "=") - if len(valSplit) > 1 { - p.SetCharset(Charset(valSplit[1])) - } - } -} - // handleEMLMultiPartBase64Encoding sets the content body of a base64 encoded Part func handleEMLMultiPartBase64Encoding(mpdata []byte, p *Part) error { p.SetEncoding(EncodingB64)