Mercurial > dovecot > original-hg > dovecot-1.2
view src/lib-mail/istream-header-filter.c @ 2708:f1e9f3ec8135 HEAD
Buffer API change: we no longer support limited sized buffers where
writes past limit wouldn't kill the process. They weren't used hardly
anywhere, they could have hidden bugs and the code for handling them was too
complex.
This also changed base64 and hex-binary APIs.
author | Timo Sirainen <tss@iki.fi> |
---|---|
date | Fri, 08 Oct 2004 20:51:47 +0300 |
parents | 2844c33a1be9 |
children | 19a6ff9fed58 |
line wrap: on
line source
/* Copyright (C) 2003-2004 Timo Sirainen */ #include "lib.h" #include "buffer.h" #include "message-parser.h" #include "istream-internal.h" #include "istream-header-filter.h" #include <stdlib.h> struct header_filter_istream { struct _istream istream; pool_t pool; struct istream *input; struct message_header_parser_ctx *hdr_ctx; const char **headers; size_t headers_count; header_filter_callback *callback; void *context; buffer_t *hdr_buf; struct message_size header_size; uoff_t skip_count; unsigned int cur_line, parsed_lines; unsigned int header_read:1; unsigned int exclude:1; unsigned int crlf:1; unsigned int hide_body:1; }; static void _close(struct _iostream *stream __attr_unused__) { } static void _destroy(struct _iostream *stream) { struct header_filter_istream *mstream = (struct header_filter_istream *)stream; if (mstream->hdr_ctx != NULL) message_parse_header_deinit(mstream->hdr_ctx); i_stream_unref(mstream->input); pool_unref(mstream->pool); } static void _set_max_buffer_size(struct _iostream *stream, size_t max_size) { struct header_filter_istream *mstream = (struct header_filter_istream *)stream; i_stream_set_max_buffer_size(mstream->input, max_size); } static ssize_t read_header(struct header_filter_istream *mstream) { struct message_header_line *hdr; size_t pos; ssize_t ret; int matched, hdr_ret; if (mstream->header_read && mstream->istream.istream.v_offset + (mstream->istream.pos - mstream->istream.skip) == mstream->header_size.virtual_size) { /* we don't support mixing headers and body. it shouldn't be needed. */ return -2; } if (mstream->hdr_ctx == NULL) { mstream->hdr_ctx = message_parse_header_init(mstream->input, NULL, FALSE); } buffer_copy(mstream->hdr_buf, 0, mstream->hdr_buf, mstream->istream.skip, (size_t)-1); mstream->istream.pos -= mstream->istream.skip; mstream->istream.skip = 0; buffer_set_used_size(mstream->hdr_buf, mstream->istream.pos); while ((hdr_ret = message_parse_header_next(mstream->hdr_ctx, &hdr)) > 0) { mstream->cur_line++; if (hdr->eoh) { matched = TRUE; if (!mstream->header_read && mstream->callback != NULL) { mstream->callback(hdr, &matched, mstream->context); } if (!matched) continue; if (mstream->crlf) buffer_append(mstream->hdr_buf, "\r\n", 2); else buffer_append_c(mstream->hdr_buf, '\n'); continue; } matched = bsearch(hdr->name, mstream->headers, mstream->headers_count, sizeof(*mstream->headers), bsearch_strcasecmp) != NULL; if (mstream->cur_line > mstream->parsed_lines && mstream->callback != NULL) { mstream->parsed_lines = mstream->cur_line; mstream->callback(hdr, &matched, mstream->context); } if (matched == mstream->exclude) { /* ignore */ } else { if (!hdr->continued) { buffer_append(mstream->hdr_buf, hdr->name, hdr->name_len); buffer_append(mstream->hdr_buf, hdr->middle, hdr->middle_len); } buffer_append(mstream->hdr_buf, hdr->value, hdr->value_len); if (!hdr->no_newline) { if (mstream->crlf) { buffer_append(mstream->hdr_buf, "\r\n", 2); } else buffer_append_c(mstream->hdr_buf, '\n'); } if (mstream->skip_count >= mstream->hdr_buf->used) { /* we need more */ mstream->skip_count -= mstream->hdr_buf->used; buffer_set_used_size(mstream->hdr_buf, 0); } else { if (mstream->skip_count > 0) { mstream->istream.skip = mstream->skip_count; mstream->skip_count = 0; } break; } } } mstream->istream.istream.eof = mstream->input->eof; mstream->istream.buffer = buffer_get_data(mstream->hdr_buf, &pos); ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip); mstream->istream.pos = pos; if (hdr_ret == 0) return ret; if (hdr == NULL) { /* finished */ message_parse_header_deinit(mstream->hdr_ctx); mstream->hdr_ctx = NULL; if (!mstream->header_read && mstream->callback != NULL) mstream->callback(NULL, &matched, mstream->context); mstream->header_read = TRUE; mstream->header_size.physical_size = mstream->input->v_offset; mstream->header_size.virtual_size = mstream->istream.istream.v_offset + pos; } if (ret == 0) { i_assert(hdr == NULL); i_assert(mstream->istream.istream.v_offset + mstream->istream.pos == mstream->header_size.virtual_size); return -2; } return ret; } static ssize_t _read(struct _istream *stream) { struct header_filter_istream *mstream = (struct header_filter_istream *)stream; ssize_t ret; size_t pos; if (!mstream->header_read || stream->istream.v_offset < mstream->header_size.virtual_size) { ret = read_header(mstream); if (ret != -2 || stream->pos != stream->skip) return ret; } if (mstream->hide_body) { stream->istream.eof = TRUE; return -1; } if (mstream->input->v_offset - mstream->header_size.physical_size != stream->istream.v_offset - mstream->header_size.virtual_size) { i_stream_seek(mstream->input, stream->istream.v_offset - mstream->header_size.virtual_size + mstream->header_size.physical_size); } stream->buffer = i_stream_get_data(mstream->input, &pos); if (pos <= stream->pos) { if ((ret = i_stream_read(mstream->input)) == -2) { if (stream->skip == 0) return -2; } stream->istream.eof = mstream->input->eof; stream->buffer = i_stream_get_data(mstream->input, &pos); } else { ret = 0; } stream->pos -= stream->skip; stream->skip = 0; ret = pos > stream->pos ? (ssize_t)(pos - stream->pos) : (ret == 0 ? 0 : -1); stream->pos = pos; return ret; } static void _seek(struct _istream *stream, uoff_t v_offset) { struct header_filter_istream *mstream = (struct header_filter_istream *)stream; size_t pos; while (!mstream->header_read) { if (_read(stream) == -1) break; (void)i_stream_get_data(&stream->istream, &pos); i_stream_skip(&stream->istream, pos); } stream->istream.v_offset = v_offset; stream->skip = stream->pos = 0; stream->buffer = NULL; if (mstream->hdr_ctx != NULL) { message_parse_header_deinit(mstream->hdr_ctx); mstream->hdr_ctx = NULL; } if (v_offset < mstream->header_size.virtual_size) { /* seek into headers. we'll have to re-parse them, use skip_count to set the wanted position */ i_stream_seek(mstream->input, 0); mstream->skip_count = v_offset; mstream->cur_line = 0; } else { /* body */ v_offset += mstream->header_size.physical_size - mstream->header_size.virtual_size; i_stream_seek(mstream->input, v_offset); } } struct istream * i_stream_create_header_filter(struct istream *input, enum header_filter_flags flags, const char *const *headers, size_t headers_count, header_filter_callback *callback, void *context) { struct header_filter_istream *mstream; pool_t pool; size_t i; i_assert((flags & (HEADER_FILTER_INCLUDE|HEADER_FILTER_EXCLUDE)) != 0); pool = pool_alloconly_create("header filter stream", 2048); mstream = p_new(pool, struct header_filter_istream, 1); mstream->pool = pool; mstream->input = input; i_stream_ref(mstream->input); mstream->headers = p_new(pool, const char *, headers_count); for (i = 0; i < headers_count; i++) mstream->headers[i] = p_strdup(pool, headers[i]); mstream->headers_count = headers_count; mstream->hdr_buf = buffer_create_dynamic(pool, 1024); mstream->callback = callback; mstream->context = context; mstream->exclude = (flags & HEADER_FILTER_EXCLUDE) != 0; mstream->crlf = (flags & HEADER_FILTER_NO_CR) == 0; mstream->hide_body = (flags & HEADER_FILTER_HIDE_BODY) != 0; mstream->istream.iostream.close = _close; mstream->istream.iostream.destroy = _destroy; mstream->istream.iostream.set_max_buffer_size = _set_max_buffer_size; mstream->istream.read = _read; mstream->istream.seek = _seek; return _i_stream_create(&mstream->istream, pool, -1, 0); }