diff src/http/ngx_http_parse.c @ 635:e67b227c8dbb default tip

Merge with current.
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 25 Apr 2011 04:07:55 +0400
parents c456a023113c
children
line wrap: on
line diff
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -112,8 +112,10 @@ ngx_http_parse_request_line(ngx_http_req
         sw_schema_slash_slash,
         sw_host,
         sw_port,
+        sw_host_http_09,
         sw_after_slash_in_uri,
         sw_check_uri,
+        sw_check_uri_http_09,
         sw_uri,
         sw_http_09,
         sw_http_H,
@@ -208,6 +210,10 @@ ngx_http_parse_request_line(ngx_http_req
                         r->method = NGX_HTTP_MKCOL;
                     }
 
+                    if (ngx_str5cmp(m, 'P', 'A', 'T', 'C', 'H')) {
+                        r->method = NGX_HTTP_PATCH;
+                    }
+
                     if (ngx_str5cmp(m, 'T', 'R', 'A', 'C', 'E')) {
                         r->method = NGX_HTTP_TRACE;
                     }
@@ -266,7 +272,7 @@ ngx_http_parse_request_line(ngx_http_req
         /* space* before URI */
         case sw_spaces_before_uri:
 
-            if (ch == '/' ){
+            if (ch == '/') {
                 r->uri_start = p;
                 state = sw_after_slash_in_uri;
                 break;
@@ -353,7 +359,7 @@ ngx_http_parse_request_line(ngx_http_req
                  */
                 r->uri_start = r->schema_end + 1;
                 r->uri_end = r->schema_end + 2;
-                state = sw_http_09;
+                state = sw_host_http_09;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
@@ -379,13 +385,35 @@ ngx_http_parse_request_line(ngx_http_req
                  */
                 r->uri_start = r->schema_end + 1;
                 r->uri_end = r->schema_end + 2;
-                state = sw_http_09;
+                state = sw_host_http_09;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
+        /* space+ after "http://host[:port] " */
+        case sw_host_http_09:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                r->http_minor = 9;
+                state = sw_almost_done;
+                break;
+            case LF:
+                r->http_minor = 9;
+                goto done;
+            case 'H':
+                r->http_protocol.data = p;
+                state = sw_http_H;
+                break;
+            default:
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+
         /* check "/.", "//", "%", and "\" (Win32) in URI */
         case sw_after_slash_in_uri:
 
@@ -397,7 +425,7 @@ ngx_http_parse_request_line(ngx_http_req
             switch (ch) {
             case ' ':
                 r->uri_end = p;
-                state = sw_http_09;
+                state = sw_check_uri_http_09;
                 break;
             case CR:
                 r->uri_end = p;
@@ -438,8 +466,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->plus_in_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             default:
                 state = sw_check_uri;
                 break;
@@ -463,7 +490,7 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             case ' ':
                 r->uri_end = p;
-                state = sw_http_09;
+                state = sw_check_uri_http_09;
                 break;
             case CR:
                 r->uri_end = p;
@@ -496,11 +523,34 @@ ngx_http_parse_request_line(ngx_http_req
                 r->plus_in_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
+        /* space+ after URI */
+        case sw_check_uri_http_09:
+            switch (ch) {
+            case ' ':
+                break;
+            case CR:
+                r->http_minor = 9;
+                state = sw_almost_done;
+                break;
+            case LF:
+                r->http_minor = 9;
+                goto done;
+            case 'H':
+                r->http_protocol.data = p;
+                state = sw_http_H;
+                break;
+            default:
+                r->space_in_uri = 1;
+                state = sw_check_uri;
                 break;
             }
             break;
 
+
         /* URI */
         case sw_uri:
 
@@ -526,8 +576,7 @@ ngx_http_parse_request_line(ngx_http_req
                 r->complex_uri = 1;
                 break;
             case '\0':
-                r->zero_in_uri = 1;
-                break;
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
@@ -548,7 +597,9 @@ ngx_http_parse_request_line(ngx_http_req
                 state = sw_http_H;
                 break;
             default:
-                return NGX_HTTP_PARSE_INVALID_REQUEST;
+                r->space_in_uri = 1;
+                state = sw_uri;
+                break;
             }
             break;
 
@@ -1190,19 +1241,14 @@ ngx_http_parse_complex_uri(ngx_http_requ
             if (ch >= '0' && ch <= '9') {
                 ch = (u_char) ((decoded << 4) + ch - '0');
 
-                if (ch == '%') {
+                if (ch == '%' || ch == '#') {
                     state = sw_usual;
                     *u++ = ch;
                     ch = *p++;
                     break;
-                }
-
-                if (ch == '#') {
-                    *u++ = ch;
-                    ch = *p++;
 
                 } else if (ch == '\0') {
-                    r->zero_in_uri = 1;
+                    return NGX_HTTP_PARSE_INVALID_REQUEST;
                 }
 
                 state = quoted_state;
@@ -1214,8 +1260,10 @@ ngx_http_parse_complex_uri(ngx_http_requ
                 ch = (u_char) ((decoded << 4) + c - 'a' + 10);
 
                 if (ch == '?') {
+                    state = sw_usual;
                     *u++ = ch;
                     ch = *p++;
+                    break;
 
                 } else if (ch == '+') {
                     r->plus_in_uri = 1;
@@ -1270,6 +1318,211 @@ args:
 
 
 ngx_int_t
+ngx_http_parse_status_line(ngx_http_request_t *r, ngx_buf_t *b,
+    ngx_http_status_t *status)
+{
+    u_char   ch;
+    u_char  *p;
+    enum {
+        sw_start = 0,
+        sw_H,
+        sw_HT,
+        sw_HTT,
+        sw_HTTP,
+        sw_first_major_digit,
+        sw_major_digit,
+        sw_first_minor_digit,
+        sw_minor_digit,
+        sw_status,
+        sw_space_after_status,
+        sw_status_text,
+        sw_almost_done
+    } state;
+
+    state = r->state;
+
+    for (p = b->pos; p < b->last; p++) {
+        ch = *p;
+
+        switch (state) {
+
+        /* "HTTP/" */
+        case sw_start:
+            switch (ch) {
+            case 'H':
+                state = sw_H;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_H:
+            switch (ch) {
+            case 'T':
+                state = sw_HT;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_HT:
+            switch (ch) {
+            case 'T':
+                state = sw_HTT;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_HTT:
+            switch (ch) {
+            case 'P':
+                state = sw_HTTP;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        case sw_HTTP:
+            switch (ch) {
+            case '/':
+                state = sw_first_major_digit;
+                break;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        /* the first digit of major HTTP version */
+        case sw_first_major_digit:
+            if (ch < '1' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            state = sw_major_digit;
+            break;
+
+        /* the major HTTP version or dot */
+        case sw_major_digit:
+            if (ch == '.') {
+                state = sw_first_minor_digit;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            break;
+
+        /* the first digit of minor HTTP version */
+        case sw_first_minor_digit:
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            state = sw_minor_digit;
+            break;
+
+        /* the minor HTTP version or the end of the request line */
+        case sw_minor_digit:
+            if (ch == ' ') {
+                state = sw_status;
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            break;
+
+        /* HTTP status code */
+        case sw_status:
+            if (ch == ' ') {
+                break;
+            }
+
+            if (ch < '0' || ch > '9') {
+                return NGX_ERROR;
+            }
+
+            status->code = status->code * 10 + ch - '0';
+
+            if (++status->count == 3) {
+                state = sw_space_after_status;
+                status->start = p - 2;
+            }
+
+            break;
+
+        /* space or end of line */
+        case sw_space_after_status:
+            switch (ch) {
+            case ' ':
+                state = sw_status_text;
+                break;
+            case '.':                    /* IIS may send 403.1, 403.2, etc */
+                state = sw_status_text;
+                break;
+            case CR:
+                state = sw_almost_done;
+                break;
+            case LF:
+                goto done;
+            default:
+                return NGX_ERROR;
+            }
+            break;
+
+        /* any text until end of line */
+        case sw_status_text:
+            switch (ch) {
+            case CR:
+                state = sw_almost_done;
+
+                break;
+            case LF:
+                goto done;
+            }
+            break;
+
+        /* end of status line */
+        case sw_almost_done:
+            status->end = p - 1;
+            switch (ch) {
+            case LF:
+                goto done;
+            default:
+                return NGX_ERROR;
+            }
+        }
+    }
+
+    b->pos = p;
+    r->state = state;
+
+    return NGX_AGAIN;
+
+done:
+
+    b->pos = p + 1;
+
+    if (status->end == NULL) {
+        status->end = p;
+    }
+
+    r->state = sw_start;
+
+    return NGX_OK;
+}
+
+
+ngx_int_t
 ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
     ngx_str_t *args, ngx_uint_t *flags)
 {
@@ -1304,8 +1557,7 @@ ngx_http_parse_unsafe_uri(ngx_http_reque
         }
 
         if (ch == '\0') {
-            *flags |= NGX_HTTP_ZERO_IN_URI;
-            continue;
+            goto unsafe;
         }
 
         if (ngx_path_separator(ch) && len > 2) {
@@ -1449,34 +1701,19 @@ ngx_http_arg(ngx_http_request_t *r, u_ch
 void
 ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
 {
-    u_char  ch, *p, *last;
-
-    p = uri->data;
-
-    last = p + uri->len;
+    u_char  *p, *last;
 
-    args->len = 0;
+    last = uri->data + uri->len;
 
-    while (p < last) {
-
-        ch = *p++;
+    p = ngx_strlchr(uri->data, last, '?');
 
-        if (ch == '?') {
-            args->len = last - p;
-            args->data = p;
-
-            uri->len = p - 1 - uri->data;
+    if (p) {
+        uri->len = p - uri->data;
+        p++;
+        args->len = last - p;
+        args->data = p;
 
-            if (ngx_strlchr(p, last, '\0') != NULL) {
-                r->zero_in_uri = 1;
-            }
-
-            return;
-        }
-
-        if (ch == '\0') {
-            r->zero_in_uri = 1;
-            continue;
-        }
+    } else {
+        args->len = 0;
     }
 }