]> git.kaiwu.me - nginx.git/commitdiff
Mail: smtp pipelining support.
authorMaxim Dounin <mdounin@mdounin.ru>
Mon, 30 Sep 2013 18:09:57 +0000 (22:09 +0400)
committerMaxim Dounin <mdounin@mdounin.ru>
Mon, 30 Sep 2013 18:09:57 +0000 (22:09 +0400)
Basically, this does the following two changes (and corresponding
modifications of related code):

1. Does not reset session buffer unless it's reached it's end, and always
wait for LF to terminate command (even if we detected invalid command).

2. Record command name to make it available for handlers (since now we
can't assume that command starts from s->buffer->start).

src/mail/ngx_mail.h
src/mail/ngx_mail_handler.c
src/mail/ngx_mail_parse.c
src/mail/ngx_mail_proxy_module.c
src/mail/ngx_mail_smtp_handler.c

index ccdfb8c6f1099a777b27878d8f254ed5b58ba224..dc39f1e1375af6ee5a652ab360abcfb19532f6e3 100644 (file)
@@ -234,6 +234,8 @@ typedef struct {
     ngx_str_t               smtp_from;
     ngx_str_t               smtp_to;
 
+    ngx_str_t               cmd;
+
     ngx_uint_t              command;
     ngx_array_t             args;
 
index ae955f9c6aea04cf64a72d4ea306af2ceb2b81d4..7cfff1a0709b6221fc7167754a69c4ef6ff89ed5 100644 (file)
@@ -620,7 +620,9 @@ ngx_mail_read_command(ngx_mail_session_t *s, ngx_connection_t *c)
             return NGX_ERROR;
         }
 
-        return NGX_AGAIN;
+        if (s->buffer->pos == s->buffer->last) {
+            return NGX_AGAIN;
+        }
     }
 
     cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
@@ -661,8 +663,12 @@ void
 ngx_mail_auth(ngx_mail_session_t *s, ngx_connection_t *c)
 {
     s->args.nelts = 0;
-    s->buffer->pos = s->buffer->start;
-    s->buffer->last = s->buffer->start;
+
+    if (s->buffer->pos == s->buffer->last) {
+        s->buffer->pos = s->buffer->start;
+        s->buffer->last = s->buffer->start;
+    }
+
     s->state = 0;
 
     if (c->read->timer_set) {
index 7de6c19a13b822d6f0432f4fd5e27aadcdad07e9..b158f5a0fbaa77175983bfaf21378cbf90d24cf7 100644 (file)
@@ -626,6 +626,8 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
     ngx_str_t  *arg;
     enum {
         sw_start = 0,
+        sw_command,
+        sw_invalid,
         sw_spaces_before_argument,
         sw_argument,
         sw_almost_done
@@ -640,8 +642,14 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
 
         /* SMTP command */
         case sw_start:
+            s->cmd_start = p;
+            state = sw_command;
+
+            /* fall through */
+
+        case sw_command:
             if (ch == ' ' || ch == CR || ch == LF) {
-                c = s->buffer->start;
+                c = s->cmd_start;
 
                 if (p - c == 4) {
 
@@ -719,6 +727,9 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
                     goto invalid;
                 }
 
+                s->cmd.data = s->cmd_start;
+                s->cmd.len = p - s->cmd_start;
+
                 switch (ch) {
                 case ' ':
                     state = sw_spaces_before_argument;
@@ -738,6 +749,9 @@ ngx_mail_smtp_parse_command(ngx_mail_session_t *s)
 
             break;
 
+        case sw_invalid:
+            goto invalid;
+
         case sw_spaces_before_argument:
             switch (ch) {
             case ' ':
@@ -824,9 +838,21 @@ done:
 
 invalid:
 
-    s->state = sw_start;
+    s->state = sw_invalid;
     s->arg_start = NULL;
 
+    /* skip invalid command till LF */
+
+    for (p = s->buffer->pos; p < s->buffer->last; p++) {
+        if (*p == LF) {
+            s->state = sw_start;
+            p++;
+            break;
+        }
+    }
+
+    s->buffer->pos = p;
+
     return NGX_MAIL_PARSE_INVALID_COMMAND;
 }
 
index 4ea608ceafa98d825529016cbec7508197283b9b..ed9e0e2d12325675f5f0a82803fb2856fd39262b 100644 (file)
@@ -657,7 +657,12 @@ ngx_mail_proxy_smtp_handler(ngx_event_t *rev)
         c->log->action = NULL;
         ngx_log_error(NGX_LOG_INFO, c->log, 0, "client logged in");
 
-        ngx_mail_proxy_handler(s->connection->write);
+        if (s->buffer->pos == s->buffer->last) {
+            ngx_mail_proxy_handler(s->connection->write);
+
+        } else {
+            ngx_mail_proxy_handler(c->write);
+        }
 
         return;
 
index c118f547dcffd504a5f5eda04ca021ba2d46ea2d..0238b62825837578a0a4babd2d0af5d05c24e2ab 100644 (file)
@@ -486,6 +486,10 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev)
         }
     }
 
+    if (s->buffer->pos < s->buffer->last) {
+        s->blocked = 1;
+    }
+
     switch (rc) {
 
     case NGX_DONE:
@@ -505,11 +509,14 @@ ngx_mail_smtp_auth_state(ngx_event_t *rev)
 
     case NGX_OK:
         s->args.nelts = 0;
-        s->buffer->pos = s->buffer->start;
-        s->buffer->last = s->buffer->start;
+
+        if (s->buffer->pos == s->buffer->last) {
+            s->buffer->pos = s->buffer->start;
+            s->buffer->last = s->buffer->start;
+        }
 
         if (s->state) {
-            s->arg_start = s->buffer->start;
+            s->arg_start = s->buffer->pos;
         }
 
         ngx_mail_send(c->write);
@@ -652,9 +659,7 @@ ngx_mail_smtp_auth(ngx_mail_session_t *s, ngx_connection_t *c)
 static ngx_int_t
 ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    u_char                     ch;
-    ngx_str_t                  l;
-    ngx_uint_t                 i;
+    ngx_str_t                 *arg, cmd;
     ngx_mail_smtp_srv_conf_t  *sscf;
 
     sscf = ngx_mail_get_module_srv_conf(s, ngx_mail_smtp_module);
@@ -672,37 +677,20 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
         return NGX_OK;
     }
 
-    l.len = s->buffer->last - s->buffer->start;
-    l.data = s->buffer->start;
-
-    for (i = 0; i < l.len; i++) {
-        ch = l.data[i];
-
-        if (ch != CR && ch != LF) {
-            continue;
-        }
-
-        l.data[i] = ' ';
-    }
-
-    while (i) {
-        if (l.data[i - 1] != ' ') {
-            break;
-        }
-
-        i--;
-    }
+    arg = s->args.elts;
+    arg += s->args.nelts - 1;
 
-    l.len = i;
+    cmd.len = arg->data + arg->len - s->cmd.data;
+    cmd.data = s->cmd.data;
 
-    s->smtp_from.len = l.len;
+    s->smtp_from.len = cmd.len;
 
-    s->smtp_from.data = ngx_pnalloc(c->pool, l.len);
+    s->smtp_from.data = ngx_pnalloc(c->pool, cmd.len);
     if (s->smtp_from.data == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_memcpy(s->smtp_from.data, l.data, l.len);
+    ngx_memcpy(s->smtp_from.data, cmd.data, cmd.len);
 
     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    "smtp mail from:\"%V\"", &s->smtp_from);
@@ -716,46 +704,27 @@ ngx_mail_smtp_mail(ngx_mail_session_t *s, ngx_connection_t *c)
 static ngx_int_t
 ngx_mail_smtp_rcpt(ngx_mail_session_t *s, ngx_connection_t *c)
 {
-    u_char      ch;
-    ngx_str_t   l;
-    ngx_uint_t  i;
+    ngx_str_t  *arg, cmd;
 
     if (s->smtp_from.len == 0) {
         ngx_str_set(&s->out, smtp_bad_sequence);
         return NGX_OK;
     }
 
-    l.len = s->buffer->last - s->buffer->start;
-    l.data = s->buffer->start;
-
-    for (i = 0; i < l.len; i++) {
-        ch = l.data[i];
-
-        if (ch != CR && ch != LF) {
-            continue;
-        }
-
-        l.data[i] = ' ';
-    }
-
-    while (i) {
-        if (l.data[i - 1] != ' ') {
-            break;
-        }
-
-        i--;
-    }
+    arg = s->args.elts;
+    arg += s->args.nelts - 1;
 
-    l.len = i;
+    cmd.len = arg->data + arg->len - s->cmd.data;
+    cmd.data = s->cmd.data;
 
-    s->smtp_to.len = l.len;
+    s->smtp_to.len = cmd.len;
 
-    s->smtp_to.data = ngx_pnalloc(c->pool, l.len);
+    s->smtp_to.data = ngx_pnalloc(c->pool, cmd.len);
     if (s->smtp_to.data == NULL) {
         return NGX_ERROR;
     }
 
-    ngx_memcpy(s->smtp_to.data, l.data, l.len);
+    ngx_memcpy(s->smtp_to.data, cmd.data, cmd.len);
 
     ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
                    "smtp rcpt to:\"%V\"", &s->smtp_to);