diff src/http/modules/ngx_http_proxy_module.c @ 692:6db6e93f55ee NGINX_1_3_9

nginx 1.3.9 *) Feature: support for chunked transfer encoding while reading client request body. *) Feature: the $request_time and $msec variables can now be used not only in the "log_format" directive. *) Bugfix: cache manager and cache loader processes might not be able to start if more than 512 listen sockets were used. *) Bugfix: in the ngx_http_dav_module.
author Igor Sysoev <http://sysoev.ru>
date Tue, 27 Nov 2012 00:00:00 +0400
parents f41d4b305d22
children 88a1b4797f2e
line wrap: on
line diff
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -81,12 +81,9 @@ 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;
+    off_t                          internal_body_length;
 
     ngx_uint_t                     head;  /* unsigned  head:1 */
 } ngx_http_proxy_ctx_t;
@@ -558,6 +555,8 @@ static char  ngx_http_proxy_version_11[]
 static ngx_keyval_t  ngx_http_proxy_headers[] = {
     { ngx_string("Host"), ngx_string("$proxy_host") },
     { ngx_string("Connection"), ngx_string("close") },
+    { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
+    { ngx_string("Transfer-Encoding"), ngx_string("") },
     { ngx_string("Keep-Alive"), ngx_string("") },
     { ngx_string("Expect"), ngx_string("") },
     { ngx_string("Upgrade"), ngx_string("") },
@@ -583,6 +582,8 @@ static ngx_str_t  ngx_http_proxy_hide_he
 static ngx_keyval_t  ngx_http_proxy_cache_headers[] = {
     { ngx_string("Host"), ngx_string("$proxy_host") },
     { ngx_string("Connection"), ngx_string("close") },
+    { ngx_string("Content-Length"), ngx_string("$proxy_internal_body_length") },
+    { ngx_string("Transfer-Encoding"), ngx_string("") },
     { ngx_string("Keep-Alive"), ngx_string("") },
     { ngx_string("Expect"), ngx_string("") },
     { ngx_string("Upgrade"), ngx_string("") },
@@ -1006,6 +1007,9 @@ ngx_http_proxy_create_request(ngx_http_r
 
         ctx->internal_body_length = body_len;
         len += body_len;
+
+    } else {
+        ctx->internal_body_length = r->headers_in.content_length_n;
     }
 
     le.ip = plcf->headers_set_len->elts;
@@ -1252,7 +1256,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 +1621,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 +1646,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 +1697,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 +1727,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 +1742,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 +1839,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 +1861,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;
             }
@@ -2301,7 +2046,7 @@ ngx_http_proxy_internal_body_length_vari
 
     ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_module);
 
-    if (ctx == NULL) {
+    if (ctx == NULL || ctx->internal_body_length < 0) {
         v->not_found = 1;
         return NGX_OK;
     }
@@ -2310,13 +2055,13 @@ ngx_http_proxy_internal_body_length_vari
     v->no_cacheable = 0;
     v->not_found = 0;
 
-    v->data = ngx_pnalloc(r->connection->pool, NGX_SIZE_T_LEN);
+    v->data = ngx_pnalloc(r->connection->pool, NGX_OFF_T_LEN);
 
     if (v->data == NULL) {
         return NGX_ERROR;
     }
 
-    v->len = ngx_sprintf(v->data, "%uz", ctx->internal_body_length) - v->data;
+    v->len = ngx_sprintf(v->data, "%O", ctx->internal_body_length) - v->data;
 
     return NGX_OK;
 }
@@ -3084,8 +2829,6 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
     }
 
     if (conf->headers_set_hash.buckets
-        && ((conf->body_source.data == NULL)
-            == (prev->body_source.data == NULL))
 #if (NGX_HTTP_CACHE)
         && ((conf->upstream.cache == NULL) == (prev->upstream.cache == NULL))
 #endif
@@ -3168,16 +2911,6 @@ ngx_http_proxy_merge_headers(ngx_conf_t 
         h++;
     }
 
-    if (conf->body_source.data) {
-        s = ngx_array_push(&headers_merged);
-        if (s == NULL) {
-            return NGX_ERROR;
-        }
-
-        ngx_str_set(&s->key, "Content-Length");
-        ngx_str_set(&s->value, "$proxy_internal_body_length");
-    }
-
 
     src = headers_merged.elts;
     for (i = 0; i < headers_merged.nelts; i++) {