message-header-parser.c revision 15362cdf9df29fef8795e865957e17ec027a9ebf
2454dfa32c93c20a8522c6ed42fe057baaac9f9aStephan Bosch/* Copyright (c) 2002-2008 Dovecot authors, see the included COPYING file */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "lib.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "buffer.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "istream.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "str.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "message-size.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen#include "message-header-parser.h"
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
b7324e421e2132cbbf753e6fdbe675bbaecdf929Timo Sirainenstruct message_header_parser_ctx {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct message_header_line line;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct istream *input;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen struct message_size *hdr_size;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen string_t *name;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen buffer_t *value_buf;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen size_t skip;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen enum message_header_parser_flags flags;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen unsigned int skip_line:1;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen unsigned int has_nuls:1;
c9099b08b3cae8a849098ca776b4363c6d5f5f36Timo Sirainen};
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenstruct message_header_parser_ctx *
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen enum message_header_parser_flags flags)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen struct message_header_parser_ctx *ctx;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx = i_new(struct message_header_parser_ctx, 1);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->input = input;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->hdr_size = hdr_size;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->name = str_new(default_pool, 128);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->flags = flags;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (hdr_size != NULL)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen memset(hdr_size, 0, sizeof(*hdr_size));
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen return ctx;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen}
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
92f5ea24e989266539e97c6fe59ede0565aec6fdTimo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **_ctx)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen{
fb79b36eb34532dbe67caf99eefe3660b8c841e0Timo Sirainen struct message_header_parser_ctx *ctx = *_ctx;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen
92f5ea24e989266539e97c6fe59ede0565aec6fdTimo Sirainen i_stream_skip(ctx->input, ctx->skip);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen if (ctx->value_buf != NULL)
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen buffer_free(&ctx->value_buf);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen str_free(&ctx->name);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen i_free(ctx);
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen *_ctx = NULL;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen}
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen struct message_header_line **hdr_r)
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen{
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen struct message_header_line *line = &ctx->line;
1c0020171b04d14adc4966ed963361abc9a86787Timo Sirainen const unsigned char *msg;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen size_t i, size, startpos, colon_pos, parse_size;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen int ret;
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen bool continued, continues, last_no_newline, last_crlf;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen bool no_newline, crlf_newline;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen *hdr_r = NULL;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (line->eoh)
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen return -1;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (ctx->skip > 0) {
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen i_stream_skip(ctx->input, ctx->skip);
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen ctx->skip = 0;
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (line->continues) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen if (line->use_full_value && !line->continued) {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen /* save the first line */
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen if (ctx->value_buf != NULL)
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen buffer_set_used_size(ctx->value_buf, 0);
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen else {
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen ctx->value_buf =
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen buffer_create_dynamic(default_pool,
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen 4096);
df8046c9a4f6bc2a478ad1e74504d50f3110c906Timo Sirainen }
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen buffer_append(ctx->value_buf,
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen line->value, line->value_len);
7000810786f2959f02cd6d2f4151a9eb61ff5db8Timo Sirainen }
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen colon_pos = 0;
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen } else {
abb5d20d3155db02a1afec4066d52707ba9d4e52Timo Sirainen /* new header line */
2aee623fcad4b931c27435ceaa495c3d3edd69b6Aki Tuomi line->name_offset = ctx->input->v_offset;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen colon_pos = UINT_MAX;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen }
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen no_newline = FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen crlf_newline = FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen continued = line->continues;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen continues = FALSE;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen for (startpos = 0;;) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen ret = i_stream_read_data(ctx->input, &msg, &size, startpos+1);
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if (ret >= 0) {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen /* we want to know one byte in advance to find out
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen if it's multiline header */
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen parse_size = size == 0 ? 0 : size-1;
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen } else {
d6a7cb184cc882a90aa3d9312082e0029f354ff6Timo Sirainen parse_size = size;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (ret <= 0 && startpos == parse_size) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (ret == -1) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen if (startpos > 0) {
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* header ended unexpectedly. */
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen no_newline = TRUE;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen ctx->skip = startpos;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen break;
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen }
f5e8a76a128d4e92f0641135183c164fd5c5ce5eTimo Sirainen /* error / EOF with no bytes */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return -1;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (ret == 0 && !ctx->input->eof) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* stream is nonblocking - need more data */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen return 0;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen }
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (msg[0] == '\n' ||
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen (msg[0] == '\r' && size > 1 && msg[1] == '\n')) {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen /* end of headers - this mostly happens just
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen with mbox where headers are read separately
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen from body */
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen size = 0;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (ctx->hdr_size != NULL)
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ctx->hdr_size->lines++;
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen if (msg[0] == '\r') {
cc935aff970ed6c24d136cc560c7e705a49d536cTimo Sirainen ctx->skip = 2;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen crlf_newline = TRUE;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen } else {
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen ctx->skip = 1;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen if (ctx->hdr_size != NULL)
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen ctx->hdr_size->virtual_size++;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen }
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen break;
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen }
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen /* a) line is larger than input buffer
279c6b6d0b0a159c8533102e7e914db21dadcb03Timo Sirainen b) header ended unexpectedly */
387f9e3b4120273ad0213206a0e9cc2dc0e62ccaTimo Sirainen if (colon_pos == UINT_MAX && ret == -2 && !continued) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen /* header name is huge. just skip it. */
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen if (msg[size-1] == '\r')
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen size--;
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen
071543cc13df9600d2e97aa35f28907be5a79477Timo Sirainen if (ctx->hdr_size != NULL) {
27e859cee42654bff801ba96677cfc4e4e0108c7Timo Sirainen ctx->hdr_size->physical_size += size;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen ctx->hdr_size->virtual_size += size;
387f9e3b4120273ad0213206a0e9cc2dc0e62ccaTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen i_stream_skip(ctx->input, size);
632018810af689442569cbb0139c55868923ccfeTimo Sirainen ctx->skip_line = TRUE;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen startpos = 0;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen continue;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
632018810af689442569cbb0139c55868923ccfeTimo Sirainen
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (ret == -2) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen /* go back to last LWSP if found. */
632018810af689442569cbb0139c55868923ccfeTimo Sirainen size_t min_pos = !continued ? colon_pos : 0;
387f9e3b4120273ad0213206a0e9cc2dc0e62ccaTimo Sirainen for (i = size-1; i > min_pos; i--) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen if (IS_LWSP(msg[i])) {
632018810af689442569cbb0139c55868923ccfeTimo Sirainen size = i;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen break;
632018810af689442569cbb0139c55868923ccfeTimo Sirainen }
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen }
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen continues = TRUE;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen }
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen no_newline = TRUE;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen ctx->skip = size;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen break;
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen }
8d3af185ae454653fad60e41c5f36edb1d45c868Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen /* find ':' */
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (colon_pos == UINT_MAX) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen for (i = startpos; i < parse_size; i++) {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (msg[i] > ':')
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen continue;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (msg[i] == ':') {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen colon_pos = i;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen line->full_value_offset =
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen ctx->input->v_offset + i + 1;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen break;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen }
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen if (msg[i] == '\n') {
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen /* end of headers, or error */
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen break;
dea8bfa31729dbdde1b12718f1ef98fac4e99db9Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (msg[i] == '\0')
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->has_nuls = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen } else {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen i = startpos;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* find '\n' */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen for (; i < parse_size; i++) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (msg[i] <= '\n') {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (msg[i] == '\n')
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen break;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (msg[i] == '\0')
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->has_nuls = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (i < parse_size) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* got a line */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (ctx->skip_line) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* skipping a huge line */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (ctx->hdr_size != NULL) {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->hdr_size->physical_size += i;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->hdr_size->virtual_size += i;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (i == 0 || msg[i-1] != '\r') {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen /* missing CR */
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen if (ctx->hdr_size != NULL)
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->hdr_size->virtual_size++;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen } else {
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen crlf_newline = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen i_stream_skip(ctx->input, i);
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen startpos = 0;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->skip_line = FALSE;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen continue;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen }
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen continues = i+1 < size && IS_LWSP(msg[i+1]);
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen if (ctx->hdr_size != NULL)
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen ctx->hdr_size->lines++;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen if (i == 0 || msg[i-1] != '\r') {
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen /* missing CR */
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen if (ctx->hdr_size != NULL)
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen ctx->hdr_size->virtual_size++;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen size = i;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen } else {
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen size = i-1;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen crlf_newline = TRUE;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
baf3e87e186453fda13bd21f7cbcb2efc8492e8bTimo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen ctx->skip = i+1;
6de0cbb4a498ce0519b0f28e221164ce8d39736aTimo Sirainen break;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen startpos = i;
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen }
f8740ac53310cd28ba4ec6dc9e9ce6e9a3688f39Timo Sirainen
last_crlf = line->crlf_newline &&
(ctx->flags & MESSAGE_HEADER_PARSER_FLAG_DROP_CR) == 0;
last_no_newline = line->no_newline ||
(ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) != 0;
line->continues = continues;
line->continued = continued;
line->crlf_newline = crlf_newline;
line->no_newline = no_newline;
if (size == 0) {
/* end of headers */
line->eoh = TRUE;
line->name_len = line->value_len = line->full_value_len = 0;
line->name = ""; line->value = line->full_value = NULL;
line->middle = NULL; line->middle_len = 0;
} else if (line->continued) {
line->value = msg;
line->value_len = size;
} else if (colon_pos == UINT_MAX) {
/* missing ':', assume the whole line is name */
line->value = NULL;
line->value_len = 0;
str_truncate(ctx->name, 0);
str_append_n(ctx->name, msg, size);
line->name = str_c(ctx->name);
line->name_len = str_len(ctx->name);
line->middle = NULL;
line->middle_len = 0;
} else {
size_t pos;
line->value = msg + colon_pos+1;
line->value_len = size - colon_pos - 1;
if (ctx->flags & MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP) {
/* get value. skip all LWSP after ':'. Note that
RFC2822 doesn't say we should, but history behind
it..
Exception to this is if the value consists only of
LWSP, then skip only the one LWSP after ':'. */
for (pos = 0; pos < line->value_len; pos++) {
if (!IS_LWSP(line->value[0]))
break;
}
if (pos == line->value_len) {
/* everything was LWSP */
if (line->value_len > 0 &&
IS_LWSP(line->value[0]))
pos = 1;
}
} else {
pos = line->value_len > 0 &&
IS_LWSP(line->value[0]) ? 1 : 0;
}
line->value += pos;
line->value_len -= pos;
line->full_value_offset += pos;
/* get name, skip LWSP before ':' */
while (colon_pos > 0 && IS_LWSP(msg[colon_pos-1]))
colon_pos--;
str_truncate(ctx->name, 0);
str_append_n(ctx->name, msg, colon_pos);
str_append_c(ctx->name, '\0');
/* keep middle stored also in ctx->name so it's available
with use_full_value */
line->middle = msg + colon_pos;
line->middle_len = (size_t)(line->value - line->middle);
str_append_n(ctx->name, line->middle, line->middle_len);
line->name = str_c(ctx->name);
line->name_len = colon_pos;
line->middle = str_data(ctx->name) + line->name_len + 1;
}
if (!line->continued) {
/* first header line, set full_value = value */
line->full_value = line->value;
line->full_value_len = line->value_len;
} else if (line->use_full_value) {
/* continue saving the full value. */
if (last_no_newline) {
/* line is longer than fit into our buffer, so we
were forced to break it into multiple
message_header_lines */
} else {
if (last_crlf)
buffer_append_c(ctx->value_buf, '\r');
buffer_append_c(ctx->value_buf, '\n');
}
if ((ctx->flags & MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE) &&
line->value_len > 0 && line->value[0] != ' ' &&
IS_LWSP(line->value[0])) {
buffer_append_c(ctx->value_buf, ' ');
buffer_append(ctx->value_buf,
line->value + 1, line->value_len - 1);
} else {
buffer_append(ctx->value_buf,
line->value, line->value_len);
}
line->full_value = buffer_get_data(ctx->value_buf,
&line->full_value_len);
} else {
/* we didn't want full_value, and this is a continued line. */
line->full_value = NULL;
line->full_value_len = 0;
}
/* always reset it */
line->use_full_value = FALSE;
if (ctx->hdr_size != NULL) {
ctx->hdr_size->physical_size += ctx->skip;
ctx->hdr_size->virtual_size += ctx->skip;
}
*hdr_r = line;
return 1;
}
bool message_parse_header_has_nuls(struct message_header_parser_ctx *ctx)
{
return ctx->has_nuls;
}
#undef message_parse_header
void message_parse_header(struct istream *input, struct message_size *hdr_size,
enum message_header_parser_flags flags,
message_header_callback_t *callback, void *context)
{
struct message_header_parser_ctx *hdr_ctx;
struct message_header_line *hdr;
int ret;
hdr_ctx = message_parse_header_init(input, hdr_size, flags);
while ((ret = message_parse_header_next(hdr_ctx, &hdr)) > 0)
callback(hdr, context);
i_assert(ret != 0);
message_parse_header_deinit(&hdr_ctx);
/* call after the final skipping */
callback(NULL, context);
}