[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