message-header-parser.c revision bcb4e51a409d94ae670de96afb8483a4f7855294
/* Copyright (c) 2002-2018 Dovecot authors, see the included COPYING file */
#include "lib.h"
#include "buffer.h"
#include "istream.h"
#include "str.h"
#include "message-size.h"
#include "message-header-parser.h"
struct message_header_parser_ctx {
struct message_header_line line;
struct message_size *hdr_size;
bool skip_line:1;
bool has_nuls:1;
};
struct message_header_parser_ctx *
{
struct message_header_parser_ctx *ctx;
return ctx;
}
{
}
struct message_header_line **hdr_r)
{
const unsigned char *msg;
int ret;
bool no_newline, crlf_newline;
return -1;
colon_pos = 0;
else {
/* new header line */
}
no_newline = FALSE;
for (startpos = 0;;) {
if (ret >= 0) {
/* we want to know one byte in advance to find out
if it's multiline header */
} else {
parse_size = size;
}
if (ret == -1) {
if (startpos > 0) {
/* header ended unexpectedly. */
no_newline = TRUE;
break;
}
/* error / EOF with no bytes */
return -1;
}
(msg[0] == '\n' ||
/* end of headers - this mostly happens just
with mbox where headers are read separately
from body */
size = 0;
if (msg[0] == '\r') {
skip = 2;
crlf_newline = TRUE;
} else {
skip = 1;
}
break;
}
/* stream is nonblocking - need more data */
return 0;
}
/* a) line is larger than input buffer
b) header ended unexpectedly */
if (ret == -2) {
/* go back to last LWSP if found. */
size = i;
break;
}
}
/* we may or may not have a full header,
but we don't know until we get the
next character. leave out the
linefeed and finish the header on
the next run. */
size--;
size--;
}
/* the buffer really has to be more than 2 to
avoid CRLF looping forever */
}
no_newline = TRUE;
break;
}
/* find ':' */
for (i = startpos; i < parse_size; i++) {
if (msg[i] > ':')
continue;
colon_pos = i;
break;
}
if (msg[i] == '\n') {
/* end of headers, or error */
break;
}
if (msg[i] == '\0')
}
} else {
i = startpos;
}
/* find '\n' */
for (; i < parse_size; i++) {
if (msg[i] <= '\n') {
if (msg[i] == '\n')
break;
if (msg[i] == '\0')
}
}
/* we don't know if the line continues. */
i++;
} else if (i < parse_size) {
/* got a line */
/* skipping a line with a huge header name */
}
/* missing CR */
}
startpos = 0;
continue;
}
/* missing CR */
size = i;
} else {
size = i-1;
crlf_newline = TRUE;
}
skip = i+1;
break;
}
startpos = i;
}
/* end of headers */
/* missing ':', assume the whole line is name */
line->middle_len = 0;
} else {
/* 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 ':'. */
break;
}
/* everything was LWSP */
pos = 1;
}
} else {
}
/* get name, skip LWSP before ':' */
colon_pos--;
/* use buffer_append() so the name won't be truncated if there
are NULs. */
/* keep middle stored also in ctx->name so it's available
with use_full_value */
}
/* first header line. make a copy of the line since we can't
really trust input stream not to lose it. */
} 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)
}
} else {
}
} else {
/* we didn't want full_value, and this is a continued line. */
line->full_value_len = 0;
}
/* always reset it */
}
return 1;
}
{
}
{
struct message_header_parser_ctx *hdr_ctx;
struct message_header_line *hdr;
int ret;
/* call after the final skipping */
}
const struct message_header_line *hdr)
{
}
if (!hdr->no_newline) {
if (hdr->crlf_newline)
}
}