# HG changeset patch # User Igor Sysoev # Date 1183924800 -14400 # Node ID a6d84efa510670a5401fbd31ddd28f6931a88869 # Parent f51e5273589ba67498271ad99cb0a8a959e90a39 nginx 0.6.2 *) Bugfix: if the FastCGI header was split in records, then nginx passed garbage in the header to a client. diff --git a/CHANGES b/CHANGES --- 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. diff --git a/CHANGES.ru b/CHANGES.ru --- 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. diff --git a/src/core/nginx.h b/src/core/nginx.h --- 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" diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- 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; } } diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- 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) diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- 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);