You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by so...@apache.org on 2005/09/09 07:58:12 UTC
svn commit: r279711 - in /httpd/mod_smtpd/trunk: mod_smtpd.h smtp.h
smtp_core.c smtp_filters.c smtp_filters.h smtp_protocol.c smtp_util.c
Author: soc-rian
Date: Thu Sep 8 22:58:08 2005
New Revision: 279711
URL: http://svn.apache.org/viewcvs?rev=279711&view=rev
Log:
simplified data filter, modified header parsing to be a filter, fixed bug that didn't catch single '.' when parsing a header
Modified:
httpd/mod_smtpd/trunk/mod_smtpd.h
httpd/mod_smtpd/trunk/smtp.h
httpd/mod_smtpd/trunk/smtp_core.c
httpd/mod_smtpd/trunk/smtp_filters.c
httpd/mod_smtpd/trunk/smtp_filters.h
httpd/mod_smtpd/trunk/smtp_protocol.c
httpd/mod_smtpd/trunk/smtp_util.c
Modified: httpd/mod_smtpd/trunk/mod_smtpd.h
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/mod_smtpd.h?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/mod_smtpd.h (original)
+++ httpd/mod_smtpd/trunk/mod_smtpd.h Thu Sep 8 22:58:08 2005
@@ -67,11 +67,6 @@
} smtpd_trans_state;
typedef enum {
- SMTPD_READ_COMMAND,
- SMTPD_READ_DATA
-} smtpd_read_type;
-
-typedef enum {
SMTPD_PROTOCOL_SMTP,
SMTPD_PROTOCOL_ESMTP
} smtpd_protocol_type;
@@ -137,8 +132,7 @@
SMTPD_DECLARE_NONSTD(apr_status_t) smtpd_getline(smtpd_conn_rec *scr,
char *data, apr_size_t dlen,
- apr_size_t *outlen,
- smtpd_read_type read_type);
+ apr_size_t *outlen);
SMTPD_DECLARE_NONSTD(apr_status_t) smtpd_respond_multiline(smtpd_conn_rec *scr,
int code,
@@ -185,7 +179,7 @@
APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, queue,
(smtpd_conn_rec *scr, smtpd_return_data *in));
APR_DECLARE_EXTERNAL_HOOK(smtpd, SMTPD, smtpd_retcode, headers_parsed,
- (smtpd_conn_rec *scr, smtpd_return_data *in));
+ (smtpd_conn_rec *scr));
#ifdef __cplusplus
}
Modified: httpd/mod_smtpd/trunk/smtp.h
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp.h?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp.h (original)
+++ httpd/mod_smtpd/trunk/smtp.h Thu Sep 8 22:58:08 2005
@@ -84,6 +84,11 @@
void *data;
} smtpd_handler_st;
+typedef struct {
+ int headers_parsed;
+ smtpd_conn_rec *scr;
+} smtpd_header_filter_ctx;
+
void smtpd_process_connection_internal(smtpd_conn_rec *str);
void smtpd_clear_trans_rec(smtpd_conn_rec *);
Modified: httpd/mod_smtpd/trunk/smtp_core.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_core.c?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_core.c (original)
+++ httpd/mod_smtpd/trunk/smtp_core.c Thu Sep 8 22:58:08 2005
@@ -39,6 +39,7 @@
module AP_MODULE_DECLARE_DATA smtpd_module;
ap_filter_rec_t *smtpd_data_input_filter_handle;
+ap_filter_rec_t *smtpd_header_input_filter_handle;
static apr_hash_t *smtpd_handlers;
@@ -120,9 +121,8 @@
/* Implement 'smtpd_run_headers_parsed'. */
APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL_MOD(smtpd, SMTPD, smtpd_retcode,
headers_parsed,
- (smtpd_conn_rec *scr,
- smtpd_return_data *in),
- (scr, in),
+ (smtpd_conn_rec *scr),
+ (scr),
SMTPD_OK, SMTPD_DECLINED);
apr_hash_t *smtpd_get_handlers()
@@ -289,7 +289,11 @@
APR_HOOK_MIDDLE);
smtpd_data_input_filter_handle =
- ap_register_input_filter("SMTP_IN", smtpd_data_filter,
+ ap_register_input_filter("SMTP_DATA_IN", smtpd_data_filter,
+ NULL, AP_FTYPE_PROTOCOL);
+
+ smtpd_header_input_filter_handle =
+ ap_register_input_filter("SMTP_HEADER_IN", smtpd_header_filter,
NULL, AP_FTYPE_PROTOCOL);
smtpd_handlers = apr_hash_make(p);
Modified: httpd/mod_smtpd/trunk/smtp_filters.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_filters.c?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_filters.c (original)
+++ httpd/mod_smtpd/trunk/smtp_filters.c Thu Sep 8 22:58:08 2005
@@ -17,7 +17,10 @@
#include "util_filter.h"
#include "apr_buckets.h"
+#include "apreq2/apreq_parser.h"
+
#include "mod_smtpd.h"
+#include "smtp.h"
#include "smtp_filters.h"
#define SMTPD_ASCII_DOT 0x2E
@@ -25,81 +28,181 @@
ap_input_mode_t mode, apr_read_type_e block,
apr_off_t readbytes)
{
- static int saw_eos = 0;
-
/* if we already got a dot, don't read more data
just fill the brigade with an eos bucket and return
+ note: our context is a dot notifier
*/
-
- if (saw_eos) {
+ if (f->ctx) {
/* then insert a EOS bucket at the head of the brigade */
apr_bucket *ne = apr_bucket_eos_create(f->c->bucket_alloc);
+
APR_BRIGADE_INSERT_HEAD(b, ne);
return APR_SUCCESS;
}
if (mode == AP_MODE_GETLINE) {
- apr_bucket *e;
- char stack_buf[3];
+ char stack_buf[4];
apr_status_t rc;
- apr_size_t bytes_handled = 0;
- int breakpoint;
- char ending_sequence[3] = {SMTPD_ASCII_DOT, APR_ASCII_CR, APR_ASCII_LF};
+ apr_size_t len;
+ char dotdot_sequence[4] = {SMTPD_ASCII_DOT, SMTPD_ASCII_DOT,
+ APR_ASCII_CR, APR_ASCII_LF};
+ char *ending_sequence = &(dotdot_sequence[1]);
+ apr_brigade_cleanup(b);
rc = ap_get_brigade(f->next, b, mode, block, readbytes);
if (rc != APR_SUCCESS)
return rc;
- /* only get the first 3 bytes of the brigade */
- for (e = APR_BRIGADE_FIRST(b);
- e != APR_BRIGADE_SENTINEL(b);
- e = APR_BUCKET_NEXT(e)) {
- const char *str;
- apr_size_t len;
-
- rc = apr_bucket_read(e, &str, &len, APR_BLOCK_READ);
- if (rc != APR_SUCCESS)
- return rc;
-
- breakpoint = 3 - bytes_handled;
- memcpy(stack_buf + bytes_handled, str, breakpoint < len ?
- breakpoint : len);
+ len = 4;
+ apr_brigade_flatten(b, stack_buf, &len);
- bytes_handled += len;
+ /* if the next line is just ".\r\n" we are done */
+ if ((len == 3) && (!strncmp(stack_buf, ending_sequence, 3))) {
+ apr_bucket *ne;
+
+ /* clear brigade (remove ".\r\n") */
+ apr_brigade_cleanup(b);
+
+ /* then insert a EOS bucket at the head of the brigade */
+ ne = apr_bucket_eos_create(f->c->bucket_alloc);
+ APR_BRIGADE_INSERT_HEAD(b, ne);
+ f->ctx = (void *) 1;
+ }
+ /* if the line is "..\r\n" translate to ".\r\n" */
+ else if ((len == 4) && (!strncmp(stack_buf, dotdot_sequence, 4))) {
+ apr_bucket *ne;
+ /* split the brigade after the first byte: "." */
+ apr_brigade_partition(b, 1, &ne);
+ /* get the bucket that has the "."
+ and just delete it */
+ ne = APR_BUCKET_PREV(ne);
+ apr_bucket_delete(ne);
+ }
+ } else if (mode == AP_MODE_READBYTES) {
+ /* XXX: need to check for single "./r/n" here too!!
+ maybe. might not have to since SMTP is line oriented
+ */
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
+ } else {
+ return ap_get_brigade(f->next, b, mode, block, readbytes);
+ }
+
+ return APR_SUCCESS;
+}
- /* if the first three bytes are ".\r\n"
- delete that stuff, and put an EOS bucket there instead
- */
- if ((bytes_handled >= 3) &&
- (!strncmp(stack_buf, ending_sequence, 3))) {
- apr_bucket *ne;
- apr_bucket_split(e, breakpoint);
- e = APR_BUCKET_NEXT(e);
-
- /* delete the buckets that entail ".\r\n" */
- while (!APR_BRIGADE_EMPTY(b)) {
- ne = APR_BRIGADE_FIRST(b);
-
- if (ne == e)
- break;
-
- apr_bucket_delete(ne);
- }
+static int ascii_printable(unsigned char character)
+{
+ return ((character <= 126) &&
+ (character >= 32));
+}
+
+static int is_ascii(unsigned char character)
+{
+ return (character <= 127);
+}
- /* then insert a EOS bucket at the head of the brigade */
- ne = apr_bucket_eos_create(f->c->bucket_alloc);
- APR_BRIGADE_INSERT_HEAD(b, ne);
- saw_eos = 1;
+static int is_rfc822_header(char *line)
+{
+ int i;
+ int header_len = 0;
+ enum {
+ HEADER_NAME,
+ HEADER_GAP,
+ HEADER_VALUE
+ } state = HEADER_NAME;
+
+ for (i = 0; line[i] != '\0'; ++i) {
+ switch(state) {
+ case HEADER_NAME:
+ if (!ascii_printable(line[i])) {
+ return 0;
+ }
+ else if (line[i] == ':') {
+ if (!header_len) {
+ return 0;
+ } else {
+ state = HEADER_GAP;
+ }
+ }
+ else {
+ header_len = 1;
+ }
+ break;
+ case HEADER_GAP:
+ if ((line[i] == APR_ASCII_BLANK) ||
+ (line[i] == APR_ASCII_TAB)) {
break;
}
+
+ if (line[i] == APR_ASCII_LF) {
+ return 0;
+ }
+
+ state = HEADER_VALUE;
+ /* fall through */
+ case HEADER_VALUE:
+ if (!is_ascii(line[i])) {
+ return 0;
+ }
+ else if (line[i] == APR_ASCII_LF) {
+ return 1;
+ }
+ break;
}
+ }
- } else if (mode == AP_MODE_READBYTES) {
- /* XXX: need to check for single "./r/n" here too!!
- maybe. might not have to since SMTP is line oriented
- */
+ return (state == HEADER_VALUE);
+}
+
+apr_status_t smtpd_header_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t readbytes)
+{
+ smtpd_header_filter_ctx *my_ctx = f->ctx;
+ smtpd_conn_rec *scr = my_ctx->scr;
+ smtpd_trans_rec *str = scr->transaction;
+ apr_status_t rv;
+
+ /* if we already parsed our headers just pass to next filter */
+ if (my_ctx->headers_parsed)
return ap_get_brigade(f->next, b, mode, block, readbytes);
+
+ if (mode == AP_MODE_GETLINE) {
+ char stack_buf[1000];
+ apr_size_t len = 1000;
+
+ ap_get_brigade(f->next, b, mode, block, readbytes);
+
+ apr_brigade_flatten(b, stack_buf, &len);
+
+ /* if the first line is a header, then parse the rest as header */
+ if (is_rfc822_header(stack_buf)) {
+ apreq_parser_t *rfc822_parser;
+ rfc822_parser = apreq_parser_make(str->p,
+ f->c->bucket_alloc,
+ "text/rfc822", apreq_parse_headers,
+ 1000, NULL, NULL, NULL);
+ do {
+ rv = apreq_parser_run(rfc822_parser, str->headers, b);
+
+ /* if we are done parsing, don't get another brigade
+ we'll pass the excess brigade to the caller */
+ if (rv == APR_SUCCESS)
+ break;
+
+ apr_brigade_cleanup(b);
+ ap_get_brigade(f->next, b,
+ AP_MODE_GETLINE, APR_BLOCK_READ, 0);
+ } while (rv == APR_INCOMPLETE);
+ }
+
+ /* by convention this is where most filters
+ should be inserted
+ */
+ smtpd_run_headers_parsed(scr);
+
+ my_ctx->headers_parsed = 1;
} else {
return ap_get_brigade(f->next, b, mode, block, readbytes);
}
Modified: httpd/mod_smtpd/trunk/smtp_filters.h
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_filters.h?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_filters.h (original)
+++ httpd/mod_smtpd/trunk/smtp_filters.h Thu Sep 8 22:58:08 2005
@@ -24,6 +24,9 @@
apr_status_t smtpd_data_filter(ap_filter_t *f, apr_bucket_brigade *b,
ap_input_mode_t mode, apr_read_type_e block,
apr_off_t readbytes);
+apr_status_t smtpd_header_filter(ap_filter_t *f, apr_bucket_brigade *b,
+ ap_input_mode_t mode, apr_read_type_e block,
+ apr_off_t readbytes);
#ifdef __cplusplus
Modified: httpd/mod_smtpd/trunk/smtp_protocol.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_protocol.c?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_protocol.c (original)
+++ httpd/mod_smtpd/trunk/smtp_protocol.c Thu Sep 8 22:58:08 2005
@@ -31,14 +31,13 @@
#include "apr_errno.h"
#include "scoreboard.h"
-#include "apreq2/apreq_parser.h"
-
#include "smtp.h"
#include "mod_smtpd.h"
#include "smtp_filters.h"
extern module AP_MODULE_DECLARE_DATA smtpd_module;
extern ap_filter_rec_t *smtpd_data_input_filter_handle;
+extern ap_filter_rec_t *smtpd_header_input_filter_handle;
inline static int smtpd_handle_unrecognized_command(smtpd_conn_rec *scr,
smtpd_return_data *in_data,
@@ -96,8 +95,7 @@
break;
}
- while (smtpd_getline(scr, buffer, BUFFER_STR_LEN, NULL,
- SMTPD_READ_COMMAND) == APR_SUCCESS) {
+ while (smtpd_getline(scr, buffer, BUFFER_STR_LEN, NULL) == APR_SUCCESS) {
apr_pool_clear(p);
command = ap_getword_white_nc(p, &buffer);
ap_str_tolower(command);
@@ -460,79 +458,21 @@
}
}
-static int ascii_printable(unsigned char character) {
- return ((character <= 126) &&
- (character >= 33));
-}
-
-static int is_ascii(unsigned char character) {
- return (character <= 127);
-}
-
-static int is_rfc822_header(char *line) {
- int i;
- int header_len = 0;
- enum {
- HEADER_NAME,
- HEADER_GAP,
- HEADER_VALUE
- } state = HEADER_NAME;
-
- for (i = 0; line[i] != '\0'; ++i) {
- switch(state) {
- case HEADER_NAME:
- if (!ascii_printable(line[i])) {
- return 0;
- }
- else if (line[i] == ':') {
- if (!header_len) {
- return 0;
- } else {
- state = HEADER_GAP;
- }
- }
- else {
- header_len = 1;
- }
- break;
- case HEADER_GAP:
- if ((line[i] == APR_ASCII_BLANK) ||
- (line[i] == APR_ASCII_TAB)) {
- break;
- }
-
- if (line[i] == APR_ASCII_LF) {
- return 0;
- }
-
- state = HEADER_VALUE;
- /* fall through */
- case HEADER_VALUE:
- if (!is_ascii(line[i])) {
- return 0;
- }
- else if (line[i] == APR_ASCII_LF) {
- return 1;
- }
- break;
- }
- }
-
- return (state == HEADER_VALUE);
-}
-
HANDLER_DECLARE(data)
{
smtpd_trans_rec *str = scr->transaction;
smtpd_svr_config_rec *pConfig =
ap_get_module_config(scr->s->module_config,
&smtpd_module);
+ smtpd_header_filter_ctx header_ctx = {0, scr};
int rv, retval = 0;
char *tempfile;
char our_buffer[BUFFER_STR_LEN];
+ const char *string;
apr_file_t *tfp;
apr_size_t len, total_data = 0;
apr_bucket_brigade *bb;
+ apr_bucket *e;
switch(smtpd_run_data(scr, in_data)) {
case SMTPD_DONE:
@@ -598,63 +538,42 @@
smtpd_respond_oneline(scr, 354, "End data with <CR><LF>.<CR><LF>");
/* add filter that translates ".\r\n" into EOS */
- smtpd_add_input_filter_handle(smtpd_data_input_filter_handle, NULL, scr);
+ smtpd_add_input_filter_handle(smtpd_data_input_filter_handle, 0, scr);
+ /* add filter that parses smtp headers */
+ smtpd_add_input_filter_handle(smtpd_header_input_filter_handle,
+ &header_ctx, scr);
- /* going to make header parsing a filter */
-#if 0
- /* get a line after the data command */
- smtpd_getline(scr, our_buffer, BUFFER_STR_LEN - 3, &len,
- SMTPD_READ_COMMAND);
- /* but put it back in the bucket brigade */
- {
- apr_bucket *temp_bucket;
-
- our_buffer[len] = '\r';
- our_buffer[len+1] = '\n';
- our_buffer[len+2] = '\0';
- temp_bucket = apr_bucket_transient_create(our_buffer, len+2,
- scr->c->bucket_alloc);
- apr_bucket_setaside(temp_bucket, str->p);
- APR_BRIGADE_INSERT_HEAD(bb, temp_bucket);
- }
-
- /* if the first line is a header, then parse the rest as header */
- if (is_rfc822_header(our_buffer)) {
- apreq_parser_t *rfc822_parser;
- rfc822_parser = apreq_parser_make(str->p,
- scr->c->bucket_alloc,
- "text/rfc822", apreq_parse_headers,
- 1000, NULL, NULL, NULL);
- do {
- ap_get_brigade(scr->c->input_filters, bb,
- AP_MODE_READBYTES, APR_BLOCK_READ, 1000);
-
- rv = apreq_parser_run(rfc822_parser, str->headers, bb);
- } while (rv == APR_INCOMPLETE);
- }
-
-#endif
- /* by convention this is where most filters
- should be inserted, but no action can be taken here
- right in the middle of the data command
- it is called even when there are no headers.
- */
- smtpd_run_headers_parsed(scr, in_data);
-
+ bb = apr_brigade_create(str->p, scr->c->bucket_alloc);
/* wait until there is no more data
or until we have too much data */
- while (((rv = smtpd_getline(scr, our_buffer, BUFFER_STR_LEN, &len,
- SMTPD_READ_DATA)) == APR_SUCCESS) &&
- (total_data < pConfig->max_data)) {
- if (len == 0)
- break;
-
- /* character data read plus newline */
- total_data += len + 1;
- apr_file_write(tfp, our_buffer, &len);
- len = 1;
- apr_file_write(tfp, "\n", &len);
+ while (total_data < pConfig->max_data) {
+ apr_size_t line_size;
+
+ ap_get_brigade(scr->transaction->input_filters, bb, AP_MODE_GETLINE,
+ APR_BLOCK_READ, 0);
+
+ for (e = APR_BRIGADE_FIRST(bb), line_size = 0;
+ e != APR_BRIGADE_SENTINEL(bb);
+ e = APR_BUCKET_NEXT(e)) {
+
+ if (APR_BUCKET_IS_EOS(e))
+ goto data_done;
+
+ rv = apr_bucket_read(e, &string, &len, APR_BLOCK_READ);
+ if (rv != APR_SUCCESS) {
+ len = 0;
+ break;
+ }
+
+ memcpy(our_buffer + line_size, string, len);
+ line_size += len;
+ total_data += len;
+ }
+
+ apr_file_write(tfp, our_buffer, &line_size);
}
+
+ data_done:
str->tfp = tfp;
Modified: httpd/mod_smtpd/trunk/smtp_util.c
URL: http://svn.apache.org/viewcvs/httpd/mod_smtpd/trunk/smtp_util.c?rev=279711&r1=279710&r2=279711&view=diff
==============================================================================
--- httpd/mod_smtpd/trunk/smtp_util.c (original)
+++ httpd/mod_smtpd/trunk/smtp_util.c Thu Sep 8 22:58:08 2005
@@ -46,8 +46,7 @@
SMTPD_DECLARE_NONSTD(apr_status_t) smtpd_getline(smtpd_conn_rec *scr,
char *data, apr_size_t dlen,
- apr_size_t *outlen,
- smtpd_read_type read_type)
+ apr_size_t *outlen)
{
apr_status_t rc;
apr_bucket *e;
@@ -55,9 +54,7 @@
char *pos, *last_char = data;
apr_size_t len, bytes_handled = 0;
int saw_eos = 0;
- ap_filter_t *input_filters = read_type == SMTPD_READ_DATA ?
- scr->transaction->input_filters :
- scr->c->input_filters;
+ ap_filter_t *input_filters = scr->c->input_filters;
while (!saw_eos) {
apr_brigade_cleanup(scr->bb_in);
@@ -158,7 +155,7 @@
}
#define INSERT_BEFORE(f, before_this) ((before_this) == NULL \
- || (before_this)->frec->ftype > (f)->frec->ftype \
+ || (before_this)->frec->ftype >= (f)->frec->ftype \
|| (before_this)->r != (f)->r)
SMTPD_DECLARE_NONSTD(ap_filter_t *)
smtpd_add_input_filter_handle(ap_filter_rec_t *frec, void *ctx,