c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#ifndef MESSAGE_HEADER_PARSER_H
c25356d5978632df6203437e1953bcb29e0c736fTimo Sirainen#define MESSAGE_HEADER_PARSER_H
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#define IS_LWSP(c) \
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen ((c) == ' ' || (c) == '\t')
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct message_size;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct message_header_parser_ctx;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainenenum message_header_parser_flags {
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen /* Don't add LWSP after "header: " to value. */
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen MESSAGE_HEADER_PARSER_FLAG_SKIP_INITIAL_LWSP = 0x01,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen /* Don't add CRs to full_value even if input had them */
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen MESSAGE_HEADER_PARSER_FLAG_DROP_CR = 0x02,
9d53cff7ba0e2fc5fd907d9194448d5090e1c403Timo Sirainen /* Convert [CR+]LF+LWSP to a space character in full_value */
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen MESSAGE_HEADER_PARSER_FLAG_CLEAN_ONELINE = 0x04
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen};
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct message_header_line {
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const char *name;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t name_len;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const unsigned char *value;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t value_len;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const unsigned char *full_value;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t full_value_len;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen const unsigned char *middle;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen size_t middle_len;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen uoff_t name_offset, full_value_offset;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool continues:1; /* multiline header, continues in next line */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool continued:1; /* multiline header, continues */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool eoh:1; /* "end of headers" line */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool no_newline:1; /* no \n after this line */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool crlf_newline:1; /* newline was \r\n */
0dffa25d211be541ee3c953b23566a1a990789dfTimo Sirainen bool use_full_value:1; /* set if you want full_value */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen};
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* called once with hdr = NULL at the end of headers */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainentypedef void message_header_callback_t(struct message_header_line *hdr,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen void *context);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenstruct message_header_parser_ctx *
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenmessage_parse_header_init(struct istream *input, struct message_size *hdr_size,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen enum message_header_parser_flags flags) ATTR_NULL(2);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenvoid message_parse_header_deinit(struct message_header_parser_ctx **ctx);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* Read and return next header line. Returns 1 if header is returned, 0 if
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen input stream is non-blocking and more data needs to be read, -1 when all is
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen done or error occurred (see stream's error status). */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenint message_parse_header_next(struct message_header_parser_ctx *ctx,
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen struct message_header_line **hdr_r);
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* Returns TRUE if the parser has seen NUL characters. */
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainenbool message_parse_header_has_nuls(const struct message_header_parser_ctx *ctx)
68a4946b12583b88fa802e52ebee45cd96056772Timo Sirainen ATTR_PURE;
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen/* Read and parse the header from the given stream. */
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainenvoid message_parse_header(struct istream *input, struct message_size *hdr_size,
043c8a96a035379bcba04f487d58457beefdfcaaTimo Sirainen enum message_header_parser_flags flags,
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen message_header_callback_t *callback, void *context)
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen ATTR_NULL(2);
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen#define message_parse_header(input, hdr_size, flags, callback, context) \
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen message_parse_header(input, hdr_size, flags + \
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen CALLBACK_TYPECHECK(callback, void (*)( \
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen struct message_header_line *hdr, typeof(context))), \
27a44fcfd8d19bffe0f267f20a2b5d3fe7600fddTimo Sirainen (message_header_callback_t *)callback, context)
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen/* Write the header line to buffer exactly as it was read, including the
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen newline. */
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainenvoid message_header_line_write(buffer_t *output,
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen const struct message_header_line *hdr);
d45a4c7d1df04dd93d57aa8a29b76b55d4905341Timo Sirainen
d96f86fb881c5b106649e8994ead1052acf24030Timo Sirainen#endif