mirror of
https://github.com/mjl-/mox.git
synced 2025-01-15 09:56:27 +03:00
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:
parent
1e15a10b66
commit
d4d2a0fd99
4 changed files with 15 additions and 15 deletions
|
@ -172,7 +172,7 @@ func (Webmail) ParsedMessage(ctx context.Context, msgID int64) (pm ParsedMessage
|
||||||
state := msgState{acc: acc}
|
state := msgState{acc: acc}
|
||||||
defer state.clear()
|
defer state.clear()
|
||||||
var err error
|
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")
|
xcheckf(ctx, err, "parsing message")
|
||||||
|
|
||||||
if len(pm.envelope.From) == 1 {
|
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.
|
// Parse message for List-Id header.
|
||||||
state := msgState{acc: acc}
|
state := msgState{acc: acc}
|
||||||
defer state.clear()
|
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")
|
xcheckf(ctx, err, "parsing message")
|
||||||
|
|
||||||
// The suggested ruleset. Once all is checked, we'll return it.
|
// The suggested ruleset. Once all is checked, we'll return it.
|
||||||
|
|
|
@ -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) {
|
func messageItem(log mlog.Log, m store.Message, state *msgState, moreHeaders []string) (MessageItem, error) {
|
||||||
full := len(moreHeaders) > 0
|
headers := len(moreHeaders) > 0
|
||||||
pm, err := parsedMessage(log, m, state, full, true)
|
pm, err := parsedMessage(log, m, state, false, true, headers)
|
||||||
if err != nil && errors.Is(err, message.ErrHeader) && full {
|
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))
|
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 {
|
if err != nil {
|
||||||
return MessageItem{}, fmt.Errorf("parsing message %d for item: %v", m.ID, err)
|
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()
|
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.
|
pm.ViewMode = store.ModeText // Valid default, in case this makes it to frontend.
|
||||||
|
|
||||||
if full || msgitem {
|
if full || msgitem {
|
||||||
|
@ -247,7 +247,7 @@ func parsedMessage(log mlog.Log, m store.Message, state *msgState, full, msgitem
|
||||||
pm.envelope = env
|
pm.envelope = env
|
||||||
}
|
}
|
||||||
|
|
||||||
if full && state.part.BodyOffset > 0 {
|
if (full || msgitemHeaders) && state.part.BodyOffset > 0 {
|
||||||
hdrs, err := state.part.Header()
|
hdrs, err := state.part.Header()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return ParsedMessage{}, fmt.Errorf("parsing headers: %w", err)
|
return ParsedMessage{}, fmt.Errorf("parsing headers: %w", err)
|
||||||
|
|
|
@ -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
|
// expected to read first, that would be the first unread, which we'll get below
|
||||||
// when gathering the thread.
|
// when gathering the thread.
|
||||||
found = true
|
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) {
|
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))
|
log.Debug("not returning parsed message due to invalid headers", slog.Int64("msgid", m.ID), slog.Any("err", err))
|
||||||
} else if err != nil {
|
} 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) {
|
if tm.ID == destMessageID || destMessageID == 0 && first && (pm == nil || !firstUnread && !tm.Seen) {
|
||||||
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) {
|
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))
|
log.Debug("not returning parsed message due to invalid headers", slog.Int64("msgid", m.ID), slog.Any("err", err))
|
||||||
} else if err != nil {
|
} 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 {
|
if destMessageID == 0 && first && !m.Seen && !firstUnread {
|
||||||
xstate := msgState{acc: acc}
|
xstate := msgState{acc: acc}
|
||||||
defer xstate.clear()
|
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) {
|
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))
|
log.Debug("not returning parsed message due to invalid headers", slog.Int64("msgid", m.ID), slog.Any("err", err))
|
||||||
} else if err != nil {
|
} 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) {
|
func attachmentTypes(log mlog.Log, m store.Message, state *msgState) (map[AttachmentType]bool, error) {
|
||||||
types := map[AttachmentType]bool{}
|
types := map[AttachmentType]bool{}
|
||||||
|
|
||||||
pm, err := parsedMessage(log, m, state, false, false)
|
pm, err := parsedMessage(log, m, state, false, false, false)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("parsing message for attachments: %w", err)
|
return nil, fmt.Errorf("parsing message for attachments: %w", err)
|
||||||
}
|
}
|
||||||
|
|
|
@ -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}
|
state := msgState{acc: acc, m: m, msgr: msgr, part: &p}
|
||||||
// note: state is cleared by cleanup
|
// 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")
|
xcheckf(ctx, err, "getting parsed message")
|
||||||
if t[1] == "msgtext" && len(pm.Texts) == 0 || t[1] != "msgtext" && !pm.HasHTML {
|
if t[1] == "msgtext" && len(pm.Texts) == 0 || t[1] != "msgtext" && !pm.HasHTML {
|
||||||
http.Error(w, "400 - bad request - no such part", http.StatusBadRequest)
|
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}
|
state := msgState{acc: acc, m: m, msgr: msgr, part: &p}
|
||||||
// note: state is cleared by cleanup
|
// 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")
|
xcheckf(ctx, err, "parsing parsedmessage")
|
||||||
pmjson, err := json.Marshal(pm)
|
pmjson, err := json.Marshal(pm)
|
||||||
xcheckf(ctx, err, "marshal parsedmessage")
|
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}
|
state := msgState{acc: acc, m: m, msgr: msgr, part: &p}
|
||||||
// note: state is cleared by cleanup
|
// 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")
|
xcheckf(ctx, err, "parsing parsedmessage")
|
||||||
|
|
||||||
if len(pm.Texts) == 0 {
|
if len(pm.Texts) == 0 {
|
||||||
|
|
Loading…
Reference in a new issue