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,