]> git.ipfire.org Git - thirdparty/dovecot/core.git/commitdiff
imap: Handle rawlogs when starting a compressed communication
authorKarl Fleischmann <karl.fleischmann@open-xchange.com>
Wed, 3 Aug 2022 12:53:36 +0000 (14:53 +0200)
committeraki.tuomi <aki.tuomi@open-xchange.com>
Mon, 15 Aug 2022 07:34:57 +0000 (07:34 +0000)
The rawlogs should not contain compressed data when starting a
compressed communication channel. This commit amends rawlog management
data on the imap client to keep track of rawlog streams, and
appropriately handle rawlogs when imap compression is enabled.

src/imap/cmd-compress.c
src/imap/imap-client.c
src/imap/imap-client.h

index 1df526e3f98d42a6d3aac3a8ffbeb362011a5200..7254d40110407934da74b91af26d3365d6d288a0 100644 (file)
@@ -4,6 +4,7 @@
 #include "imap-commands.h"
 #include "istream.h"
 #include "ostream.h"
+#include "iostream-rawlog.h"
 #include "str.h"
 #include "compression.h"
 
@@ -70,6 +71,32 @@ bool cmd_compress(struct client_command_context *cmd)
        client_skip_line(client);
        client_send_tagline(cmd, "OK Begin compression.");
 
+       if (client->pre_rawlog_input != NULL) {
+               /* Rawlogging is currently enabled. Stop it. */
+               i_assert(client->pre_rawlog_output != NULL);
+               i_assert(client->pre_rawlog_input != client->post_rawlog_input);
+               i_assert(client->pre_rawlog_output != client->post_rawlog_output);
+               uoff_t prev_in_offset = client->input->v_offset;
+               /* Make sure the rawlog is the outermost stream, since we
+                  can't remove it from the middle */
+               i_assert(client->post_rawlog_input == client->input);
+               i_assert(client->post_rawlog_output == client->output);
+               /* Pre-rawlog streams are referenced only by the outermost
+                  stream, so make sure they don't get destroyed */
+               client->input = client->pre_rawlog_input;
+               client->output = client->pre_rawlog_output;
+               i_stream_ref(client->input);
+               o_stream_ref(client->output);
+               /* Destroy the rawlog streams. This closes the rawlogs, but
+                  not the parent streams. */
+               i_stream_destroy(&client->post_rawlog_input);
+               o_stream_destroy(&client->post_rawlog_output);
+               io_remove(&client->io);
+               /* Make sure istream-rawlog updated the parent stream's seek
+                  offset. */
+               i_assert(client->input->v_offset == prev_in_offset);
+       }
+
        level = handler->get_default_level();
        old_input = client->input;
        old_output = client->output;
@@ -81,6 +108,14 @@ bool cmd_compress(struct client_command_context *cmd)
        i_stream_unref(&old_input);
        o_stream_unref(&old_output);
 
+       if (client->pre_rawlog_input != NULL) {
+               (void)iostream_rawlog_create(client->set->rawlog_dir,
+                                            &client->input, &client->output);
+               client->post_rawlog_input = client->input;
+               client->post_rawlog_output = client->output;
+               client_add_missing_io(client);
+       }
+
        client_update_imap_parser_streams(client);
        return TRUE;
 }
index 3c445b0f7fb500c19834647f0c26867758997297..2b0fcb07dbd0457d557c88b594b3866d58faa762 100644 (file)
@@ -221,8 +221,20 @@ struct client *client_create(int fd_in, int fd_out, bool unhibernated,
 void client_create_finish_io(struct client *client)
 {
        if (client->set->rawlog_dir[0] != '\0') {
+               client->pre_rawlog_input = client->input;
+               client->pre_rawlog_output = client->output;
                (void)iostream_rawlog_create(client->set->rawlog_dir,
                                             &client->input, &client->output);
+               if (client->input != client->pre_rawlog_input) {
+                       /* rawlog enabled */
+                       client->post_rawlog_input = client->input;
+                       client->post_rawlog_output = client->output;
+               } else {
+                       /* rawlog setting is set, but rawlog wasn't actually
+                          started. */
+                       client->pre_rawlog_input = NULL;
+                       client->pre_rawlog_output = NULL;
+               }
        }
        client->io = io_add_istream(client->input, client_input, client);
 }
index af8af980c7db92e4763c8941370262e6f00cf011..433d850117d57bbf3699d41f9c2e91ed9d36dcd4 100644 (file)
@@ -161,8 +161,8 @@ struct client {
 
        int fd_in, fd_out;
        struct io *io;
-       struct istream *input;
-       struct ostream *output;
+       struct istream *input, *pre_rawlog_input, *post_rawlog_input;
+       struct ostream *output, *pre_rawlog_output, *post_rawlog_output;
        struct timeout *to_idle, *to_idle_output, *to_delayed_input;
        guid_128_t anvil_conn_guid;