[dovecot-cvs] dovecot/src/lib-mail istream-header-filter.c, 1.5,
1.6 istream-header-filter.h, 1.3, 1.4
cras at dovecot.org
cras at dovecot.org
Sun Aug 22 05:58:42 EEST 2004
Update of /home/cvs/dovecot/src/lib-mail
In directory talvi:/tmp/cvs-serv27532/lib-mail
Modified Files:
istream-header-filter.c istream-header-filter.h
Log Message:
istream-header-filter now parses the headers incrementally while read()ing,
instead of doing it at initialization and storing into one large buffer.
Index: istream-header-filter.c
===================================================================
RCS file: /home/cvs/dovecot/src/lib-mail/istream-header-filter.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -d -r1.5 -r1.6
--- istream-header-filter.c 15 Aug 2004 03:40:31 -0000 1.5
+++ istream-header-filter.c 22 Aug 2004 02:58:40 -0000 1.6
@@ -1,8 +1,5 @@
/* Copyright (C) 2003-2004 Timo Sirainen */
-/* FIXME: the header wouldn't necessarily have to be read in memory. we could
- just parse it forward in _read(). */
-
#include "lib.h"
#include "buffer.h"
#include "message-parser.h"
@@ -13,11 +10,25 @@
struct header_filter_istream {
struct _istream istream;
+ pool_t pool;
struct istream *input;
+ struct message_header_parser_ctx *hdr_ctx;
- buffer_t *headers;
+ 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 filter:1;
};
static void _close(struct _iostream *stream __attr_unused__)
@@ -29,8 +40,10 @@
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);
- buffer_free(mstream->headers);
+ pool_unref(mstream->pool);
}
static void _set_max_buffer_size(struct _iostream *stream, size_t max_size)
@@ -41,6 +54,107 @@
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;
+
+ if (mstream->header_read &&
+ mstream->istream.istream.v_offset + mstream->istream.pos ==
+ 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 = message_parse_header_next(mstream->hdr_ctx)) != NULL) {
+ mstream->cur_line++;
+
+ if (hdr->eoh) {
+ buffer_append(mstream->hdr_buf, "\r\n", 2);
+ break;
+ }
+
+ 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->filter) {
+ /* 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);
+ buffer_append(mstream->hdr_buf, "\r\n", 2);
+
+ 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.buffer = buffer_get_data(mstream->hdr_buf, &pos);
+ ret = (ssize_t)(pos - mstream->istream.pos - mstream->istream.skip);
+ mstream->istream.pos = pos;
+
+ if (hdr == NULL) {
+ /* finished */
+ mstream->header_read = TRUE;
+
+ message_parse_header_deinit(mstream->hdr_ctx);
+ mstream->hdr_ctx = NULL;
+
+ 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 =
@@ -48,10 +162,11 @@
ssize_t ret;
size_t pos;
- if (stream->istream.v_offset < mstream->header_size.virtual_size) {
- /* we don't support mixing headers and body.
- it shouldn't be needed. */
- return -2;
+ 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->input->v_offset - mstream->header_size.physical_size !=
@@ -71,7 +186,7 @@
stream->buffer = i_stream_get_data(mstream->input, &pos);
}
- stream->pos -= mstream->istream.skip;
+ stream->pos -= stream->skip;
stream->skip = 0;
ret = pos <= stream->pos ? -1 :
@@ -86,94 +201,53 @@
(struct header_filter_istream *)stream;
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) {
- /* still in headers */
- stream->skip = v_offset;
- stream->pos = mstream->header_size.virtual_size;
- stream->buffer = buffer_get_data(mstream->headers, NULL);
+ /* 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 - use our real input stream */
- stream->skip = stream->pos = 0;
- stream->buffer = NULL;
-
+ /* body */
v_offset += mstream->header_size.physical_size -
mstream->header_size.virtual_size;
i_stream_seek(mstream->input, v_offset);
}
}
-static void
-read_and_hide_headers(struct istream *input, int filter,
- const char *const *headers, size_t headers_count,
- buffer_t *dest, struct message_size *hdr_size,
- header_filter_callback *callback, void *context)
-{
- struct message_header_parser_ctx *hdr_ctx;
- struct message_header_line *hdr;
- uoff_t virtual_size = 0;
- int matched;
-
- hdr_ctx = message_parse_header_init(input, hdr_size, FALSE);
- while ((hdr = message_parse_header_next(hdr_ctx)) != NULL) {
- if (hdr->eoh) {
- if (dest != NULL)
- buffer_append(dest, "\r\n", 2);
- else
- virtual_size += 2;
- break;
- }
-
- matched = bsearch(hdr->name, headers, headers_count,
- sizeof(*headers), bsearch_strcasecmp) != NULL;
- if (callback != NULL)
- callback(hdr, &matched, context);
-
- if (matched == filter) {
- /* ignore */
- } else if (dest != NULL) {
- if (!hdr->continued) {
- buffer_append(dest, hdr->name, hdr->name_len);
- buffer_append(dest, hdr->middle,
- hdr->middle_len);
- }
- buffer_append(dest, hdr->value, hdr->value_len);
- buffer_append(dest, "\r\n", 2);
- } else {
- if (!hdr->continued)
- virtual_size += hdr->name_len + 2;
- virtual_size += hdr->value_len + 2;
- }
- }
- message_parse_header_deinit(hdr_ctx);
-
- if (dest != NULL)
- virtual_size = buffer_get_used_size(dest);
-
- hdr_size->virtual_size = virtual_size;
- hdr_size->lines = 0;
-}
-
struct istream *
-i_stream_create_header_filter(pool_t pool, struct istream *input, int filter,
+i_stream_create_header_filter(struct istream *input, int filter,
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;
+ pool = pool_alloconly_create("header filter stream", 1024);
mstream = p_new(pool, struct header_filter_istream, 1);
+ mstream->pool = pool;
+
mstream->input = input;
i_stream_ref(mstream->input);
- mstream->headers = buffer_create_dynamic(default_pool,
- 8192, (size_t)-1);
- read_and_hide_headers(input, filter, headers, headers_count,
- mstream->headers, &mstream->header_size,
- callback, context);
- if (callback != NULL)
- callback(NULL, FALSE, context);
+ 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, 512, (size_t)-1);
- mstream->istream.buffer = buffer_get_data(mstream->headers, NULL);
- mstream->istream.pos = mstream->header_size.virtual_size;
+ mstream->callback = callback;
+ mstream->context = context;
+ mstream->filter = filter;
mstream->istream.iostream.close = _close;
mstream->istream.iostream.destroy = _destroy;
Index: istream-header-filter.h
===================================================================
RCS file: /home/cvs/dovecot/src/lib-mail/istream-header-filter.h,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -d -r1.3 -r1.4
--- istream-header-filter.h 15 Aug 2004 03:40:31 -0000 1.3
+++ istream-header-filter.h 22 Aug 2004 02:58:40 -0000 1.4
@@ -9,7 +9,7 @@
/* NOTE: headers list must be sorted. If filter is TRUE, given headers are
removed from output, otherwise only given headers are included in output. */
struct istream *
-i_stream_create_header_filter(pool_t pool, struct istream *input, int filter,
+i_stream_create_header_filter(struct istream *input, int filter,
const char *const *headers, size_t headers_count,
header_filter_callback *callback, void *context);
More information about the dovecot-cvs
mailing list