message-header-parser.c revision e161a5225abda0837b5deb8746ef808ba5e98d94
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* Copyright (C) 2002-2006 Timo Sirainen */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx = i_new(struct message_header_parser_ctx, 1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_parser_ctx *ctx = *_ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_line *line = &ctx->line;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const unsigned char *msg;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t i, size, startpos, colon_pos, parse_size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (line->use_full_value && !line->continued) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* save the first line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* new header line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* we want to know one byte in advance to find out
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if it's multiline header */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* header ended unexpectedly. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* error / EOF with no bytes */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* stream is nonblocking - need more data */
d96f86fb881c5b106649e8994ead1052acf24030Timo 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 /* a) line is larger than input buffer
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen b) header ended unexpectedly */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* header name is huge. just skip it. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* go back to last LWSP if found. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* find ':' */
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen /* end of headers, or error */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* find '\n' */
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen for (; i < parse_size; i++) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* got a line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* skipping a huge line */
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen /* missing CR */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->continues = i+1 < size && IS_LWSP(msg[i+1]);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* missing CR */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* end of headers */
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 /* missing ':', assume the whole line is name */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* get value. skip all LWSP after ':'. Note that
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen RFC2822 doesn't say we should, but history behind
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen Exception to this is if the value consists only of
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen LWSP, then skip only the one LWSP after ':'. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* everything was LWSP */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* get name, skip LWSP before ':' */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1]))
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen /* keep middle stored also in ctx->name so it's available
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen with use_full_value */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->middle_len = (size_t)(line->value - line->middle);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen str_append_n(ctx->name, line->middle, line->middle_len);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen line->middle = str_data(ctx->name) + line->name_len + 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* first header line, set full_value = value */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* continue saving the full value */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen buffer_append(ctx->value_buf, line->value, line->value_len);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value = buffer_get_data(ctx->value_buf,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* we didn't want full_value, and this is a continued line. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* always reset it */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenbool message_parse_header_has_nuls(struct message_header_parser_ctx *ctx)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenvoid message_parse_header(struct istream *input, struct message_size *hdr_size,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen message_header_callback_t *callback, void *context)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen hdr_ctx = message_parse_header_init(input, hdr_size, TRUE);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* call after the final skipping */