istream-header-filter.c revision e8eb96edcfe8cff7839f1258ab6e871e41a4785e
5f5870385cff47efd2f58e7892f251cf13761528Timo Sirainen/* Copyright (C) 2003-2004 Timo Sirainen */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "lib.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "buffer.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "message-parser.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen#include "istream-internal.h"
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen#include "istream-header-filter.h"
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen#include <stdlib.h>
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainenstruct header_filter_istream {
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen struct _istream istream;
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen pool_t pool;
c977374bd4651cafc1626ebe308aa66dfd8b30e0Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct istream *input;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct message_header_parser_ctx *hdr_ctx;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t start_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char **headers;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int headers_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen header_filter_callback *callback;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen void *context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen buffer_t *hdr_buf;
9955f6cba7652469b1d600a3674e8d27dd4e61bdTimo Sirainen struct message_size header_size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen uoff_t skip_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen unsigned int cur_line, parsed_lines;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int header_read:1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int header_parsed:1;
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen unsigned int exclude:1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int crlf:1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int hide_body:1;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen};
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainenheader_filter_callback *null_header_filter_callback = NULL;
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void _close(struct _iostream *stream __attr_unused__)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainenstatic void _destroy(struct _iostream *stream)
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen{
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen struct header_filter_istream *mstream =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (struct header_filter_istream *)stream;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->hdr_ctx != NULL)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
de62ce819d59a529530da4b57be1b8d6dad13d6bTimo Sirainen i_stream_unref(&mstream->input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen pool_unref(mstream->pool);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
461ffead9720d1e516b959d5e41f049c73d38c7cTimo Sirainenstatic void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct header_filter_istream *mstream =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (struct header_filter_istream *)stream;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_set_max_buffer_size(mstream->input, max_size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic ssize_t read_header(struct header_filter_istream *mstream)
c18ff860dc22960fd37c272d929f889c7939a2c8Timo Sirainen{
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen struct message_header_line *hdr;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen size_t pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ssize_t ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool matched;
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen int hdr_ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->header_read &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.istream.v_offset +
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (mstream->istream.pos - mstream->istream.skip) ==
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->header_size.virtual_size) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we don't support mixing headers and body.
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen it shouldn't be needed. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return -2;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->hdr_ctx == NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->hdr_ctx =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen message_parse_header_init(mstream->input, NULL, FALSE);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_copy(mstream->hdr_buf, 0,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->hdr_buf, mstream->istream.skip, (size_t)-1);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.pos -= mstream->istream.skip;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.skip = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen &hdr)) > 0) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen mstream->cur_line++;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if (hdr->eoh) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen matched = TRUE;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!mstream->header_parsed &&
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->callback != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->callback(hdr, &matched,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->context);
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen if (!matched)
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen continue;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->crlf)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(mstream->hdr_buf, "\r\n", 2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen else
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
a10ed8c47534b4c6b6bf2711ccfe577e720a47b4Timo Sirainen continue;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen }
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen matched = mstream->headers_count == 0 ? FALSE :
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen bsearch(hdr->name, mstream->headers,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->headers_count,
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen sizeof(*mstream->headers),
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen bsearch_strcasecmp) != NULL;
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen if (mstream->cur_line > mstream->parsed_lines &&
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen mstream->callback != NULL) {
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen mstream->parsed_lines = mstream->cur_line;
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen mstream->callback(hdr, &matched, mstream->context);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen
6ae329de09afb7214c906d762320847e05469d53Timo Sirainen if (matched == mstream->exclude) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* ignore */
637455ebee0453f860c9bce0626c485e35fb83deTimo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!hdr->continued) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(mstream->hdr_buf,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hdr->name, hdr->name_len);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(mstream->hdr_buf,
d22301419109ed4a38351715e6760011421dadecTimo Sirainen hdr->middle, hdr->middle_len);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(mstream->hdr_buf,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen hdr->value, hdr->value_len);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (!hdr->no_newline) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->crlf) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_append(mstream->hdr_buf,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen "\r\n", 2);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen buffer_append_c(mstream->hdr_buf, '\n');
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen }
e790c9b1fc56bca7ebd59dc289cb5035e3afcee5Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->skip_count >= mstream->hdr_buf->used) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* we need more */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->skip_count -= mstream->hdr_buf->used;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen buffer_set_used_size(mstream->hdr_buf, 0);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen } else {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (mstream->skip_count > 0) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mstream->istream.skip =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->skip_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->skip_count = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
65b94e73c305dcb209cf958f938b93ec061c67a9Timo Sirainen break;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen /* don't copy eof here because we're only returning headers here.
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen the body will be returned in separate read() call. */
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
73a87c2ff65c6116cde6fb158dfddb8ef7346901Timo Sirainen mstream->istream.pos = pos;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (hdr_ret == 0)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return ret;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (hdr == NULL) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* finished */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->hdr_ctx = NULL;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (!mstream->header_parsed && mstream->callback != NULL)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->callback(NULL, &matched, mstream->context);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_parsed = TRUE;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_read = TRUE;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_size.physical_size = mstream->input->v_offset;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_size.virtual_size =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.istream.v_offset + pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (ret == 0) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_assert(hdr == NULL);
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen i_assert(mstream->istream.istream.v_offset +
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.pos ==
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->header_size.virtual_size);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -2;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return ret;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainenstatic ssize_t _read(struct _istream *stream)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
d0b2bd9e2246eb68ed952c7f2e13d1969d657c8fTimo Sirainen struct header_filter_istream *mstream =
d0b2bd9e2246eb68ed952c7f2e13d1969d657c8fTimo Sirainen (struct header_filter_istream *)stream;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ssize_t ret;
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen size_t pos;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (!mstream->header_read ||
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->istream.v_offset < mstream->header_size.virtual_size) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen ret = read_header(mstream);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (ret != -2 || stream->pos != stream->skip)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mstream->hide_body) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen stream->istream.eof = TRUE;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen return -1;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen i_stream_seek(mstream->input, mstream->start_offset +
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen stream->istream.v_offset -
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_size.virtual_size +
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_size.physical_size);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->pos -= stream->skip;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->skip = 0;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->buffer = i_stream_get_data(mstream->input, &pos);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (pos <= stream->pos) {
d22301419109ed4a38351715e6760011421dadecTimo Sirainen if ((ret = i_stream_read(mstream->input)) == -2) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (stream->skip == 0)
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen return -2;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->istream.stream_errno = mstream->input->stream_errno;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->istream.eof = mstream->input->eof;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen stream->buffer = i_stream_get_data(mstream->input, &pos);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen } else {
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen ret = 0;
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen }
dd4f30895ebbddd77e000472fbadcb3128ae2883Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) :
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen (ret == 0 ? 0 : -1);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen stream->pos = pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return ret;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void parse_header(struct header_filter_istream *mstream)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen size_t pos;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen while (!mstream->header_read) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (_read(&mstream->istream) == -1)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen break;
3f91e60401495a4046c73992fabaa5e77200a451Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (void)i_stream_get_data(&mstream->istream.istream, &pos);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_skip(&mstream->istream.istream, pos);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen }
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic void _seek(struct _istream *stream, uoff_t v_offset,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen bool mark __attr_unused__)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen struct header_filter_istream *mstream =
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen (struct header_filter_istream *)stream;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen parse_header(mstream);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen stream->istream.v_offset = v_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->skip = stream->pos = 0;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen stream->buffer = NULL;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (mstream->hdr_ctx != NULL) {
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen message_parse_header_deinit(&mstream->hdr_ctx);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->hdr_ctx = NULL;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen }
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen if (v_offset < mstream->header_size.virtual_size) {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* seek into headers. we'll have to re-parse them, use
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen skip_count to set the wanted position */
ddb018bc886680f462463b2c87f983fdedbf6cf0Timo Sirainen i_stream_seek(mstream->input, mstream->start_offset);
ca98892a6b8a30ffc1fe26fcf02c7d59e3204e7eTimo Sirainen mstream->skip_count = v_offset;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->cur_line = 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->header_read = FALSE;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen } else {
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen /* body */
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen v_offset += mstream->header_size.physical_size -
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->header_size.virtual_size;
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen i_stream_seek(mstream->input, mstream->start_offset + v_offset);
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen }
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen}
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainenstatic void __attr_noreturn__
37ee89f3cba22cd975912a882f0d3097fa5031e1Timo Sirainen_sync(struct _istream *stream __attr_unused__)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_panic("istream-header-filter sync() not implemented");
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstatic const struct stat *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen_stat(struct _istream *stream, bool exact)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct header_filter_istream *mstream =
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (struct header_filter_istream *)stream;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const struct stat *st;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen st = i_stream_stat(mstream->input, exact);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen if (st == NULL || st->st_size == -1 || !exact)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return st;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen parse_header(mstream);
1f1ee8db68d9ae1604350801cd8dc33ebe29fe8aTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->statbuf = *st;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen stream->statbuf.st_size -=
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (off_t)mstream->header_size.physical_size -
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen (off_t)mstream->header_size.virtual_size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen return &stream->statbuf;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen}
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen#undef i_stream_create_header_filter
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainenstruct istream *
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Siraineni_stream_create_header_filter(struct istream *input,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen enum header_filter_flags flags,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen const char *const *headers,
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen unsigned int headers_count,
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen header_filter_callback *callback, void *context)
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen{
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen struct header_filter_istream *mstream;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen pool_t pool;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen unsigned int i;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0);
4fded1eec06aba9ce37887ac30619768760cd0d0Timo Sirainen
4fded1eec06aba9ce37887ac30619768760cd0d0Timo Sirainen pool = pool_alloconly_create("header filter stream", 4096);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream = p_new(pool, struct header_filter_istream, 1);
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen mstream->pool = pool;
08a8b3de61139ba02371afc8240ac85be0e8b17cTimo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->input = input;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen i_stream_ref(mstream->input);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->headers = headers_count == 0 ? NULL :
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen p_new(pool, const char *, headers_count);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen for (i = 0; i < headers_count; i++)
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->headers[i] = p_strdup(pool, headers[i]);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->headers_count = headers_count;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->hdr_buf = buffer_create_dynamic(pool, 1024);
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->callback = callback;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->context = context;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->crlf = (flags & HEADER_FILTER_NO_CR) == 0;
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen mstream->hide_body = (flags & HEADER_FILTER_HIDE_BODY) != 0;
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen mstream->start_offset = input->v_offset;
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen
f71c2d4e6b802bf8e622bcd5df29286262d05d5aTimo Sirainen mstream->istream.iostream.close = _close;
d22301419109ed4a38351715e6760011421dadecTimo Sirainen mstream->istream.iostream.destroy = _destroy;
5b62dea2f88165f3f4d87bba9011343f3ff415ffTimo Sirainen mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.read = _read;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.seek = _seek;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.sync = _sync;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.stat = _stat;
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen
1ac7c8e9040e0d0b7e9f849e45b94bfe919595a9Timo Sirainen mstream->istream.istream.blocking = input->blocking;
mstream->istream.istream.seekable = input->seekable;
return _i_stream_create(&mstream->istream, pool, -1, 0);
}