webmail: when listing messages in backend to send to frontend, don't error out when there's a large plain text part

by not trying to parse the full message for the MessageItem, but only reading
headers when needed.

before previous commit, we wouldn't try reading such messages in full either.
This commit is contained in:
Mechiel Lukkien 2025-01-13 16:13:25 +01:00
parent 1e15a10b66
commit d4d2a0fd99
No known key found for this signature in database
4 changed files with 15 additions and 15 deletions

View file

@ -172,7 +172,7 @@ func (Webmail) ParsedMessage(ctx context.Context, msgID int64) (pm ParsedMessage
state := msgState{acc: acc}
defer state.clear()
var err error
pm, err = parsedMessage(log, m, &state, true, false)
pm, err = parsedMessage(log, m, &state, true, false, false)
xcheckf(ctx, err, "parsing message")
if len(pm.envelope.From) == 1 {
@ -1853,7 +1853,7 @@ func (Webmail) RulesetSuggestMove(ctx context.Context, msgID, mbSrcID, mbDstID i
// Parse message for List-Id header.
state := msgState{acc: acc}
defer state.clear()
pm, err := parsedMessage(log, m, &state, true, false)
pm, err := parsedMessage(log, m, &state, true, false, false)
xcheckf(ctx, err, "parsing message")
// The suggested ruleset. Once all is checked, we'll return it.

View file

@ -84,11 +84,11 @@ func messageItemMoreHeaders(moreHeaders []string, pm ParsedMessage) (l [][2]stri
}
func messageItem(log mlog.Log, m store.Message, state *msgState, moreHeaders []string) (MessageItem, error) {
full := len(moreHeaders) > 0
pm, err := parsedMessage(log, m, state, full, true)
if err != nil && errors.Is(err, message.ErrHeader) && full {
headers := len(moreHeaders) > 0
pm, err := parsedMessage(log, m, state, false, true, headers)
if err != nil && errors.Is(err, message.ErrHeader) && headers {
log.Debugx("load message item without parsing headers after error", err, slog.Int64("msgid", m.ID))
pm, err = parsedMessage(log, m, state, false, true)
pm, err = parsedMessage(log, m, state, false, true, false)
}
if err != nil {
return MessageItem{}, fmt.Errorf("parsing message %d for item: %v", m.ID, err)
@ -198,7 +198,7 @@ func formatFirstLine(r io.Reader) (string, error) {
return result, scanner.Err()
}
func parsedMessage(log mlog.Log, m store.Message, state *msgState, full, msgitem bool) (pm ParsedMessage, rerr error) {
func parsedMessage(log mlog.Log, m store.Message, state *msgState, full, msgitem, msgitemHeaders bool) (pm ParsedMessage, rerr error) {
pm.ViewMode = store.ModeText // Valid default, in case this makes it to frontend.
if full || msgitem {
@ -247,7 +247,7 @@ func parsedMessage(log mlog.Log, m store.Message, state *msgState, full, msgitem
pm.envelope = env
}
if full && state.part.BodyOffset > 0 {
if (full || msgitemHeaders) && state.part.BodyOffset > 0 {
hdrs, err := state.part.Header()
if err != nil {
return ParsedMessage{}, fmt.Errorf("parsing headers: %w", err)

View file

@ -1523,7 +1523,7 @@ func queryMessages(ctx context.Context, log mlog.Log, acc *store.Account, tx *bs
// expected to read first, that would be the first unread, which we'll get below
// when gathering the thread.
found = true
xpm, err := parsedMessage(log, m, &state, true, false)
xpm, err := parsedMessage(log, m, &state, true, false, false)
if err != nil && errors.Is(err, message.ErrHeader) {
log.Debug("not returning parsed message due to invalid headers", slog.Int64("msgid", m.ID), slog.Any("err", err))
} else if err != nil {
@ -1653,7 +1653,7 @@ func gatherThread(log mlog.Log, tx *bstore.Tx, acc *store.Account, v view, m sto
if tm.ID == destMessageID || destMessageID == 0 && first && (pm == nil || !firstUnread && !tm.Seen) {
firstUnread = !tm.Seen
xpm, err := parsedMessage(log, tm, &xstate, true, false)
xpm, err := parsedMessage(log, tm, &xstate, true, false, false)
if err != nil && errors.Is(err, message.ErrHeader) {
log.Debug("not returning parsed message due to invalid headers", slog.Int64("msgid", m.ID), slog.Any("err", err))
} else if err != nil {
@ -1674,7 +1674,7 @@ func gatherThread(log mlog.Log, tx *bstore.Tx, acc *store.Account, v view, m sto
if destMessageID == 0 && first && !m.Seen && !firstUnread {
xstate := msgState{acc: acc}
defer xstate.clear()
xpm, err := parsedMessage(log, m, &xstate, true, false)
xpm, err := parsedMessage(log, m, &xstate, true, false, false)
if err != nil && errors.Is(err, message.ErrHeader) {
log.Debug("not returning parsed message due to invalid headers", slog.Int64("msgid", m.ID), slog.Any("err", err))
} else if err != nil {
@ -1855,7 +1855,7 @@ var attachmentExtensions = map[string]AttachmentType{
func attachmentTypes(log mlog.Log, m store.Message, state *msgState) (map[AttachmentType]bool, error) {
types := map[AttachmentType]bool{}
pm, err := parsedMessage(log, m, state, false, false)
pm, err := parsedMessage(log, m, state, false, false, false)
if err != nil {
return nil, fmt.Errorf("parsing message for attachments: %w", err)
}

View file

@ -650,7 +650,7 @@ func handle(apiHandler http.Handler, isForwarded bool, accountPath string, w htt
state := msgState{acc: acc, m: m, msgr: msgr, part: &p}
// note: state is cleared by cleanup
pm, err := parsedMessage(log, m, &state, true, true)
pm, err := parsedMessage(log, m, &state, true, true, true)
xcheckf(ctx, err, "getting parsed message")
if t[1] == "msgtext" && len(pm.Texts) == 0 || t[1] != "msgtext" && !pm.HasHTML {
http.Error(w, "400 - bad request - no such part", http.StatusBadRequest)
@ -682,7 +682,7 @@ func handle(apiHandler http.Handler, isForwarded bool, accountPath string, w htt
state := msgState{acc: acc, m: m, msgr: msgr, part: &p}
// note: state is cleared by cleanup
pm, err := parsedMessage(log, m, &state, true, true)
pm, err := parsedMessage(log, m, &state, true, true, true)
xcheckf(ctx, err, "parsing parsedmessage")
pmjson, err := json.Marshal(pm)
xcheckf(ctx, err, "marshal parsedmessage")
@ -715,7 +715,7 @@ func handle(apiHandler http.Handler, isForwarded bool, accountPath string, w htt
state := msgState{acc: acc, m: m, msgr: msgr, part: &p}
// note: state is cleared by cleanup
pm, err := parsedMessage(log, m, &state, true, true)
pm, err := parsedMessage(log, m, &state, true, true, true)
xcheckf(ctx, err, "parsing parsedmessage")
if len(pm.Texts) == 0 {