From: Timo Sirainen Date: Fri, 17 Apr 2026 14:55:05 +0000 (+0200) Subject: [PATCH 02/14] imap: Stream BODYSTRUCTURE to client without ostream memory duplication X-Git-Tag: archive/raspbian/1%2.4.1+dfsg1-6+rpi1+deb13u7^2~62 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=d0adf60476b521447ece50a5a7d3e95dee66e9f9;p=dovecot.git [PATCH 02/14] imap: Stream BODYSTRUCTURE to client without ostream memory duplication For huge BODYSTRUCTURE responses (messages with many MIME parts), o_stream_send_str() caused the ostream to copy the entire string into its ring buffer when the stream was corked, doubling memory usage. Use the same o_stream_set_max_buffer_size(0) + o_stream_send_istream() pattern as fetch_stream_continue() so the ostream buffer stays at 0 bytes and the I/O loop handles flow control via WAIT_OUTPUT. Co-Authored-By: Claude Sonnet 4.6 Gbp-Pq: Name 0002-imap-Stream-BODYSTRUCTURE-to-client-without-ostream-.patch --- diff --git a/src/imap/imap-fetch.c b/src/imap/imap-fetch.c index ca4b321..b4a8a46 100644 --- a/src/imap/imap-fetch.c +++ b/src/imap/imap-fetch.c @@ -732,6 +732,34 @@ static bool fetch_body_init(struct imap_fetch_init_context *ctx) return imap_fetch_body_section_init(ctx); } +static int fetch_bodystructure_stream_continue(struct imap_fetch_context *ctx) +{ + struct imap_fetch_state *state = &ctx->state; + enum ostream_send_istream_result res; + + o_stream_set_max_buffer_size(ctx->client->output, 0); + res = o_stream_send_istream(ctx->client->output, state->cur_input); + o_stream_set_max_buffer_size(ctx->client->output, SIZE_MAX); + + switch (res) { + case OSTREAM_SEND_ISTREAM_RESULT_FINISHED: + i_stream_unref(&state->cur_input); + state->cont_handler = NULL; + if (o_stream_send(ctx->client->output, ")", 1) < 0) + return -1; + return 1; + case OSTREAM_SEND_ISTREAM_RESULT_WAIT_INPUT: + i_unreached(); + case OSTREAM_SEND_ISTREAM_RESULT_WAIT_OUTPUT: + return 0; + case OSTREAM_SEND_ISTREAM_RESULT_ERROR_INPUT: + i_unreached(); + case OSTREAM_SEND_ISTREAM_RESULT_ERROR_OUTPUT: + return -1; + } + i_unreached(); +} + static int fetch_bodystructure(struct imap_fetch_context *ctx, struct mail *mail, void *context ATTR_UNUSED) { @@ -748,12 +776,13 @@ static int fetch_bodystructure(struct imap_fetch_context *ctx, return -1; } - if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0 || - o_stream_send_str(ctx->client->output, bodystructure) < 0 || - o_stream_send(ctx->client->output, ")", 1) < 0) + if (o_stream_send(ctx->client->output, "BODYSTRUCTURE (", 15) < 0) return -1; - return 1; + ctx->state.cur_input = + i_stream_create_from_data(bodystructure, strlen(bodystructure)); + ctx->state.cont_handler = fetch_bodystructure_stream_continue; + return fetch_bodystructure_stream_continue(ctx); } static bool fetch_bodystructure_init(struct imap_fetch_init_context *ctx)