message-header-parser.c revision e161a5225abda0837b5deb8746ef808ba5e98d94
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* Copyright (C) 2002-2006 Timo Sirainen */
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 size_t skip;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int skip_initial_lwsp:1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int skip_line:1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen unsigned int 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,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen bool skip_initial_lwsp)
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);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip_initial_lwsp = skip_initial_lwsp;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen memset(hdr_size, 0, sizeof(*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
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->value_buf != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo 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;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t i, size, startpos, colon_pos, parse_size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen int ret;
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen bool last_no_newline, last_crlf;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen *hdr_r = NULL;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (line->eoh)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->skip > 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen startpos = 0; colon_pos = UINT_MAX;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen last_crlf = line->crlf_newline;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen last_no_newline = line->no_newline;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->no_newline = FALSE;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen line->crlf_newline = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (line->continues) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (line->use_full_value && !line->continued) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* save the first line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->value_buf != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen buffer_set_used_size(ctx->value_buf, 0);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->value_buf =
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen buffer_create_dynamic(default_pool,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen 4096);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen buffer_append(ctx->value_buf,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->value, line->value_len);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->continued = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->continues = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen colon_pos = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* new header line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->continued = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->name_offset = ctx->input->v_offset;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen for (;;) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret > 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* we want to know one byte in advance to find out
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if it's multiline header */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen parse_size = size-1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen parse_size = size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret <= 0 && startpos == size) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret == -1) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (startpos > 0) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* header ended unexpectedly. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->no_newline = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip = startpos;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* error / EOF with no bytes */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return -1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret == 0 && !ctx->input->eof) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* stream is nonblocking - need more data */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (msg[0] == '\n' ||
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 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') {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip = 2;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen line->crlf_newline = TRUE;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen } else {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip = 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size++;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* a) line is larger than input buffer
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen b) header ended unexpectedly */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (colon_pos == UINT_MAX && ret == -2 &&
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen !line->continued) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* header name is huge. just skip it. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (msg[size-1] == '\r')
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size--;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->physical_size += size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size += size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_stream_skip(ctx->input, size);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip_line = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen startpos = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen continue;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ret == -2) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* go back to last LWSP if found. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t min_pos =
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen !line->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 }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->continues = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->no_newline = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->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
064ccad9cea2a75a0d6caa2c679b6cd22be58174Timo Sirainen if (msg[i] == ':') {
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
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (i < parse_size) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* got a line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->skip_line) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* skipping a huge line */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->hdr_size != NULL) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->physical_size += i;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size += i;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen }
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++;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen } else {
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen line->crlf_newline = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen i_stream_skip(ctx->input, i);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen startpos = 0;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip_line = FALSE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen continue;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->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;
51c331377beb4a2acb81aee4d12bc8ef6c496625Timo Sirainen line->crlf_newline = TRUE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->skip = i+1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen break;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen startpos = i;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (size == 0) {
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;
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);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen str_append_n(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;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (ctx->skip_initial_lwsp) {
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++) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen if (!IS_LWSP(line->value[0]))
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);
f3aff3c6bf32d5bb0a61993b76a3fbe5ad798c09Timo Sirainen str_append_n(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) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* first header line, set full_value = value */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value = line->value;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen line->full_value_len = line->value_len;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen } else if (line->use_full_value) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen /* continue saving the full value */
e161a5225abda0837b5deb8746ef808ba5e98d94Timo Sirainen if (!last_no_newline) {
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 }
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 &line->full_value_len);
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) {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->physical_size += ctx->skip;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ctx->hdr_size->virtual_size += ctx->skip;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen }
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen *hdr_r = line;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen return 1;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen}
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenbool message_parse_header_has_nuls(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,
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
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 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}