parse: fix content-type parsing error
If an error occurs when parsing the content-type, check if the content-type is quoted; if so, remove quotes. If this is not the case, then return a text/plain content-type as a sane fallback option, so that the message can be at least viewed in plaintext. Fixes: https://todo.sr.ht/~rjarry/aerc/44 Signed-off-by: Koni Marti <koni.marti@gmail.com> Acked-by: Robin Jarry <robin@jarry.cc>
This commit is contained in:
parent
8b6f9719a8
commit
955f7683af
3 changed files with 96 additions and 1 deletions
|
@ -64,12 +64,37 @@ func splitMIME(m string) (string, string) {
|
||||||
return parts[0], parts[1]
|
return parts[0], parts[1]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func fixContentType(h message.Header) (string, map[string]string) {
|
||||||
|
ct, rest := h.Get("Content-Type"), ""
|
||||||
|
if i := strings.Index(ct, ";"); i > 0 {
|
||||||
|
ct, rest = ct[:i], ct[i:]
|
||||||
|
}
|
||||||
|
|
||||||
|
// check if there are quotes around the content type
|
||||||
|
if strings.Contains(ct, "\"") {
|
||||||
|
header := strings.ReplaceAll(ct, "\"", "")
|
||||||
|
if rest != "" {
|
||||||
|
header += rest
|
||||||
|
}
|
||||||
|
h.Set("Content-Type", header)
|
||||||
|
if contenttype, params, err := h.ContentType(); err == nil {
|
||||||
|
return contenttype, params
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if all else fails, return text/plain
|
||||||
|
return "text/plain", nil
|
||||||
|
}
|
||||||
|
|
||||||
func ParseEntityStructure(e *message.Entity) (*models.BodyStructure, error) {
|
func ParseEntityStructure(e *message.Entity) (*models.BodyStructure, error) {
|
||||||
var body models.BodyStructure
|
var body models.BodyStructure
|
||||||
contentType, ctParams, err := e.Header.ContentType()
|
contentType, ctParams, err := e.Header.ContentType()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("could not parse content type: %v", err)
|
// try to fix the error; if all measures fail, then return a
|
||||||
|
// text/plain content type to display at least plaintext
|
||||||
|
contentType, ctParams = fixContentType(e.Header)
|
||||||
}
|
}
|
||||||
|
|
||||||
mimeType, mimeSubType := splitMIME(contentType)
|
mimeType, mimeSubType := splitMIME(contentType)
|
||||||
body.MIMEType = mimeType
|
body.MIMEType = mimeType
|
||||||
body.MIMESubType = mimeSubType
|
body.MIMESubType = mimeSubType
|
||||||
|
|
|
@ -10,6 +10,31 @@ import (
|
||||||
"git.sr.ht/~rjarry/aerc/models"
|
"git.sr.ht/~rjarry/aerc/models"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
func TestMessageInfoParser(t *testing.T) {
|
||||||
|
rootDir := "testdata/message/valid"
|
||||||
|
msgFiles, err := ioutil.ReadDir(rootDir)
|
||||||
|
die(err)
|
||||||
|
|
||||||
|
for _, fi := range msgFiles {
|
||||||
|
if fi.IsDir() {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
p := fi.Name()
|
||||||
|
t.Run(p, func(t *testing.T) {
|
||||||
|
m := newMockRawMessageFromPath(filepath.Join(rootDir, p))
|
||||||
|
mi, err := MessageInfo(m)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("Failed to create MessageInfo with:", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if perr := mi.Error; perr != nil {
|
||||||
|
t.Fatal("Expected no parsing error, but got:", mi.Error)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestMessageInfoHandledError(t *testing.T) {
|
func TestMessageInfoHandledError(t *testing.T) {
|
||||||
rootDir := "testdata/message/invalid"
|
rootDir := "testdata/message/invalid"
|
||||||
msgFiles, err := ioutil.ReadDir(rootDir)
|
msgFiles, err := ioutil.ReadDir(rootDir)
|
||||||
|
|
45
worker/lib/testdata/message/valid/quoted-mime-type
vendored
Normal file
45
worker/lib/testdata/message/valid/quoted-mime-type
vendored
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
Subject: Your ECOLINES tickets
|
||||||
|
X-PHP-Originating-Script: 33:functions.inc.php
|
||||||
|
From: ECOLINES <ecolines@ecolines.lv>
|
||||||
|
Content-Type: multipart/mixed;
|
||||||
|
boundary="PHP-mixed-ba319678ca12656cfb8cd46e736ce09d"
|
||||||
|
Message-Id: <E1nvIQS-0004tm-Bc@legacy.ecolines.net>
|
||||||
|
Date: Sun, 29 May 2022 15:53:44 +0300
|
||||||
|
|
||||||
|
--PHP-mixed-ba319678ca12656cfb8cd46e736ce09d
|
||||||
|
Content-Type: multipart/alternative; boundary="PHP-alt-ba319678ca12656cfb8cd46e736ce09d"
|
||||||
|
|
||||||
|
--PHP-alt-ba319678ca12656cfb8cd46e736ce09d
|
||||||
|
Content-Type: text/plain; charset="UTF-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
Your tickets are attached to this message. Also You can print out Your tickets from our website www.ecolines.net<b
|
||||||
|
r />
|
||||||
|
…
|
||||||
|
|
||||||
|
--PHP-alt-ba319678ca12656cfb8cd46e736ce09d
|
||||||
|
Content-Type: text/html; charset="UTF-8"
|
||||||
|
Content-Transfer-Encoding: 7bit
|
||||||
|
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
||||||
|
…
|
||||||
|
|
||||||
|
--PHP-alt-ba319678ca12656cfb8cd46e736ce09d--
|
||||||
|
|
||||||
|
--PHP-mixed-ba319678ca12656cfb8cd46e736ce09d
|
||||||
|
Content-Type: "application/pdf"; name="17634428.pdf"
|
||||||
|
Content-Disposition: attachment; filename="17634428.pdf"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
JVBERi0xLjQKMSAwIG9iago8PAovVGl0bGUgKP7/AFkAbwB1AHIAIAB0AGkAYwBrAGUAdCkKL0Ny
|
||||||
|
…
|
||||||
|
|
||||||
|
--PHP-mixed-ba319678ca12656cfb8cd46e736ce09d
|
||||||
|
Content-Type: "application/pdf"; name="invoice-6385490.pdf"
|
||||||
|
Content-Disposition: attachment; filename="invoice-6385490.pdf"
|
||||||
|
Content-Transfer-Encoding: base64
|
||||||
|
|
||||||
|
JVBERi0xLjQKMSAwIG9iago8PAovVGl0bGUgKP7/AEkAbgB2AG8AaQBjAGUpCi9DcmVhdG9yICj+
|
||||||
|
…
|
||||||
|
|
||||||
|
--PHP-mixed-ba319678ca12656cfb8cd46e736ce09d--
|
Loading…
Reference in a new issue