# HG changeset patch # User Igor Sysoev # Date 1276545600 -14400 # Node ID bc110f60c0de90e5a56424c85286e46321e0b884 # Parent dd4c3325a56f8b2e4233bdebada81f2c0c82a14f nginx 0.8.41 *) Security: nginx/Windows worker might be terminated abnormally if a requested file name has invalid UTF-8 encoding. *) Change: now nginx allows to use spaces in a request line. *) Bugfix: the "proxy_redirect" directive changed incorrectly a backend "Refresh" response header line. Thanks to Andrey Andreew and Max Sogin. *) Bugfix: nginx did not support path without host name in "Destination" request header line. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,19 @@ +Changes with nginx 0.8.41 15 Jun 2010 + + *) Security: nginx/Windows worker might be terminated abnormally if a + requested file name has invalid UTF-8 encoding. + + *) Change: now nginx allows to use spaces in a request line. + + *) Bugfix: the "proxy_redirect" directive changed incorrectly a backend + "Refresh" response header line. + Thanks to Andrey Andreew and Max Sogin. + + *) Bugfix: nginx did not support path without host name in + "Destination" request header line. + + Changes with nginx 0.8.40 07 Jun 2010 *) Security: now nginx/Windows ignores default file stream name. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,20 @@ +Изменения в nginx 0.8.41 15.06.2010 + + *) Безопасность: рабочий процесс nginx/Windows мог завершаться аварийно + при запросе файла с неверной кодировкой UTF-8. + + *) Изменение: теперь nginx разрешает использовать пробелы в строке + запроса. + + *) Исправление: директива proxy_redirect неправильно изменяла строку + "Refresh" в заголовке ответа бэкенда. + Спасибо Андрею Андрееву и Максиму Согину. + + *) Исправление: nginx не поддерживал путь без имени хоста в строке + "Destination" в заголовке запроса. + + Изменения в nginx 0.8.40 07.06.2010 *) Безопасность: теперь nginx/Windows игнорирует имя потока файла по diff --git a/auto/install b/auto/install --- a/auto/install +++ b/auto/install @@ -105,6 +105,11 @@ install: $NGX_OBJS${ngx_dirsep}nginx${ng || cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX' cp conf/fastcgi.conf '\$(DESTDIR)$NGX_CONF_PREFIX/fastcgi.conf.default' + test -f '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params' \ + || cp conf/uwsgi_params '\$(DESTDIR)$NGX_CONF_PREFIX' + cp conf/uwsgi_params \ + '\$(DESTDIR)$NGX_CONF_PREFIX/uwsgi_params.default' + test -f '\$(DESTDIR)$NGX_CONF_PATH' \ || cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PATH' cp conf/nginx.conf '\$(DESTDIR)$NGX_CONF_PREFIX/nginx.conf.default' diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 8040 -#define NGINX_VERSION "0.8.40" +#define nginx_version 8041 +#define NGINX_VERSION "0.8.41" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -535,6 +535,13 @@ ngx_http_dav_copy_move_handler(ngx_http_ return NGX_HTTP_BAD_REQUEST; } + p = dest->value.data; + /* there is always '\0' even after empty header value */ + if (p[0] == '/') { + last = p + dest->value.len; + goto destination_done; + } + len = r->headers_in.server.len; if (len == 0) { 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 @@ -628,49 +628,51 @@ ngx_http_fastcgi_handler(ngx_http_reques static ngx_int_t ngx_http_fastcgi_eval(ngx_http_request_t *r, ngx_http_fastcgi_loc_conf_t *flcf) { - ngx_url_t u; - - ngx_memzero(&u, sizeof(ngx_url_t)); - - if (ngx_http_script_run(r, &u.url, flcf->fastcgi_lengths->elts, 0, + ngx_url_t url; + ngx_http_upstream_t *u; + + ngx_memzero(&url, sizeof(ngx_url_t)); + + if (ngx_http_script_run(r, &url.url, flcf->fastcgi_lengths->elts, 0, flcf->fastcgi_values->elts) == NULL) { return NGX_ERROR; } - u.no_resolve = 1; - - if (ngx_parse_url(r->pool, &u) != NGX_OK) { - if (u.err) { + url.no_resolve = 1; + + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + if (url.err) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "%s in upstream \"%V\"", u.err, &u.url); + "%s in upstream \"%V\"", url.err, &url.url); } return NGX_ERROR; } - if (u.no_port) { + if (url.no_port) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "no port in upstream \"%V\"", &u.url); - return NGX_ERROR; - } - - r->upstream->resolved = ngx_pcalloc(r->pool, - sizeof(ngx_http_upstream_resolved_t)); - if (r->upstream->resolved == NULL) { + "no port in upstream \"%V\"", &url.url); return NGX_ERROR; } - if (u.addrs && u.addrs[0].sockaddr) { - r->upstream->resolved->sockaddr = u.addrs[0].sockaddr; - r->upstream->resolved->socklen = u.addrs[0].socklen; - r->upstream->resolved->naddrs = 1; - r->upstream->resolved->host = u.addrs[0].name; + u = r->upstream; + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { + return NGX_ERROR; + } + + if (url.addrs && url.addrs[0].sockaddr) { + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; } else { - r->upstream->resolved->host = u.host; - r->upstream->resolved->port = u.port; + u->resolved->host = url.host; + u->resolved->port = url.port; } return NGX_OK; 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 @@ -911,7 +911,7 @@ ngx_http_proxy_create_request(ngx_http_r loc_len = (r->valid_location && ctx->vars.uri.len) ? plcf->location.len : 0; - if (r->quoted_uri || r->internal) { + if (r->quoted_uri || r->space_in_uri || r->internal) { escape = 2 * ngx_escape_uri(NULL, r->uri.data + loc_len, r->uri.len - loc_len, NGX_ESCAPE_URI); } @@ -1765,16 +1765,14 @@ ngx_http_proxy_rewrite_redirect_text(ngx return NGX_DECLINED; } - len = prefix + pr->replacement.text.len + h->value.len - pr->redirect.len; + len = pr->replacement.text.len + h->value.len - pr->redirect.len; data = ngx_pnalloc(r->pool, len); if (data == NULL) { return NGX_ERROR; } - p = data; - - p = ngx_copy(p, h->value.data, prefix); + p = ngx_copy(data, h->value.data, prefix); if (pr->replacement.text.len) { p = ngx_copy(p, pr->replacement.text.data, pr->replacement.text.len); @@ -1812,7 +1810,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx e.ip = pr->replacement.vars.lengths; e.request = r; - len = prefix + h->value.len - pr->redirect.len; + len = h->value.len - pr->redirect.len; while (*(uintptr_t *) e.ip) { lcode = *(ngx_http_script_len_code_pt *) e.ip; @@ -1824,9 +1822,7 @@ ngx_http_proxy_rewrite_redirect_vars(ngx return NGX_ERROR; } - p = data; - - p = ngx_copy(p, h->value.data, prefix); + p = ngx_copy(data, h->value.data, prefix); e.ip = pr->replacement.vars.values; e.pos = p; diff --git a/src/http/modules/ngx_http_split_clients_module.c b/src/http/modules/ngx_http_split_clients_module.c --- a/src/http/modules/ngx_http_split_clients_module.c +++ b/src/http/modules/ngx_http_split_clients_module.c @@ -163,6 +163,10 @@ ngx_conf_split_clients_block(ngx_conf_t *cf = save; + if (rv != NGX_CONF_OK) { + return rv; + } + sum = 0; last = 0; part = ctx->parts.elts; diff --git a/src/http/modules/ngx_http_uwsgi_module.c b/src/http/modules/ngx_http_uwsgi_module.c --- a/src/http/modules/ngx_http_uwsgi_module.c +++ b/src/http/modules/ngx_http_uwsgi_module.c @@ -495,49 +495,51 @@ ngx_http_uwsgi_handler(ngx_http_request_ static ngx_int_t ngx_http_uwsgi_eval(ngx_http_request_t *r, ngx_http_uwsgi_loc_conf_t * uwcf) { - ngx_url_t u; + ngx_url_t url; + ngx_http_upstream_t *u; - ngx_memzero(&u, sizeof(ngx_url_t)); + ngx_memzero(&url, sizeof(ngx_url_t)); - if (ngx_http_script_run(r, &u.url, uwcf->uwsgi_lengths->elts, 0, + if (ngx_http_script_run(r, &url.url, uwcf->uwsgi_lengths->elts, 0, uwcf->uwsgi_values->elts) == NULL) { return NGX_ERROR; } - u.no_resolve = 1; + url.no_resolve = 1; - if (ngx_parse_url(r->pool, &u) != NGX_OK) { - if (u.err) { + if (ngx_parse_url(r->pool, &url) != NGX_OK) { + if (url.err) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "%s in upstream \"%V\"", u.err, &u.url); + "%s in upstream \"%V\"", url.err, &url.url); } return NGX_ERROR; } - if (u.no_port) { + if (url.no_port) { ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "no port in upstream \"%V\"", &u.url); + "no port in upstream \"%V\"", &url.url); return NGX_ERROR; } - r->upstream->resolved = ngx_pcalloc(r->pool, - sizeof(ngx_http_upstream_resolved_t)); - if (r->upstream->resolved == NULL) { + u = r->upstream; + + u->resolved = ngx_pcalloc(r->pool, sizeof(ngx_http_upstream_resolved_t)); + if (u->resolved == NULL) { return NGX_ERROR; } - if (u.addrs && u.addrs[0].sockaddr) { - r->upstream->resolved->sockaddr = u.addrs[0].sockaddr; - r->upstream->resolved->socklen = u.addrs[0].socklen; - r->upstream->resolved->naddrs = 1; - r->upstream->resolved->host = u.addrs[0].name; + if (url.addrs && url.addrs[0].sockaddr) { + u->resolved->sockaddr = url.addrs[0].sockaddr; + u->resolved->socklen = url.addrs[0].socklen; + u->resolved->naddrs = 1; + u->resolved->host = url.addrs[0].name; } else { - r->upstream->resolved->host = u.host; - r->upstream->resolved->port = u.port; + u->resolved->host = url.host; + u->resolved->port = url.port; } return NGX_OK; @@ -831,8 +833,6 @@ ngx_http_uwsgi_create_request(ngx_http_r body = body->next; } - b->flush = 1; - } else { r->upstream->request_bufs = cl; } @@ -1199,38 +1199,6 @@ ngx_http_uwsgi_process_header(ngx_http_r ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "http uwsgi header done"); - /* - * if no "Server" and "Date" in header line, - * then add the special empty headers - */ - - if (r->upstream->headers_in.server == NULL) { - h = ngx_list_push(&r->upstream->headers_in.headers); - if (h == NULL) { - return NGX_ERROR; - } - - h->hash = ngx_hash(ngx_hash(ngx_hash(ngx_hash( - ngx_hash ('s', 'e'), 'r'), 'v'), 'e'), 'r'); - - ngx_str_set(&h->key, "Server"); - ngx_str_null(&h->value); - h->lowcase_key = (u_char *) "server"; - } - - if (r->upstream->headers_in.date == NULL) { - h = ngx_list_push(&r->upstream->headers_in.headers); - if (h == NULL) { - return NGX_ERROR; - } - - h->hash = ngx_hash(ngx_hash(ngx_hash('d', 'a'), 't'), 'e'); - - ngx_str_set(&h->key, "Date"); - ngx_str_null(&h->value); - h->lowcase_key = (u_char *) "date"; - } - return NGX_OK; } 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 @@ -14,6 +14,7 @@ our @EXPORT = qw( HTTP_OK HTTP_CREATED + HTTP_ACCEPTED HTTP_NO_CONTENT HTTP_PARTIAL_CONTENT @@ -47,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.8.40'; +our $VERSION = '0.8.41'; require XSLoader; XSLoader::load('nginx', $VERSION); @@ -59,6 +60,7 @@ use constant DECLINED use constant HTTP_OK => 200; use constant HTTP_CREATED => 201; +use constant HTTP_ACCEPTED => 202; use constant HTTP_NO_CONTENT => 204; use constant HTTP_PARTIAL_CONTENT => 206; diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -824,10 +824,6 @@ ngx_http_handler(ngx_http_request_t *r) r->phase_handler = cmcf->phase_engine.server_rewrite_index; } - if (r->unparsed_uri.len) { - r->valid_unparsed_uri = 1; - } - r->valid_location = 1; #if (NGX_HTTP_GZIP) r->gzip_tested = 0; @@ -3707,6 +3703,7 @@ static ngx_http_method_name_t ngx_metho { (u_char *) "PROPPATCH", (uint32_t) ~NGX_HTTP_PROPPATCH }, { (u_char *) "LOCK", (uint32_t) ~NGX_HTTP_LOCK }, { (u_char *) "UNLOCK", (uint32_t) ~NGX_HTTP_UNLOCK }, + { (u_char *) "PATCH", (uint32_t) ~NGX_HTTP_PATCH }, { NULL, 0 } }; diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -53,7 +53,7 @@ static ngx_str_t ngx_http_status_lines[] ngx_string("200 OK"), ngx_string("201 Created"), - ngx_null_string, /* "202 Accepted" */ + ngx_string("202 Accepted"), ngx_null_string, /* "203 Non-Authoritative Information" */ ngx_string("204 No Content"), ngx_null_string, /* "205 Reset Content" */ 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 @@ -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; } @@ -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; @@ -462,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; @@ -499,6 +527,30 @@ ngx_http_parse_request_line(ngx_http_req } 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: @@ -545,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; diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c --- a/src/http/ngx_http_request.c +++ b/src/http/ngx_http_request.c @@ -756,6 +756,7 @@ ngx_http_process_request_line(ngx_event_ r->unparsed_uri.len = r->uri_end - r->uri_start; r->unparsed_uri.data = r->uri_start; + r->valid_unparsed_uri = r->space_in_uri ? 0 : 1; r->method_name.len = r->method_end - r->request_start + 1; r->method_name.data = r->request_line.data; diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -37,7 +37,8 @@ #define NGX_HTTP_PROPPATCH 0x0800 #define NGX_HTTP_LOCK 0x1000 #define NGX_HTTP_UNLOCK 0x2000 -#define NGX_HTTP_TRACE 0x4000 +#define NGX_HTTP_PATCH 0x4000 +#define NGX_HTTP_TRACE 0x8000 #define NGX_HTTP_CONNECTION_CLOSE 1 #define NGX_HTTP_CONNECTION_KEEP_ALIVE 2 @@ -64,6 +65,7 @@ #define NGX_HTTP_OK 200 #define NGX_HTTP_CREATED 201 +#define NGX_HTTP_ACCEPTED 202 #define NGX_HTTP_NO_CONTENT 204 #define NGX_HTTP_PARTIAL_CONTENT 206 @@ -435,6 +437,9 @@ struct ngx_http_request_s { /* URI with "+" */ unsigned plus_in_uri:1; + /* URI with " " */ + unsigned space_in_uri:1; + unsigned invalid_header:1; unsigned add_uri_to_alias:1;