message-header-parser.c revision c2f2a6cdf7dd55a4aabe72495cabb4deaa59cffc
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2007 Dovecot authors, see the included COPYING file */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "lib.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "buffer.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#include "istream.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "str.h"
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen#include "message-size.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen#include "message-header-parser.h"
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenstruct message_header_parser_ctx {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct message_header_line line;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi struct istream *input;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct message_size *hdr_size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen string_t *name;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen buffer_t *value_buf;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen size_t skip;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen enum message_header_parser_flags flags;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen unsigned int skip_line:1;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen unsigned int has_nuls:1;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen};
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainenstruct message_header_parser_ctx *
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen enum message_header_parser_flags flags)
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen{
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen struct message_header_parser_ctx *ctx;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx = i_new(struct message_header_parser_ctx, 1);
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen ctx->input = input;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->hdr_size = hdr_size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->name = str_new(default_pool, 128);
8a2df8a89fc61c584429534a57a2ea20fcaf2d28Timo Sirainen ctx->flags = flags;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (hdr_size != NULL)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen memset(hdr_size, 0, sizeof(*hdr_size));
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch return ctx;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen{
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen struct message_header_parser_ctx *ctx = *_ctx;
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen
2303ad68175883aaebd1f3b18e69593c2422c7bbTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen if (ctx->value_buf != NULL)
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen buffer_free(&ctx->value_buf);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_free(&ctx->name);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_free(ctx);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen *_ctx = NULL;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen struct message_header_line **hdr_r)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen{
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 int ret;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen bool continued, continues, last_no_newline, last_crlf;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen *hdr_r = NULL;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (line->eoh)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return -1;
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->skip > 0) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->skip = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen startpos = 0; colon_pos = UINT_MAX;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen last_crlf = line->crlf_newline &&
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) == 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen last_no_newline = line->no_newline ||
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->no_newline = FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->crlf_newline = FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (line->continues) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (line->use_full_value && !line->continued) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* save the first line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->value_buf != NULL)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen buffer_set_used_size(ctx->value_buf, 0);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen else {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->value_buf =
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen buffer_create_dynamic(default_pool,
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen 4096);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen buffer_append(ctx->value_buf,
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->value, line->value_len);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->value_len = 0;
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen colon_pos = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* new header line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->name_offset = ctx->input->v_offset;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continued = line->continues;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continues = FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (;;) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ret >= 0) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* we want to know one byte in advance to find out
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if it's multiline header */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen parse_size = size-1;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen parse_size = size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ret <= 0 && startpos == parse_size) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ret == -1) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (startpos > 0) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* header ended unexpectedly. */
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen line->no_newline = TRUE;
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen ctx->skip = startpos;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen break;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* error / EOF with no bytes */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return -1;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ret == 0 && !ctx->input->eof) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* stream is nonblocking - need more data */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen return 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[0] == '\n' ||
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
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen from body */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen size = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->hdr_size != NULL)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->hdr_size->lines++;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[0] == '\r') {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->skip = 2;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->crlf_newline = TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->skip = 1;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->hdr_size != NULL)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->hdr_size->virtual_size++;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen break;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
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 if (msg[size-1] == '\r')
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen size--;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen if (ctx->hdr_size != NULL) {
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen ctx->hdr_size->physical_size += size;
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen ctx->hdr_size->virtual_size += size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_stream_skip(ctx->input, size);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->skip_line = TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen startpos = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ret == -2) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* go back to last LWSP if found. */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen size_t min_pos = !continued ? colon_pos : 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (i = size-1; i > min_pos; i--) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (IS_LWSP(msg[i])) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen size = i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen break;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continues = TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen line->no_newline = TRUE;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen ctx->skip = size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen break;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen
67d86acc16b837a01d0967b65fc9a81ccf54ef0bTimo Sirainen /* find ':' */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (colon_pos == UINT_MAX) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (i = startpos; i < parse_size; i++) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[i] > ':')
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[i] == ':') {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen colon_pos = i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->full_value_offset =
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->input->v_offset + i + 1;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen break;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[i] == '\n') {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* end of headers, or error */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen break;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[i] == '\0')
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->has_nuls = TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i = startpos;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* find '\n' */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen for (; i < parse_size; i++) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (msg[i] <= '\n') {
0beef9bf818accfb629a92ef53ff0f6a15005941Timo Sirainen if (msg[i] == '\n')
0beef9bf818accfb629a92ef53ff0f6a15005941Timo Sirainen break;
0beef9bf818accfb629a92ef53ff0f6a15005941Timo Sirainen if (msg[i] == '\0')
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->has_nuls = TRUE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (i < parse_size) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* got a line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->skip_line) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* skipping a huge line */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->hdr_size != NULL) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->hdr_size->physical_size += i;
efe78d3ba24fc866af1c79b9223dc0809ba26cadStephan Bosch ctx->hdr_size->virtual_size += i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
678d0463849ba777106eb7875f27db07a5d8e3dfTimo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* missing CR */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->hdr_size != NULL)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->hdr_size->virtual_size++;
4338c7b02e15779efaee5cedd4a355c946d9d4c2Timo Sirainen } else {
4338c7b02e15779efaee5cedd4a355c946d9d4c2Timo Sirainen line->crlf_newline = TRUE;
4338c7b02e15779efaee5cedd4a355c946d9d4c2Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_stream_skip(ctx->input, i);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen startpos = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen ctx->skip_line = FALSE;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen continue;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen continues = i+1 < size && IS_LWSP(msg[i+1]);
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (ctx->hdr_size != NULL)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen ctx->hdr_size->lines++;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen /* missing CR */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (ctx->hdr_size != NULL)
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen ctx->hdr_size->virtual_size++;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen size = i;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen } else {
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen size = i-1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen line->crlf_newline = TRUE;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen ctx->skip = i+1;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen break;
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen }
deb06d37292d9112d74bdf80cfebb92ab5151679Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen startpos = i;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen }
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->continues = continues;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen if (size == 0) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* end of headers */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->eoh = TRUE;
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 line->middle = NULL; line->middle_len = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else if (line->continued) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->value = msg;
a75d470c9223a75801418fcdda258885c36317e0Timo Sirainen line->value_len = size;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else if (colon_pos == UINT_MAX) {
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen /* missing ':', assume the whole line is name */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->value = NULL;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->value_len = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_truncate(ctx->name, 0);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen str_append_n(ctx->name, msg, size);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->name = str_c(ctx->name);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->name_len = str_len(ctx->name);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->middle = NULL;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen line->middle_len = 0;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen } else {
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi size_t pos;
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
2ac5f36aa7c2e7a07ba8815d43a6d7483f62e74cTimo Sirainen line->value = msg + colon_pos+1;
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen line->value_len = size - colon_pos - 1;
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
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen it..
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi Exception to this is if the value consists only of
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi LWSP, then skip only the one LWSP after ':'. */
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi for (pos = 0; pos < line->value_len; pos++) {
96f35f249ab0d8d19c5201f6e6c850514ad36971Timo Sirainen if (!IS_LWSP(line->value[0]))
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi break;
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi }
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen if (pos == line->value_len) {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* everything was LWSP */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen if (line->value_len > 0 &&
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen IS_LWSP(line->value[0]))
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen pos = 1;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen } else {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen pos = line->value_len > 0 &&
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen IS_LWSP(line->value[0]) ? 1 : 0;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen }
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->value += pos;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->value_len -= pos;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->full_value_offset += pos;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* get name, skip LWSP before ':' */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1]))
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen colon_pos--;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi str_truncate(ctx->name, 0);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi str_append_n(ctx->name, msg, colon_pos);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi str_append_c(ctx->name, '\0');
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen /* keep middle stored also in ctx->name so it's available
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen with use_full_value */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->middle = msg + colon_pos;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->middle_len = (size_t)(line->value - line->middle);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen str_append_n(ctx->name, line->middle, line->middle_len);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->name = str_c(ctx->name);
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->name_len = colon_pos;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->middle = str_data(ctx->name) + line->name_len + 1;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen }
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (!line->continued) {
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen /* first header line, set full_value = value */
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->full_value = line->value;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen line->full_value_len = line->value_len;
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen } else if (line->use_full_value) {
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen /* continue saving the full value */
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (!last_no_newline) {
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (last_crlf)
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen buffer_append_c(ctx->value_buf, '\r');
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen buffer_append_c(ctx->value_buf, '\n');
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen }
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) &&
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->value_len > 0 && line->value[0] != ' ') {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen i_assert(IS_LWSP(line->value[0]));
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen buffer_append_c(ctx->value_buf, ' ');
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen buffer_append(ctx->value_buf,
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->value + 1, line->value_len - 1);
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen } else {
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen buffer_append(ctx->value_buf,
bace943c67e6cd14ce6c994f533d82a3caad5bf1Timo Sirainen line->value, line->value_len);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi }
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi line->full_value = buffer_get_data(ctx->value_buf,
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi &line->full_value_len);
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi } else {
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi /* we didn't want full_value, and this is a continued line. */
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi line->full_value = NULL;
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi line->full_value_len = 0;
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi }
8fdbe2f47df7cbe4ffe163e7c13f52d2649a0dfbAki Tuomi
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen /* always reset it */
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen line->use_full_value = FALSE;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
8f0c238dcbbfa3b984b102260a2440adac667ae8Timo Sirainen if (ctx->hdr_size != NULL) {
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen ctx->hdr_size->physical_size += ctx->skip;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen ctx->hdr_size->virtual_size += ctx->skip;
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen }
5fbccc935e3f7b916aa7c6e302a212821072e83aTimo Sirainen
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen *hdr_r = line;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen return 1;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen}
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainenbool message_parse_header_has_nuls(struct message_header_parser_ctx *ctx)
bde78a7bf5f9000f1ae4dc7ce6cabd012e1f8b79Pascal Volk{
bde78a7bf5f9000f1ae4dc7ce6cabd012e1f8b79Pascal Volk return ctx->has_nuls;
acba68a69cdd6f3f00faa18cccef356d95048e46Timo Sirainen}
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi#undef message_parse_header
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomivoid message_parse_header(struct istream *input, struct message_size *hdr_size,
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi enum message_header_parser_flags flags,
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi message_header_callback_t *callback, void *context)
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi{
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi struct message_header_parser_ctx *hdr_ctx;
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi struct message_header_line *hdr;
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi int ret;
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen hdr_ctx = message_parse_header_init(input, hdr_size, flags);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0)
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen callback(hdr, context);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen i_assert(ret != 0);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen message_parse_header_deinit(&hdr_ctx);
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi
0ed5452f5fcff082087622e473d790403f66a0e2Aki Tuomi /* call after the final skipping */
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen callback(NULL, context);
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen}
bf333c7645b8ddb6eedd6834db2fd908888793e1Timo Sirainen