bcb4e51a409d94ae670de96afb8483a4f7855294Stephan Bosch/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "lib.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "buffer.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "istream.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "str.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "message-size.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#include "message-header-parser.h"
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct message_header_parser_ctx {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_line line;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct istream *input;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_size *hdr_size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen string_t *name;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen buffer_t *value_buf;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen enum message_header_parser_flags flags;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool skip_line:1;
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool has_nuls:1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen};
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct message_header_parser_ctx *
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen enum message_header_parser_flags flags)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_parser_ctx *ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx = i_new(struct message_header_parser_ctx, 1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->input = input;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size = hdr_size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->name = str_new(default_pool, 128);
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen ctx->flags = flags;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen ctx->value_buf = buffer_create_dynamic(default_pool, 4096);
20faa69d801460e89aa0b1214f3db4b026999b1eTimo Sirainen i_stream_ref(input);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (hdr_size != NULL)
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch i_zero(hdr_size);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_parser_ctx *ctx = *_ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
20faa69d801460e89aa0b1214f3db4b026999b1eTimo Sirainen i_stream_unref(&ctx->input);
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen buffer_free(&ctx->value_buf);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_free(&ctx->name);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_free(ctx);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen *_ctx = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_line **hdr_r)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_line *line = &ctx->line;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const unsigned char *msg;
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen size_t i, size, startpos, colon_pos, parse_size, skip = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int ret;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen bool continued, continues, last_no_newline, last_crlf;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen bool no_newline, crlf_newline;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen *hdr_r = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (line->eoh)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen if (line->continues)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen colon_pos = 0;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* new header line */
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen line->name_offset = ctx->input->v_offset;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen colon_pos = UINT_MAX;
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen buffer_set_used_size(ctx->value_buf, 0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen no_newline = FALSE;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen crlf_newline = FALSE;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen continued = line->continues;
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen continues = FALSE;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen for (startpos = 0;;) {
651f981ca065d2365bf2ea07b04318a5402f047aTimo Sirainen ret = i_stream_read_bytes(ctx->input, &msg, &size, startpos+2);
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen if (ret >= 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* we want to know one byte in advance to find out
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if it's multiline header */
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen parse_size = size == 0 ? 0 : size-1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen parse_size = size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen if (ret <= 0 && startpos == parse_size) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret == -1) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (startpos > 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* header ended unexpectedly. */
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen no_newline = TRUE;
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen skip = startpos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* error / EOF with no bytes */
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen i_assert(skip == 0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
01ca85e6e763cfa0d146166fdd60654f04f51199Timo Sirainen if (size > 0 && !ctx->skip_line && !continued &&
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen (msg[0] == '\n' ||
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen (msg[0] == '\r' && size > 1 && msg[1] == '\n'))) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* end of headers - this mostly happens just
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen with mbox where headers are read separately
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen from body */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->lines++;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen if (msg[0] == '\r') {
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen skip = 2;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen crlf_newline = TRUE;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen } else {
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen skip = 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen if (ret == 0 && !ctx->input->eof) {
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen /* stream is nonblocking - need more data */
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen i_assert(skip == 0);
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen return 0;
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen }
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen i_assert(size > 0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* a) line is larger than input buffer
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen b) header ended unexpectedly */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret == -2) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* go back to last LWSP if found. */
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen size_t min_pos = !continued ? colon_pos : 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (i = size-1; i > min_pos; i--) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (IS_LWSP(msg[i])) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size = i;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen if (i == min_pos && (msg[size-1] == '\r' ||
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen msg[size-1] == '\n')) {
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen /* we may or may not have a full header,
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen but we don't know until we get the
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen next character. leave out the
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen linefeed and finish the header on
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen the next run. */
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen size--;
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen if (size > 0 && msg[size-1] == '\r')
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen size--;
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen }
01ca85e6e763cfa0d146166fdd60654f04f51199Timo Sirainen /* the buffer really has to be more than 2 to
01ca85e6e763cfa0d146166fdd60654f04f51199Timo Sirainen avoid CRLF looping forever */
01ca85e6e763cfa0d146166fdd60654f04f51199Timo Sirainen i_assert(size > 0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen continues = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen no_newline = TRUE;
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen skip = size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* find ':' */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (colon_pos == UINT_MAX) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (i = startpos; i < parse_size; i++) {
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (msg[i] > ':')
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen continue;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen if (msg[i] == ':' && !ctx->skip_line) {
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen colon_pos = i;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen line->full_value_offset =
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen ctx->input->v_offset + i + 1;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (msg[i] == '\n') {
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen /* end of headers, or error */
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen break;
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen }
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (msg[i] == '\0')
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen ctx->has_nuls = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen } else {
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen i = startpos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* find '\n' */
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen for (; i < parse_size; i++) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (msg[i] <= '\n') {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (msg[i] == '\n')
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (msg[i] == '\0')
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->has_nuls = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen if (i < parse_size && i+1 == size && ret == -2) {
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen /* we don't know if the line continues. */
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen i++;
6cb3c4f4276531258be706821e034f1f0a8cd276Timo Sirainen } else if (i < parse_size) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* got a line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->skip_line) {
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen /* skipping a line with a huge header name */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL) {
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen ctx->hdr_size->lines++;
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen ctx->hdr_size->physical_size += i + 1;
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen ctx->hdr_size->virtual_size += i + 1;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen }
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen /* missing CR */
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen if (ctx->hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen
f16712057c1b82c6d2a3a4267c4521d357cd4b4cTimo Sirainen i_stream_skip(ctx->input, i + 1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen startpos = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip_line = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen continue;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen continues = i+1 < size && IS_LWSP(msg[i+1]);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->lines++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* missing CR */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size = i;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size = i-1;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen crlf_newline = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen skip = i+1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen startpos = i;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen last_crlf = line->crlf_newline &&
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) == 0;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen last_no_newline = line->no_newline ||
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen
c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffcTimo Sirainen line->continues = continues;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen line->continued = continued;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen line->crlf_newline = crlf_newline;
675b2b1c4587a79478062b05725da61afa5d8045Timo Sirainen line->no_newline = no_newline;
01ca85e6e763cfa0d146166fdd60654f04f51199Timo Sirainen if (size == 0 && !continued) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* end of headers */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->eoh = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->name_len = line->value_len = line->full_value_len = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->name = ""; line->value = line->full_value = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->middle = NULL; line->middle_len = 0;
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen line->full_value_offset = line->name_offset;
cc3da53f3a49304a251bfae88f814505326ac210Timo Sirainen line->continues = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else if (line->continued) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value = msg;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value_len = size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else if (colon_pos == UINT_MAX) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* missing ':', assume the whole line is name */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value_len = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_truncate(ctx->name, 0);
4bd6702bfcb3568959acdb3cb68450aa76ed703bTimo Sirainen buffer_append(ctx->name, msg, size);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->name = str_c(ctx->name);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->name_len = str_len(ctx->name);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->middle = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->middle_len = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t pos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value = msg + colon_pos+1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value_len = size - colon_pos - 1;
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP) != 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* get value. skip all LWSP after ':'. Note that
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen RFC2822 doesn't say we should, but history behind
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen it..
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen Exception to this is if the value consists only of
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen LWSP, then skip only the one LWSP after ':'. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (pos = 0; pos < line->value_len; pos++) {
c52eba0224a0ff239f4778a7f6ed5ce38d92a5ddTimo Sirainen if (!IS_LWSP(line->value[pos]))
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (pos == line->value_len) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* everything was LWSP */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (line->value_len > 0 &&
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen IS_LWSP(line->value[0]))
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen pos = 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen pos = line->value_len > 0 &&
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen IS_LWSP(line->value[0]) ? 1 : 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value += pos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value_len -= pos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value_offset += pos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* get name, skip LWSP before ':' */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1]))
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen colon_pos--;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen str_truncate(ctx->name, 0);
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen /* use buffer_append() so the name won't be truncated if there
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen are NULs. */
200500ebd3c93a5771e7ae2f442659b9acb16eb6Timo Sirainen buffer_append(ctx->name, msg, colon_pos);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen str_append_c(ctx->name, '\0');
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen /* keep middle stored also in ctx->name so it's available
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen with use_full_value */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->middle = msg + colon_pos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->middle_len = (size_t)(line->value - line->middle);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen str_append_n(ctx->name, line->middle, line->middle_len);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->name = str_c(ctx->name);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen line->name_len = colon_pos;
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen line->middle = str_data(ctx->name) + line->name_len + 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (!line->continued) {
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen /* first header line. make a copy of the line since we can't
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen really trust input stream not to lose it. */
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen buffer_append(ctx->value_buf, line->value, line->value_len);
1ff487015234b23c32cf8bb4c9f8c02922535b8eTimo Sirainen line->value = line->full_value = ctx->value_buf->data;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value_len = line->value_len;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else if (line->use_full_value) {
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen /* continue saving the full value. */
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen if (last_no_newline) {
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen /* line is longer than fit into our buffer, so we
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen were forced to break it into multiple
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen message_header_lines */
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen } else {
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen if (last_crlf)
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen buffer_append_c(ctx->value_buf, '\r');
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen buffer_append_c(ctx->value_buf, '\n');
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen }
23bdbb7b1831785c6ba6df190f6369da882d2b9dTimo Sirainen if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0 &&
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen line->value_len > 0 && line->value[0] != ' ' &&
15362cdf9df29fef8795e865957e17ec027a9ebfTimo Sirainen IS_LWSP(line->value[0])) {
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen buffer_append_c(ctx->value_buf, ' ');
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen buffer_append(ctx->value_buf,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen line->value + 1, line->value_len - 1);
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen } else {
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen buffer_append(ctx->value_buf,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen line->value, line->value_len);
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen }
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen line->full_value = ctx->value_buf->data;
b88c43d09a288e99d439c78de4cc613212ea924cTimo Sirainen line->full_value_len = ctx->value_buf->used;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* we didn't want full_value, and this is a continued line. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value_len = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* always reset it */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->use_full_value = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL) {
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen ctx->hdr_size->physical_size += skip;
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen ctx->hdr_size->virtual_size += skip;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
a556e29bb9e48968b88c783148f3308bf90c7912Timo Sirainen i_stream_skip(ctx->input, skip);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen *hdr_r = line;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenbool message_parse_header_has_nuls(const struct message_header_parser_ctx *ctx)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return ctx->has_nuls;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
59151b71059df1190acd75d8717ed04a7920c862Timo Sirainen#undef message_parse_header
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenvoid message_parse_header(struct istream *input, struct message_size *hdr_size,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen enum message_header_parser_flags flags,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen message_header_callback_t *callback, void *context)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen{
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_parser_ctx *hdr_ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_line *hdr;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int ret;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen hdr_ctx = message_parse_header_init(input, hdr_size, flags);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen callback(hdr, context);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_assert(ret != 0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen message_parse_header_deinit(&hdr_ctx);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* call after the final skipping */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen callback(NULL, context);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainenvoid message_header_line_write(buffer_t *output,
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen const struct message_header_line *hdr)
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen{
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen if (!hdr->continued) {
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen buffer_append(output, hdr->name, strlen(hdr->name));
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen buffer_append(output, hdr->middle, hdr->middle_len);
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen }
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen buffer_append(output, hdr->value, hdr->value_len);
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen if (!hdr->no_newline) {
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen if (hdr->crlf_newline)
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen buffer_append_c(output, '\r');
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen buffer_append_c(output, '\n');
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen }
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen}