diff src/imap/ngx_imap_parse.c @ 527:7fa11e5c6e96 release-0.1.38

nginx-0.1.38-RELEASE import *) Feature: the "limit_rate" directive is supported in in proxy and FastCGI mode. *) Feature: the "X-Accel-Limit-Rate" response header line is supported in proxy and FastCGI mode. *) Feature: the "break" directive. *) Feature: the "log_not_found" directive. *) Bugfix: the response status code was not changed when request was redirected by the ""X-Accel-Redirect" header line. *) Bugfix: the variables set by the "set" directive could not be used in SSI. *) Bugfix: the segmentation fault may occurred if the SSI page has more than one remote subrequest. *) Bugfix: nginx treated the backend response as invalid if the status line in the header was transferred in two packets; the bug had appeared in 0.1.29. *) Feature: the "ssi_types" directive. *) Feature: the "autoindex_exact_size" directive. *) Bugfix: the ngx_http_autoindex_module did not support the long file names in UTF-8. *) Feature: the IMAP/POP3 proxy.
author Igor Sysoev <igor@sysoev.ru>
date Fri, 08 Jul 2005 14:34:20 +0000
parents d4ea69372b94
children e5d7d0334fdb
line wrap: on
line diff
--- a/src/imap/ngx_imap_parse.c
+++ b/src/imap/ngx_imap_parse.c
@@ -10,64 +10,134 @@
 #include <ngx_imap.h>
 
 
-ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
+ngx_int_t ngx_imap_parse_command(ngx_imap_session_t *s)
 {
     u_char      ch, *p, *c;
     ngx_str_t  *arg;
     enum {
         sw_start = 0,
+        sw_spaces_before_command,
+        sw_command,
         sw_spaces_before_argument,
         sw_argument,
-        sw_almost_done,
-        sw_done
+        sw_literal,
+        sw_start_literal_argument,
+        sw_literal_argument,
+        sw_end_literal_argument,
+        sw_almost_done
     } state;
 
     state = s->state;
-    p = s->buffer->pos;
 
-    while (p < s->buffer->last && state < sw_done) {
-        ch = *p++;
+    for (p = s->buffer->pos; p < s->buffer->last; p++) {
+        ch = *p;
 
         switch (state) {
 
-        /* POP3 command */
-
+        /* IMAP tag */
         case sw_start:
-            if (ch == ' ' || ch == CR || ch == LF) {
-                c = s->buffer->start;
-
-                if (p - 1 - c == 4) {
-
-                    if (c[0] == 'U' && c[1] == 'S'
-                        && c[2] == 'E' && c[3] == 'R')
-                    {
-                        s->command = NGX_POP3_USER;
+            switch (ch) {
+            case ' ':
+                s->tag.len = p - s->buffer->start + 1;
+                s->tag.data = s->buffer->start;
+                state = sw_spaces_before_command;
+                break;
+            case CR:
+                s->state = sw_start;
+                return NGX_IMAP_PARSE_INVALID_COMMAND;
+            case LF:
+                s->state = sw_start;
+                return NGX_IMAP_PARSE_INVALID_COMMAND;
+            }
+            break;
 
-                    } else if (c[0] == 'P' && c[1] == 'A'
-                               && c[2] == 'S' && c[3] == 'S')
-                    {
-                        s->command = NGX_POP3_PASS;
+        case sw_spaces_before_command:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                s->state = sw_start;
+                return NGX_IMAP_PARSE_INVALID_COMMAND;
+            case LF:
+                s->state = sw_start;
+                return NGX_IMAP_PARSE_INVALID_COMMAND;
+            default:
+                s->cmd_start = p;
+                state = sw_command;
+                break;
+            }
+            break;
 
-                    } else if (c[0] == 'Q' && c[1] == 'U'
-                               && c[2] == 'I' && c[3] == 'T')
+        case sw_command:
+            if (ch == ' ' || ch == CR || ch == LF) {
+
+                c = s->cmd_start;
+
+                switch (p - c) {
+
+                case 4:
+                    if ((c[0] == 'N' || c[0] == 'n')
+                        && (c[1] == 'O'|| c[1] == 'o')
+                        && (c[2] == 'O'|| c[2] == 'o')
+                        && (c[3] == 'P'|| c[3] == 'p'))
                     {
-                        s->command = NGX_POP3_QUIT;
-
-#if 0
-                    } else if (c[0] == 'N' && c[1] == 'O'
-                               && c[2] == 'O' && c[3] == 'P')
-                    {
-                        s->command = NGX_POP3_NOOP;
-#endif
+                        s->command = NGX_IMAP_NOOP;
 
                     } else {
-                        s->state = sw_start;
-                        return NGX_IMAP_PARSE_INVALID_COMMAND;
+                        goto invalid;
                     }
+                    break;
+
+                case 5:
+                    if ((c[0] == 'L'|| c[0] == 'l')
+                        && (c[1] == 'O'|| c[1] == 'o')
+                        && (c[2] == 'G'|| c[2] == 'g')
+                        && (c[3] == 'I'|| c[3] == 'i')
+                        && (c[4] == 'N'|| c[4] == 'n'))
+                    {
+                        s->command = NGX_IMAP_LOGIN;
+
+                    } else {
+                        goto invalid;
+                    }
+                    break;
 
-                } else {
-                    s->state = sw_start;
-                    return NGX_IMAP_PARSE_INVALID_COMMAND;
+                case 6:
+                    if ((c[0] == 'L'|| c[0] == 'l')
+                        && (c[1] == 'O'|| c[1] == 'o')
+                        && (c[2] == 'G'|| c[2] == 'g')
+                        && (c[3] == 'O'|| c[3] == 'o')
+                        && (c[4] == 'U'|| c[4] == 'u')
+                        && (c[5] == 'T'|| c[5] == 't'))
+                    {
+                        s->command = NGX_IMAP_LOGOUT;
+
+                    } else {
+                        goto invalid;
+                    }
+                    break;
+
+                case 10:
+                    if ((c[0] == 'C'|| c[0] == 'c')
+                        && (c[1] == 'A'|| c[1] == 'a')
+                        && (c[2] == 'P'|| c[2] == 'p')
+                        && (c[3] == 'A'|| c[3] == 'a')
+                        && (c[4] == 'B'|| c[4] == 'b')
+                        && (c[5] == 'I'|| c[5] == 'i')
+                        && (c[6] == 'L'|| c[6] == 'l')
+                        && (c[7] == 'I'|| c[7] == 'i')
+                        && (c[8] == 'T'|| c[8] == 't')
+                        && (c[9] == 'Y'|| c[9] == 'y'))
+                    {
+                        s->command = NGX_IMAP_CAPABILITY;
+
+                    } else {
+                        goto invalid;
+                    }
+                    break;
+
+                default:
+                    goto invalid;
                 }
 
                 switch (ch) {
@@ -78,45 +148,287 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
                     state = sw_almost_done;
                     break;
                 case LF:
-                    state = sw_done;
-                    break;
+                    goto done;
                 }
                 break;
             }
 
-            if (ch < 'A' || ch > 'Z') {
-                s->state = sw_start;
-                return NGX_IMAP_PARSE_INVALID_COMMAND;
+            if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
+                goto invalid;
             }
 
             break;
 
-        /* the spaces before the argument */
         case sw_spaces_before_argument:
             switch (ch) {
             case ' ':
                 break;
             case CR:
                 state = sw_almost_done;
-                s->arg_end = p - 1;
+                s->arg_end = p;
                 break;
             case LF:
-                state = sw_done;
-                s->arg_end = p - 1;
-                break;
+                s->arg_end = p;
+                goto done;
+            case '"':
+                if (s->args.nelts <= 2) {
+                    s->quoted = 1;
+                    s->arg_start = p + 1;
+                    state = sw_argument;
+                    break;
+                }
+                goto invalid;
+            case '{':
+                if (s->args.nelts <= 2) {
+                    state = sw_literal;
+                    break;
+                }
+                goto invalid;
             default:
-                if (s->args.nelts > 2) {
-                    s->state = sw_start;
-                    return NGX_IMAP_PARSE_INVALID_COMMAND;
+                if (s->args.nelts <= 2) {
+                    s->arg_start = p;
+                    state = sw_argument;
+                    break;
+                }
+                goto invalid;
+            }
+            break;
+
+        case sw_argument:
+            switch (ch) {
+            case '"':
+                if (!s->quoted) {
+                    break;
                 }
+                s->quoted = 0;
+                /* fall through */
+            case ' ':
+            case CR:
+            case LF:
+                arg = ngx_array_push(&s->args);
+                if (arg == NULL) {
+                    return NGX_ERROR;
+                }
+                arg->len = p - s->arg_start;
+                arg->data = s->arg_start;
+                s->arg_start = NULL;
 
-                state = sw_argument;
-                s->arg_start = p - 1;
+                switch (ch) {
+                case '"':
+                case ' ':
+                    state = sw_spaces_before_argument;
+                    break;
+                case CR:
+                    state = sw_almost_done;
+                    break;
+                case LF:
+                    goto done;
+                }
                 break;
             }
             break;
 
-        /* the argument */
+        case sw_literal:
+            if (ch >= '0' && ch <= '9') {
+                s->literal_len = s->literal_len * 10 + (ch - '0');
+                break;
+            }
+            if (ch == '}') {
+                state = sw_start_literal_argument;
+                break;
+            }
+            goto invalid;
+
+        case sw_start_literal_argument:
+            switch (ch) {
+            case CR:
+                break;
+            case LF:
+                s->buffer->pos = p + 1;
+                s->arg_start = p + 1;
+                s->state = sw_literal_argument;
+                return NGX_IMAP_NEXT;
+            }
+            goto invalid;
+
+        case sw_literal_argument:
+            if (--s->literal_len) {
+                break;
+            }
+
+            arg = ngx_array_push(&s->args);
+            if (arg == NULL) {
+                return NGX_ERROR;
+            }
+            arg->len = p + 1 - s->arg_start;
+            arg->data = s->arg_start;
+            s->arg_start = NULL;
+            state = sw_end_literal_argument;
+
+            break;
+
+        case sw_end_literal_argument:
+            switch (ch) {
+            case '{':
+                if (s->args.nelts <= 2) {
+                    state = sw_literal;
+                    break;
+                }
+                goto invalid;
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                goto done;
+            default:
+                goto invalid;
+            }
+            break;
+
+        case sw_almost_done:
+            switch (ch) {
+            case LF:
+                goto done;
+            default:
+                goto invalid;
+            }
+        }
+    }
+
+    s->buffer->pos = p;
+    s->state = state;
+
+    return NGX_AGAIN;
+
+done:
+
+    s->buffer->pos = p + 1;
+
+    if (s->arg_start) {
+        arg = ngx_array_push(&s->args);
+        if (arg == NULL) {
+            return NGX_ERROR;
+        }
+        arg->len = s->arg_end - s->arg_start;
+        arg->data = s->arg_start;
+        s->arg_start = NULL;
+        s->cmd_start = NULL;
+        s->quoted = 0;
+        s->literal_len = 0;
+    }
+
+    s->state = sw_start;
+
+    return NGX_OK;
+
+invalid:
+
+    s->state = sw_start;
+    s->quoted = 0;
+    s->literal_len = 0;
+
+    return NGX_IMAP_PARSE_INVALID_COMMAND;
+}
+
+
+ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s)
+{
+    u_char      ch, *p, *c, c0, c1, c2, c3;
+    ngx_str_t  *arg;
+    enum {
+        sw_start = 0,
+        sw_spaces_before_argument,
+        sw_argument,
+        sw_almost_done
+    } state;
+
+    state = s->state;
+
+    for (p = s->buffer->pos; p < s->buffer->last; p++) {
+        ch = *p;
+
+        switch (state) {
+
+        /* POP3 command */
+        case sw_start:
+            if (ch == ' ' || ch == CR || ch == LF) {
+                c = s->buffer->start;
+
+                if (p - c == 4) {
+
+                    c0 = ngx_toupper(c[0]);
+                    c1 = ngx_toupper(c[1]);
+                    c2 = ngx_toupper(c[2]);
+                    c3 = ngx_toupper(c[3]);
+
+                    if (c0 == 'U' && c1 == 'S' && c2 == 'E' && c3 == 'R')
+                    {
+                        s->command = NGX_POP3_USER;
+
+                    } else if (c0 == 'P' && c1 == 'A' && c2 == 'S' && c3 == 'S')
+                    {
+                        s->command = NGX_POP3_PASS;
+
+                    } else if (c0 == 'Q' && c1 == 'U' && c2 == 'I' && c3 == 'T')
+                    {
+                        s->command = NGX_POP3_QUIT;
+
+                    } else if (c0 == 'C' && c1 == 'A' && c2 == 'P' && c3 == 'A')
+                    {
+                        s->command = NGX_POP3_CAPA;
+
+                    } else if (c0 == 'N' && c1 == 'O' && c2 == 'O' && c3 == 'P')
+                    {
+                        s->command = NGX_POP3_NOOP;
+
+                    } else {
+                        goto invalid;
+                    }
+
+                } else {
+                    goto invalid;
+                }
+
+                switch (ch) {
+                case ' ':
+                    state = sw_spaces_before_argument;
+                    break;
+                case CR:
+                    state = sw_almost_done;
+                    break;
+                case LF:
+                    goto done;
+                }
+                break;
+            }
+
+            if ((ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
+                goto invalid;
+            }
+
+            break;
+
+        case sw_spaces_before_argument:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                state = sw_almost_done;
+                s->arg_end = p;
+                break;
+            case LF:
+                s->arg_end = p;
+                goto done;
+            default:
+                if (s->args.nelts <= 2) {
+                    state = sw_argument;
+                    s->arg_start = p;
+                    break;
+                }
+                goto invalid;
+            }
+            break;
+
         case sw_argument:
             switch (ch) {
             case ' ':
@@ -126,7 +438,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
                 if (arg == NULL) {
                     return NGX_ERROR;
                 }
-                arg->len = p - 1 - s->arg_start;
+                arg->len = p - s->arg_start;
                 arg->data = s->arg_start;
                 s->arg_start = NULL;
 
@@ -138,8 +450,7 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
                     state = sw_almost_done;
                     break;
                 case LF:
-                    state = sw_done;
-                    break;
+                    goto done;
                 }
                 break;
 
@@ -148,42 +459,42 @@ ngx_int_t ngx_pop3_parse_command(ngx_ima
             }
             break;
 
-        /* end of request line */
         case sw_almost_done:
             switch (ch) {
             case LF:
-                state = sw_done;
-                break;
+                goto done;
             default:
-                s->state = sw_start;
-                return NGX_IMAP_PARSE_INVALID_COMMAND;
+                goto invalid;
             }
-            break;
-
-        /* suppress warning */
-        case sw_done:
-            break;
         }
     }
 
     s->buffer->pos = p;
+    s->state = state;
 
-    if (state == sw_done) {
-        if (s->arg_start) {
-            arg = ngx_array_push(&s->args);
-            if (arg == NULL) {
-                return NGX_ERROR;
-            }
-            arg->len = s->arg_end - s->arg_start;
-            arg->data = s->arg_start;
-            s->arg_start = NULL;
+    return NGX_AGAIN;
+
+done:
+
+    s->buffer->pos = p + 1;
+
+    if (s->arg_start) {
+        arg = ngx_array_push(&s->args);
+        if (arg == NULL) {
+            return NGX_ERROR;
         }
+        arg->len = s->arg_end - s->arg_start;
+        arg->data = s->arg_start;
+        s->arg_start = NULL;
+    }
 
-        s->state = sw_start;
-        return NGX_OK;
+    s->state = sw_start;
 
-    } else {
-        s->state = state;
-        return NGX_AGAIN;
-    }
+    return NGX_OK;
+
+invalid:
+
+    s->state = sw_start;
+
+    return NGX_IMAP_PARSE_INVALID_COMMAND;
 }