]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
lib-mail, lib-imap: Optimize parsing large number of address headers
authorTimo Sirainen <timo.sirainen@open-xchange.com>
Thu, 8 Feb 2024 22:57:12 +0000 (00:57 +0200)
committertimo.sirainen <timo.sirainen@open-xchange.com>
Wed, 7 Aug 2024 13:15:57 +0000 (13:15 +0000)
Every header was appended to a linked list by walking through the whole
list, causing excessive CPU usage when the list became large enough.
Fixed by changing struct message_part_envelope to use struct
message_address_list, which stores also linked list tail pointers. This
allows quickly appending to the end of the linked list.

src/lib-imap/imap-envelope.c
src/lib-mail/message-part-data.c
src/lib-mail/message-part-data.h
src/lib-storage/index/index-search-mime.c

index 1312eae2ff303954c694c58f227c7160e1e1d301..da3177025a5e832e8841be6e64d9a898e692f186 100644 (file)
@@ -67,17 +67,17 @@ void imap_envelope_write(struct message_part_envelope *data,
        }
 
        str_append_c(str, ' ');
-       imap_write_address(str, data->from);
+       imap_write_address(str, data->from.head);
        str_append_c(str, ' ');
-       imap_write_address(str, NVL(data->sender, data->from));
+       imap_write_address(str, NVL(data->sender.head, data->from.head));
        str_append_c(str, ' ');
-       imap_write_address(str, NVL(data->reply_to, data->from));
+       imap_write_address(str, NVL(data->reply_to.head, data->from.head));
        str_append_c(str, ' ');
-       imap_write_address(str, data->to);
+       imap_write_address(str, data->to.head);
        str_append_c(str, ' ');
-       imap_write_address(str, data->cc);
+       imap_write_address(str, data->cc.head);
        str_append_c(str, ' ');
-       imap_write_address(str, data->bcc);
+       imap_write_address(str, data->bcc.head);
 
        str_append_c(str, ' ');
        imap_append_nstring_nolf(str, data->in_reply_to);
@@ -126,28 +126,25 @@ imap_envelope_parse_address(const struct imap_arg *arg,
 
 static bool
 imap_envelope_parse_addresses(const struct imap_arg *arg,
-       pool_t pool, struct message_address **addrs_r)
+       pool_t pool, struct message_address_list *addrs_r)
 {
-       struct message_address *first, *last, *addr;
+       struct message_address *addr;
        const struct imap_arg *list_args;
 
-       if (arg->type == IMAP_ARG_NIL) {
-               *addrs_r = NULL;
+       i_zero(addrs_r);
+       if (arg->type == IMAP_ARG_NIL)
                return TRUE;
-       }
 
        if (!imap_arg_get_list(arg, &list_args))
                return FALSE;
 
-       first = last = addr = NULL;
+       addr = NULL;
        for (; !IMAP_ARG_IS_EOL(list_args); list_args++) {
                if (!imap_envelope_parse_address
                        (list_args, pool, &addr))
                        return FALSE;
-               DLLIST2_APPEND(&first, &last, addr);
+               DLLIST2_APPEND(&addrs_r->head, &addrs_r->tail, addr);
        }
-
-       *addrs_r = first;
        return TRUE;
 }
 
index a5771f87e2e9e2203aac0f1144fe2117a04a1df4..25019ab432df6f7e79c93aa9c1d25a89777d0349 100644 (file)
@@ -4,6 +4,7 @@
 #include "str.h"
 #include "wildcard-match.h"
 #include "array.h"
+#include "llist.h"
 #include "rfc822-parser.h"
 #include "rfc2231-parser.h"
 #include "message-address.h"
@@ -176,7 +177,7 @@ void message_part_envelope_parse_from_header(pool_t pool,
 {
        struct message_part_envelope *d;
        enum envelope_field field;
-       struct message_address **addr_p, *addr;
+       struct message_address_list *addr_p, new_addr;
        const char **str_p;
 
        if (*data == NULL) {
@@ -234,18 +235,18 @@ void message_part_envelope_parse_from_header(pool_t pool,
        }
 
        if (addr_p != NULL) {
-               addr = message_address_parse(pool, hdr->full_value,
-                                            hdr->full_value_len,
-                                            UINT_MAX,
-                                            MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING);
+               message_address_parse_full(pool, hdr->full_value,
+                                          hdr->full_value_len,
+                                          UINT_MAX,
+                                          MESSAGE_ADDRESS_PARSE_FLAG_FILL_MISSING,
+                                          &new_addr);
                /* Merge multiple headers the same as if they were comma
                   separated in a single line. This is better from security
                   point of view, because attacker could intentionally write
                   addresses in a way that e.g. the first From header is
                   validated while MUA only shows the second From header. */
-               while (*addr_p != NULL)
-                       addr_p = &(*addr_p)->next;
-               *addr_p = addr;
+               DLLIST2_JOIN(&addr_p->head, &addr_p->tail,
+                            &new_addr.head, &new_addr.tail);
        } else if (str_p != NULL) {
                *str_p = message_header_strdup(pool, hdr->full_value,
                                               hdr->full_value_len);
index 5ff9ffe1bc6a8bce673da149cd675b411df07283..7ec878de68ed5d1105fbf6ec1f51235f0e3326eb 100644 (file)
@@ -2,6 +2,7 @@
 #define MESSAGE_PART_DATA_H
 
 #include "message-part.h"
+#include "message-address.h"
 
 #define MESSAGE_PART_DEFAULT_CHARSET "us-ascii"
 
@@ -14,8 +15,9 @@ struct message_part_param {
 
 struct message_part_envelope {
        const char *date, *subject;
-       struct message_address *from, *sender, *reply_to;
-       struct message_address *to, *cc, *bcc;
+
+       struct message_address_list from, sender, reply_to;
+       struct message_address_list to, cc, bcc;
 
        const char *in_reply_to, *message_id;
 };
index da7e5e170926506b0ba17ab8743343d231264b32..3328ce98af13af1b2067ab39d3d46da4ecaddf32 100644 (file)
@@ -205,7 +205,7 @@ seach_arg_mime_envelope_address_match(
        enum mail_search_mime_arg_type type, const char *key,
        const struct message_part_envelope *envelope)
 {
-       const struct message_address *addrs;
+       struct message_address_list addrs;
        string_t *addrs_enc;
 
        if (envelope == NULL)
@@ -239,7 +239,7 @@ seach_arg_mime_envelope_address_match(
           probably be normalized directly in the struct message_address. */
 
        addrs_enc = t_str_new(128);
-       message_address_write(addrs_enc, addrs);
+       message_address_write(addrs_enc, addrs.head);
        return (strstr(str_c(addrs_enc), key) != NULL ? 1 : 0);
 }