message-header-parser.c revision c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffc
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx = i_new(struct message_header_parser_ctx, 1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen struct message_header_parser_ctx *ctx = *_ctx;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct message_header_line *line = &ctx->line;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen const unsigned char *msg;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen size_t i, size, startpos, colon_pos, parse_size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen bool continued, continues, last_no_newline, last_crlf;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) == 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (line->use_full_value && !line->continued) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* save the first line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* new header line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* we want to know one byte in advance to find out
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if it's multiline header */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* header ended unexpectedly. */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* error / EOF with no bytes */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* stream is nonblocking - need more data */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (msg[0] == '\r' && size > 1 && msg[1] == '\n')) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* end of headers - this mostly happens just
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen with mbox where headers are read separately
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* a) line is larger than input buffer
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen b) header ended unexpectedly */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (colon_pos == UINT_MAX && ret == -2 && !continued) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* header name is huge. just skip it. */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* go back to last LWSP if found. */
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen /* find ':' */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* end of headers, or error */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* find '\n' */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (; i < parse_size; i++) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* got a line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* skipping a huge line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* missing CR */
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* missing CR */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* end of headers */
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen line->name_len = line->value_len = line->full_value_len = 0;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen line->name = ""; line->value = line->full_value = NULL;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* missing ':', assume the whole line is name */
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen if (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP) {
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen /* get value. skip all LWSP after ':'. Note that
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen RFC2822 doesn't say we should, but history behind
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi Exception to this is if the value consists only of
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi LWSP, then skip only the one LWSP after ':'. */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* everything was LWSP */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* get name, skip LWSP before ':' */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1]))
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen /* keep middle stored also in ctx->name so it's available
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen with use_full_value */
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->middle_len = (size_t)(line->value - line->middle);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen str_append_n(ctx->name, line->middle, line->middle_len);
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->middle = str_data(ctx->name) + line->name_len + 1;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen /* first header line, set full_value = value */
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen /* continue saving the full value */
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) &&
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->value_len > 0 && line->value[0] != ' ') {
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi line->full_value = buffer_get_data(ctx->value_buf,
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi /* we didn't want full_value, and this is a continued line. */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* always reset it */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenbool message_parse_header_has_nuls(struct message_header_parser_ctx *ctx)
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomivoid message_parse_header(struct istream *input, struct message_size *hdr_size,
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi message_header_callback_t *callback, void *context)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen hdr_ctx = message_parse_header_init(input, hdr_size, flags);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0)
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi /* call after the final skipping */