message-header-parser.c revision 6cb3c4f4276531258be706821e034f1f0a8cd276
2e37d45867d081db150ab78dad303b9077aea24fTimo Sirainen/* Copyright (c) 2002-2012 Dovecot authors, see the included COPYING file */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ctx = i_new(struct message_header_parser_ctx, 1);
7823ef73e51bb81a17dcb306aff89016d4ce258fTimo Sirainen ctx->value_buf = buffer_create_dynamic(default_pool, 4096);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen struct message_header_parser_ctx *ctx = *_ctx;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen struct message_header_line *line = &ctx->line;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen const unsigned char *msg;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen size_t i, size, startpos, colon_pos, parse_size;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen bool continued, continues, last_no_newline, last_crlf;
64055bc6d2ed9e25b3b1db3b5b90d0bdb77cd715Timo Sirainen /* new header line */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* we want to know one byte in advance to find out
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if it's multiline header */
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* header ended unexpectedly. */
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* error / EOF with no bytes */
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen (msg[0] == '\r' && size > 1 && msg[1] == '\n'))) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* end of headers - this mostly happens just
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen with mbox where headers are read separately
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* stream is nonblocking - need more data */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* a) line is larger than input buffer
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen b) header ended unexpectedly */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen if (colon_pos == UINT_MAX && ret == -2 && !continued) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* header name is huge. just skip it. */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* go back to last LWSP if found. */
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* we may or may not have a full header,
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen but we don't know until we get the
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen next character. leave out the
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen linefeed and finish the header on
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen the next run. */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* find ':' */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* end of headers, or error */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* find '\n' */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen for (; i < parse_size; i++) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen if (i < parse_size && i+1 == size && ret == -2) {
beffc30d933c5e134c45cc871852a8427eba7e70Timo Sirainen /* we don't know if the line continues. */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen } else if (i < parse_size) {
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* got a line */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* skipping a line with a huge header name */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* missing CR */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* missing CR */
ab7b5b9286104974c2a572a499ccf8b56c5d2955Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) == 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* end of headers */
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen line->name_len = line->value_len = line->full_value_len = 0;
4ce6338bf945cccfff9e4ce7cc6aa2246851b84aTimo Sirainen line->name = ""; line->value = line->full_value = NULL;
f89cb43088c8b46d12d66ac924724b53ab14ce66Timo Sirainen /* missing ':', assume the whole line is name */
colon_pos--;
if (last_no_newline) {
if (last_crlf)
int ret;