message-header-parser.c revision 1ff487015234b23c32cf8bb4c9f8c02922535b8e
/* Copyright (c) 2002-2008 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;
unsigned int skip_line:1;
unsigned int 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;
}
/* stream is nonblocking - need more data */
return 0;
}
if (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') {
crlf_newline = TRUE;
} else {
}
break;
}
/* a) line is larger than input buffer
b) header ended unexpectedly */
/* header name is huge. just skip it. */
size--;
}
startpos = 0;
continue;
}
if (ret == -2) {
/* go back to last LWSP if found. */
size = i;
break;
}
}
}
no_newline = TRUE;
break;
}
/* find ':' */
for (i = startpos; i < parse_size; i++) {
if (msg[i] > ':')
continue;
if (msg[i] == ':') {
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')
}
}
if (i < parse_size) {
/* got a line */
/* skipping a huge line */
}
/* missing CR */
} else {
crlf_newline = TRUE;
}
startpos = 0;
continue;
}
/* missing CR */
size = i;
} else {
size = i-1;
crlf_newline = TRUE;
}
break;
}
startpos = i;
}
if (size == 0) {
/* 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--;
/* 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 {
}
&line->full_value_len);
} 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 */
}