changeset 316:a6d84efa5106 NGINX_0_6_2

nginx 0.6.2 *) Bugfix: if the FastCGI header was split in records, then nginx passed garbage in the header to a client.
author Igor Sysoev <http://sysoev.ru>
date Mon, 09 Jul 2007 00:00:00 +0400
parents f51e5273589b
children fcdf0e42c859
files CHANGES CHANGES.ru src/core/nginx.h src/http/modules/ngx_http_fastcgi_module.c src/http/modules/ngx_http_log_module.c src/http/modules/perl/nginx.pm
diffstat 6 files changed, 117 insertions(+), 27 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,10 @@
 
+Changes with nginx 0.6.2                                         09 Jul 2007
+
+    *) Bugfix: if the FastCGI header was split in records, then nginx 
+       passed garbage in the header to a client.
+
+
 Changes with nginx 0.6.1                                         17 Jun 2007
 
     *) Bugfix: in SSI parsing.
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,10 @@
 
+Изменения в nginx 0.6.2                                           09.07.2007
+
+    *) Исправление: если заголовок ответа был разделён в FastCGI-записях, 
+       то nginx передавал клиенту мусор в таких заголовках.
+
+
 Изменения в nginx 0.6.1                                           17.06.2007
 
     *) Исправление: в парсинге SSI.
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define NGINX_VERSION      "0.6.1"
+#define NGINX_VERSION      "0.6.2"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -38,6 +38,12 @@ typedef enum {
 
 
 typedef struct {
+    u_char                        *start;
+    u_char                        *end;
+} ngx_http_fastcgi_split_part_t;
+
+
+typedef struct {
     ngx_http_fastcgi_state_e       state;
     u_char                        *pos;
     u_char                        *last;
@@ -45,7 +51,9 @@ typedef struct {
     size_t                         length;
     size_t                         padding;
 
-    ngx_uint_t                     fastcgi_stdout;
+    ngx_uint_t                     fastcgi_stdout; /* unsigned :1 */
+
+    ngx_array_t                   *split_parts;
 } ngx_http_fastcgi_ctx_t;
 
 
@@ -840,15 +848,18 @@ ngx_http_fastcgi_reinit_request(ngx_http
 static ngx_int_t
 ngx_http_fastcgi_process_header(ngx_http_request_t *r)
 {
-    u_char                         *start, *last;
+    u_char                         *p, *start, *last, *part_start;
+    size_t                          size;
     ngx_str_t                      *status_line, line, *pattern;
     ngx_int_t                       rc, status;
+    ngx_buf_t                       buf;
     ngx_uint_t                      i;
     ngx_table_elt_t                *h;
     ngx_http_upstream_t            *u;
     ngx_http_fastcgi_ctx_t         *f;
     ngx_http_upstream_header_t     *hh;
     ngx_http_fastcgi_loc_conf_t    *flcf;
+    ngx_http_fastcgi_split_part_t  *part;
     ngx_http_upstream_main_conf_t  *umcf;
 
     f = ngx_http_get_module_ctx(r, ngx_http_fastcgi_module);
@@ -1017,6 +1028,8 @@ ngx_http_fastcgi_process_header(ngx_http
 
         for ( ;; ) {
 
+            part_start = u->buffer.pos;
+
             rc = ngx_http_parse_header_line(r, &u->buffer);
 
             ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
@@ -1035,24 +1048,72 @@ ngx_http_fastcgi_process_header(ngx_http
                     return NGX_HTTP_INTERNAL_SERVER_ERROR;
                 }
 
+                if (f->split_parts && f->split_parts->nelts) {
+
+                    part = f->split_parts->elts;
+                    size = u->buffer.pos - part_start;
+
+                    for (i = 0; i < f->split_parts->nelts; i++) {
+                        size += part[i].end - part[i].start;
+                    }
+
+                    p = ngx_palloc(r->pool, size);
+                    if (p == NULL) {
+                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                    }
+
+                    buf.pos = p;
+
+                    for (i = 0; i < f->split_parts->nelts; i++) {
+                        p = ngx_cpymem(p, part[i].start,
+                                       part[i].end - part[i].start);
+                    }
+
+                    p = ngx_cpymem(p, part_start, u->buffer.pos - part_start);
+
+                    buf.last = p;
+
+                    f->split_parts->nelts = 0;
+
+                    rc = ngx_http_parse_header_line(r, &buf);
+
+                    h->key.len = r->header_name_end - r->header_name_start;
+                    h->key.data = r->header_name_start;
+                    h->key.data[h->key.len] = '\0';
+
+                    h->value.len = r->header_end - r->header_start;
+                    h->value.data = r->header_start;
+                    h->value.data[h->value.len] = '\0';
+
+                    h->lowcase_key = ngx_palloc(r->pool, h->key.len);
+                    if (h->lowcase_key == NULL) {
+                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                    }
+
+                } else {
+
+                    h->key.len = r->header_name_end - r->header_name_start;
+                    h->value.len = r->header_end - r->header_start;
+
+                    h->key.data = ngx_palloc(r->pool,
+                                             h->key.len + 1 + h->value.len + 1
+                                             + h->key.len);
+                    if (h->key.data == NULL) {
+                        return NGX_HTTP_INTERNAL_SERVER_ERROR;
+                    }
+
+                    h->value.data = h->key.data + h->key.len + 1;
+                    h->lowcase_key = h->key.data + h->key.len + 1
+                                     + h->value.len + 1;
+
+                    ngx_cpystrn(h->key.data, r->header_name_start,
+                                h->key.len + 1);
+                    ngx_cpystrn(h->value.data, r->header_start,
+                                h->value.len + 1);
+                }
+
                 h->hash = r->header_hash;
 
-                h->key.len = r->header_name_end - r->header_name_start;
-                h->value.len = r->header_end - r->header_start;
-
-                h->key.data = ngx_palloc(r->pool,
-                               h->key.len + 1 + h->value.len + 1 + h->key.len);
-                if (h->key.data == NULL) {
-                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
-                }
-
-                h->value.data = h->key.data + h->key.len + 1;
-                h->lowcase_key = h->key.data + h->key.len + 1
-                                 + h->value.len + 1;
-
-                ngx_cpystrn(h->key.data, r->header_name_start, h->key.len + 1);
-                ngx_cpystrn(h->value.data, r->header_start, h->value.len + 1);
-
                 if (h->key.len == r->lowcase_index) {
                     ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);
 
@@ -1123,7 +1184,6 @@ ngx_http_fastcgi_process_header(ngx_http
                           "upstream sent invalid header");
 
             return NGX_HTTP_UPSTREAM_INVALID_HEADER;
-
         }
 
         if (last) {
@@ -1144,16 +1204,29 @@ ngx_http_fastcgi_process_header(ngx_http
             return NGX_OK;
         }
 
-        if (u->buffer.pos == u->buffer.last) {
+        if (rc == NGX_OK) {
             return NGX_AGAIN;
         }
 
-        if (rc == NGX_AGAIN) {
-            ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
-                          "upstream split a header line in FastCGI records");
-
-            return NGX_HTTP_UPSTREAM_INVALID_HEADER;
+        /* rc == NGX_AGAIN */
+
+        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+                       "upstream split a header line in FastCGI records");
+
+        if (f->split_parts == NULL) {
+            f->split_parts = ngx_array_create(r->pool, 1,
+                                        sizeof(ngx_http_fastcgi_split_part_t));
+            if (f->split_parts == NULL) {
+                return NGX_HTTP_INTERNAL_SERVER_ERROR;
+            }
         }
+
+        part = ngx_array_push(f->split_parts);
+
+        part->start = part_start;
+        part->end = u->buffer.last;
+
+        return NGX_AGAIN;
     }
 }
 
--- a/src/http/modules/ngx_http_log_module.c
+++ b/src/http/modules/ngx_http_log_module.c
@@ -423,6 +423,11 @@ ngx_http_log_bytes_sent(ngx_http_request
 }
 
 
+/*
+ * although there is a real $body_bytes_sent variable,
+ * this log operation code function is more optimized for logging
+ */
+
 static u_char *
 ngx_http_log_body_bytes_sent(ngx_http_request_t *r, u_char *buf,
     ngx_http_log_op_t *op)
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -47,7 +47,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '0.6.1';
+our $VERSION = '0.6.2';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);