[PATCH 08 of 13] Request body: chunked parsing moved to ngx_http_parse.c from proxy

Maxim Dounin mdounin at mdounin.ru
Fri Nov 16 11:02:30 UTC 2012


# HG changeset patch
# User Maxim Dounin <mdounin at mdounin.ru>
# Date 1352393278 -14400
# Node ID 9e14a7c2950b05c3f6550b4233ead43eefa57da5
# Parent  cc692c8a60ad93fa9092140d601d57bd38764ff0
Request body: chunked parsing moved to ngx_http_parse.c from proxy.

No functional changes.

diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -81,13 +81,10 @@ typedef struct {
 
 typedef struct {
     ngx_http_status_t              status;
+    ngx_http_chunked_t             chunked;
     ngx_http_proxy_vars_t          vars;
     size_t                         internal_body_length;
 
-    ngx_uint_t                     state;
-    off_t                          size;
-    off_t                          length;
-
     ngx_uint_t                     head;  /* unsigned  head:1 */
 } ngx_http_proxy_ctx_t;
 
@@ -1252,7 +1249,7 @@ ngx_http_proxy_reinit_request(ngx_http_r
     ctx->status.count = 0;
     ctx->status.start = NULL;
     ctx->status.end = NULL;
-    ctx->state = 0;
+    ctx->chunked.state = 0;
 
     r->upstream->process_header = ngx_http_proxy_process_status_line;
     r->upstream->pipe->input_filter = ngx_http_proxy_copy_filter;
@@ -1617,265 +1614,6 @@ ngx_http_proxy_copy_filter(ngx_event_pip
 }
 
 
-static ngx_inline ngx_int_t
-ngx_http_proxy_parse_chunked(ngx_http_request_t *r, ngx_buf_t *buf)
-{
-    u_char                *pos, ch, c;
-    ngx_int_t              rc;
-    ngx_http_proxy_ctx_t  *ctx;
-    enum {
-        sw_chunk_start = 0,
-        sw_chunk_size,
-        sw_chunk_extension,
-        sw_chunk_extension_almost_done,
-        sw_chunk_data,
-        sw_after_data,
-        sw_after_data_almost_done,
-        sw_last_chunk_extension,
-        sw_last_chunk_extension_almost_done,
-        sw_trailer,
-        sw_trailer_almost_done,
-        sw_trailer_header,
-        sw_trailer_header_almost_done
-    } state;
-
-    ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
-
-    if (ctx == NULL) {
-        return NGX_ERROR;
-    }
-
-    state = ctx->state;
-
-    if (state == sw_chunk_data && ctx->size == 0) {
-        state = sw_after_data;
-    }
-
-    rc = NGX_AGAIN;
-
-    for (pos = buf->pos; pos < buf->last; pos++) {
-
-        ch = *pos;
-
-        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
-                       "http proxy chunked byte: %02Xd s:%d", ch, state);
-
-        switch (state) {
-
-        case sw_chunk_start:
-            if (ch >= '0' && ch <= '9') {
-                state = sw_chunk_size;
-                ctx->size = ch - '0';
-                break;
-            }
-
-            c = (u_char) (ch | 0x20);
-
-            if (c >= 'a' && c <= 'f') {
-                state = sw_chunk_size;
-                ctx->size = c - 'a' + 10;
-                break;
-            }
-
-            goto invalid;
-
-        case sw_chunk_size:
-            if (ch >= '0' && ch <= '9') {
-                ctx->size = ctx->size * 16 + (ch - '0');
-                break;
-            }
-
-            c = (u_char) (ch | 0x20);
-
-            if (c >= 'a' && c <= 'f') {
-                ctx->size = ctx->size * 16 + (c - 'a' + 10);
-                break;
-            }
-
-            if (ctx->size == 0) {
-
-                switch (ch) {
-                case CR:
-                    state = sw_last_chunk_extension_almost_done;
-                    break;
-                case LF:
-                    state = sw_trailer;
-                    break;
-                case ';':
-                case ' ':
-                case '\t':
-                    state = sw_last_chunk_extension;
-                    break;
-                default:
-                    goto invalid;
-                }
-
-                break;
-            }
-
-            switch (ch) {
-            case CR:
-                state = sw_chunk_extension_almost_done;
-                break;
-            case LF:
-                state = sw_chunk_data;
-                break;
-            case ';':
-            case ' ':
-            case '\t':
-                state = sw_chunk_extension;
-                break;
-            default:
-                goto invalid;
-            }
-
-            break;
-
-        case sw_chunk_extension:
-            switch (ch) {
-            case CR:
-                state = sw_chunk_extension_almost_done;
-                break;
-            case LF:
-                state = sw_chunk_data;
-            }
-            break;
-
-        case sw_chunk_extension_almost_done:
-            if (ch == LF) {
-                state = sw_chunk_data;
-                break;
-            }
-            goto invalid;
-
-        case sw_chunk_data:
-            rc = NGX_OK;
-            goto data;
-
-        case sw_after_data:
-            switch (ch) {
-            case CR:
-                state = sw_after_data_almost_done;
-                break;
-            case LF:
-                state = sw_chunk_start;
-            }
-            break;
-
-        case sw_after_data_almost_done:
-            if (ch == LF) {
-                state = sw_chunk_start;
-                break;
-            }
-            goto invalid;
-
-        case sw_last_chunk_extension:
-            switch (ch) {
-            case CR:
-                state = sw_last_chunk_extension_almost_done;
-                break;
-            case LF:
-                state = sw_trailer;
-            }
-            break;
-
-        case sw_last_chunk_extension_almost_done:
-            if (ch == LF) {
-                state = sw_trailer;
-                break;
-            }
-            goto invalid;
-
-        case sw_trailer:
-            switch (ch) {
-            case CR:
-                state = sw_trailer_almost_done;
-                break;
-            case LF:
-                goto done;
-            default:
-                state = sw_trailer_header;
-            }
-            break;
-
-        case sw_trailer_almost_done:
-            if (ch == LF) {
-                goto done;
-            }
-            goto invalid;
-
-        case sw_trailer_header:
-            switch (ch) {
-            case CR:
-                state = sw_trailer_header_almost_done;
-                break;
-            case LF:
-                state = sw_trailer;
-            }
-            break;
-
-        case sw_trailer_header_almost_done:
-            if (ch == LF) {
-                state = sw_trailer;
-                break;
-            }
-            goto invalid;
-
-        }
-    }
-
-data:
-
-    ctx->state = state;
-    buf->pos = pos;
-
-    switch (state) {
-
-    case sw_chunk_start:
-        ctx->length = 3 /* "0" LF LF */;
-        break;
-    case sw_chunk_size:
-        ctx->length = 2 /* LF LF */
-                      + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
-        break;
-    case sw_chunk_extension:
-    case sw_chunk_extension_almost_done:
-        ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
-        break;
-    case sw_chunk_data:
-        ctx->length = ctx->size + 4 /* LF "0" LF LF */;
-        break;
-    case sw_after_data:
-    case sw_after_data_almost_done:
-        ctx->length = 4 /* LF "0" LF LF */;
-        break;
-    case sw_last_chunk_extension:
-    case sw_last_chunk_extension_almost_done:
-        ctx->length = 2 /* LF LF */;
-        break;
-    case sw_trailer:
-    case sw_trailer_almost_done:
-        ctx->length = 1 /* LF */;
-        break;
-    case sw_trailer_header:
-    case sw_trailer_header_almost_done:
-        ctx->length = 2 /* LF LF */;
-        break;
-
-    }
-
-    return rc;
-
-done:
-
-    return NGX_DONE;
-
-invalid:
-
-    return NGX_ERROR;
-}
-
-
 static ngx_int_t
 ngx_http_proxy_chunked_filter(ngx_event_pipe_t *p, ngx_buf_t *buf)
 {
@@ -1901,7 +1639,7 @@ ngx_http_proxy_chunked_filter(ngx_event_
 
     for ( ;; ) {
 
-        rc = ngx_http_proxy_parse_chunked(r, buf);
+        rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
 
         if (rc == NGX_OK) {
 
@@ -1952,16 +1690,16 @@ ngx_http_proxy_chunked_filter(ngx_event_
             ngx_log_debug2(NGX_LOG_DEBUG_EVENT, p->log, 0,
                            "input buf #%d %p", b->num, b->pos);
 
-            if (buf->last - buf->pos >= ctx->size) {
-
-                buf->pos += ctx->size;
+            if (buf->last - buf->pos >= ctx->chunked.size) {
+
+                buf->pos += ctx->chunked.size;
                 b->last = buf->pos;
-                ctx->size = 0;
+                ctx->chunked.size = 0;
 
                 continue;
             }
 
-            ctx->size -= buf->last - buf->pos;
+            ctx->chunked.size -= buf->last - buf->pos;
             buf->pos = buf->last;
             b->last = buf->last;
 
@@ -1982,7 +1720,7 @@ ngx_http_proxy_chunked_filter(ngx_event_
 
             /* set p->length, minimal amount of data we want to see */
 
-            p->length = ctx->length;
+            p->length = ctx->chunked.length;
 
             break;
         }
@@ -1997,7 +1735,7 @@ ngx_http_proxy_chunked_filter(ngx_event_
 
     ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "http proxy chunked state %d, length %d",
-                   ctx->state, p->length);
+                   ctx->chunked.state, p->length);
 
     if (b) {
         b->shadow = buf;
@@ -2094,7 +1832,7 @@ ngx_http_proxy_non_buffered_chunked_filt
 
     for ( ;; ) {
 
-        rc = ngx_http_proxy_parse_chunked(r, buf);
+        rc = ngx_http_parse_chunked(r, buf, &ctx->chunked);
 
         if (rc == NGX_OK) {
 
@@ -2116,13 +1854,13 @@ ngx_http_proxy_non_buffered_chunked_filt
             b->pos = buf->pos;
             b->tag = u->output.tag;
 
-            if (buf->last - buf->pos >= ctx->size) {
-                buf->pos += ctx->size;
+            if (buf->last - buf->pos >= ctx->chunked.size) {
+                buf->pos += ctx->chunked.size;
                 b->last = buf->pos;
-                ctx->size = 0;
+                ctx->chunked.size = 0;
 
             } else {
-                ctx->size -= buf->last - buf->pos;
+                ctx->chunked.size -= buf->last - buf->pos;
                 buf->pos = buf->last;
                 b->last = buf->last;
             }
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -18,6 +18,7 @@ typedef struct ngx_http_upstream_s    ng
 typedef struct ngx_http_cache_s       ngx_http_cache_t;
 typedef struct ngx_http_file_cache_s  ngx_http_file_cache_t;
 typedef struct ngx_http_log_ctx_s     ngx_http_log_ctx_t;
+typedef struct ngx_http_chunked_s     ngx_http_chunked_t;
 
 typedef ngx_int_t (*ngx_http_header_handler_pt)(ngx_http_request_t *r,
     ngx_table_elt_t *h, ngx_uint_t offset);
@@ -52,6 +53,13 @@ struct ngx_http_log_ctx_s {
 };
 
 
+struct ngx_http_chunked_s {
+    ngx_uint_t           state;
+    off_t                size;
+    off_t                length;
+};
+
+
 typedef struct {
     ngx_uint_t           http_version;
     ngx_uint_t           code;
@@ -92,6 +100,8 @@ ngx_int_t ngx_http_arg(ngx_http_request_
     ngx_str_t *value);
 void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,
     ngx_str_t *args);
+ngx_int_t ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
+    ngx_http_chunked_t *ctx);
 
 
 ngx_int_t ngx_http_find_server_conf(ngx_http_request_t *r);
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1818,3 +1818,256 @@ ngx_http_split_args(ngx_http_request_t *
         args->len = 0;
     }
 }
+
+
+ngx_int_t
+ngx_http_parse_chunked(ngx_http_request_t *r, ngx_buf_t *b,
+    ngx_http_chunked_t *ctx)
+{
+    u_char     *pos, ch, c;
+    ngx_int_t   rc;
+    enum {
+        sw_chunk_start = 0,
+        sw_chunk_size,
+        sw_chunk_extension,
+        sw_chunk_extension_almost_done,
+        sw_chunk_data,
+        sw_after_data,
+        sw_after_data_almost_done,
+        sw_last_chunk_extension,
+        sw_last_chunk_extension_almost_done,
+        sw_trailer,
+        sw_trailer_almost_done,
+        sw_trailer_header,
+        sw_trailer_header_almost_done
+    } state;
+
+    state = ctx->state;
+
+    if (state == sw_chunk_data && ctx->size == 0) {
+        state = sw_after_data;
+    }
+
+    rc = NGX_AGAIN;
+
+    for (pos = b->pos; pos < b->last; pos++) {
+
+        ch = *pos;
+
+        ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "http chunked byte: %02Xd s:%d", ch, state);
+
+        switch (state) {
+
+        case sw_chunk_start:
+            if (ch >= '0' && ch <= '9') {
+                state = sw_chunk_size;
+                ctx->size = ch - '0';
+                break;
+            }
+
+            c = (u_char) (ch | 0x20);
+
+            if (c >= 'a' && c <= 'f') {
+                state = sw_chunk_size;
+                ctx->size = c - 'a' + 10;
+                break;
+            }
+
+            goto invalid;
+
+        case sw_chunk_size:
+            if (ch >= '0' && ch <= '9') {
+                ctx->size = ctx->size * 16 + (ch - '0');
+                break;
+            }
+
+            c = (u_char) (ch | 0x20);
+
+            if (c >= 'a' && c <= 'f') {
+                ctx->size = ctx->size * 16 + (c - 'a' + 10);
+                break;
+            }
+
+            if (ctx->size == 0) {
+
+                switch (ch) {
+                case CR:
+                    state = sw_last_chunk_extension_almost_done;
+                    break;
+                case LF:
+                    state = sw_trailer;
+                    break;
+                case ';':
+                case ' ':
+                case '\t':
+                    state = sw_last_chunk_extension;
+                    break;
+                default:
+                    goto invalid;
+                }
+
+                break;
+            }
+
+            switch (ch) {
+            case CR:
+                state = sw_chunk_extension_almost_done;
+                break;
+            case LF:
+                state = sw_chunk_data;
+                break;
+            case ';':
+            case ' ':
+            case '\t':
+                state = sw_chunk_extension;
+                break;
+            default:
+                goto invalid;
+            }
+
+            break;
+
+        case sw_chunk_extension:
+            switch (ch) {
+            case CR:
+                state = sw_chunk_extension_almost_done;
+                break;
+            case LF:
+                state = sw_chunk_data;
+            }
+            break;
+
+        case sw_chunk_extension_almost_done:
+            if (ch == LF) {
+                state = sw_chunk_data;
+                break;
+            }
+            goto invalid;
+
+        case sw_chunk_data:
+            rc = NGX_OK;
+            goto data;
+
+        case sw_after_data:
+            switch (ch) {
+            case CR:
+                state = sw_after_data_almost_done;
+                break;
+            case LF:
+                state = sw_chunk_start;
+            }
+            break;
+
+        case sw_after_data_almost_done:
+            if (ch == LF) {
+                state = sw_chunk_start;
+                break;
+            }
+            goto invalid;
+
+        case sw_last_chunk_extension:
+            switch (ch) {
+            case CR:
+                state = sw_last_chunk_extension_almost_done;
+                break;
+            case LF:
+                state = sw_trailer;
+            }
+            break;
+
+        case sw_last_chunk_extension_almost_done:
+            if (ch == LF) {
+                state = sw_trailer;
+                break;
+            }
+            goto invalid;
+
+        case sw_trailer:
+            switch (ch) {
+            case CR:
+                state = sw_trailer_almost_done;
+                break;
+            case LF:
+                goto done;
+            default:
+                state = sw_trailer_header;
+            }
+            break;
+
+        case sw_trailer_almost_done:
+            if (ch == LF) {
+                goto done;
+            }
+            goto invalid;
+
+        case sw_trailer_header:
+            switch (ch) {
+            case CR:
+                state = sw_trailer_header_almost_done;
+                break;
+            case LF:
+                state = sw_trailer;
+            }
+            break;
+
+        case sw_trailer_header_almost_done:
+            if (ch == LF) {
+                state = sw_trailer;
+                break;
+            }
+            goto invalid;
+
+        }
+    }
+
+data:
+
+    ctx->state = state;
+    b->pos = pos;
+
+    switch (state) {
+
+    case sw_chunk_start:
+        ctx->length = 3 /* "0" LF LF */;
+        break;
+    case sw_chunk_size:
+        ctx->length = 2 /* LF LF */
+                      + (ctx->size ? ctx->size + 4 /* LF "0" LF LF */ : 0);
+        break;
+    case sw_chunk_extension:
+    case sw_chunk_extension_almost_done:
+        ctx->length = 1 /* LF */ + ctx->size + 4 /* LF "0" LF LF */;
+        break;
+    case sw_chunk_data:
+        ctx->length = ctx->size + 4 /* LF "0" LF LF */;
+        break;
+    case sw_after_data:
+    case sw_after_data_almost_done:
+        ctx->length = 4 /* LF "0" LF LF */;
+        break;
+    case sw_last_chunk_extension:
+    case sw_last_chunk_extension_almost_done:
+        ctx->length = 2 /* LF LF */;
+        break;
+    case sw_trailer:
+    case sw_trailer_almost_done:
+        ctx->length = 1 /* LF */;
+        break;
+    case sw_trailer_header:
+    case sw_trailer_header_almost_done:
+        ctx->length = 2 /* LF LF */;
+        break;
+
+    }
+
+    return rc;
+
+done:
+
+    return NGX_DONE;
+
+invalid:
+
+    return NGX_ERROR;
+}



More information about the nginx-devel mailing list