changeset 528:005a70f9573b NGINX_0_8_16

nginx 0.8.16 *) Feature: the "image_filter_transparency" directive. *) Bugfix: "addition_types" directive was incorrectly named "addtion_types". *) Bugfix: resolver cache poisoning. Thanks to Matthew Dempsky. *) Bugfix: memory leak in resolver. Thanks to Matthew Dempsky. *) Bugfix: invalid request line in $request variable was written in access_log only if error_log was set to "info" or "debug" level. *) Bugfix: in PNG alpha-channel support in the ngx_http_image_filter_module. *) Bugfix: nginx always added "Vary: Accept-Encoding" response header line, if both "gzip_static" and "gzip_vary" were on. *) Bugfix: in UTF-8 encoding support by "try_files" directive in nginx/Windows. *) Bugfix: in "post_action" directive usage; the bug had appeared in 0.8.11. Thanks to Igor Artemiev.
author Igor Sysoev <http://sysoev.ru>
date Tue, 22 Sep 2009 00:00:00 +0400
parents a607f3a5aefe
children b8ac674b0ec9
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_cycle.c src/core/ngx_output_chain.c src/core/ngx_resolver.c src/http/modules/ngx_http_addition_filter_module.c src/http/modules/ngx_http_gzip_static_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_ssl_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/ngx_http_perl_module.c src/http/ngx_http_file_cache.c src/http/ngx_http_request.c src/http/ngx_http_variables.c
diffstat 15 files changed, 198 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,34 @@
 
+Changes with nginx 0.8.16                                        22 Sep 2009
+
+    *) Feature: the "image_filter_transparency" directive.
+
+    *) Bugfix: "addition_types" directive was incorrectly named 
+       "addtion_types".
+
+    *) Bugfix: resolver cache poisoning.
+       Thanks to Matthew Dempsky.
+
+    *) Bugfix: memory leak in resolver.
+       Thanks to Matthew Dempsky.
+
+    *) Bugfix: invalid request line in $request variable was written in 
+       access_log only if error_log was set to "info" or "debug" level.
+
+    *) Bugfix: in PNG alpha-channel support in the 
+       ngx_http_image_filter_module.
+
+    *) Bugfix: nginx always added "Vary: Accept-Encoding" response header 
+       line, if both "gzip_static" and "gzip_vary" were on.
+
+    *) Bugfix: in UTF-8 encoding support by "try_files" directive in 
+       nginx/Windows.
+
+    *) Bugfix: in "post_action" directive usage; the bug had appeared in 
+       0.8.11.
+       Thanks to Igor Artemiev.
+
+
 Changes with nginx 0.8.15                                        14 Sep 2009
 
     *) Security: a segmentation fault might occur in worker process while 
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,36 @@
 
+Изменения в nginx 0.8.16                                          22.09.2009
+
+    *) Добавление: директива image_filter_transparency.
+
+    *) Исправление: директива "addition_types" была неверно названа 
+       "addtion_types".
+
+    *) Исправление: порчи кэша resolver'а.
+       Спасибо Matthew Dempsky.
+
+    *) Исправление: утечки памяти в resolver'е.
+       Спасибо Matthew Dempsky.
+
+    *) Исправление: неверная строка запроса в переменной $request 
+       записывалась в access_log только при использовании error_log на 
+       уровне info или debug.
+
+    *) Исправление: в поддержке альфа-канала PNG в модуле 
+       ngx_http_image_filter_module.
+
+    *) Исправление: nginx всегда добавлял строку "Vary: Accept-Encoding" в 
+       заголовок ответа, если обе директивы gzip_static и gzip_vary были 
+       включены.
+
+    *) Исправление: в поддержке кодировки UTF-8 директивой try_files в 
+       nginx/Windows.
+
+    *) Исправление: ошибки при использовании post_action; ошибка появилась 
+       в 0.8.11.
+       Спасибо Игорю Артемьеву.
+
+
 Изменения в nginx 0.8.15                                          14.09.2009
 
     *) Безопасность: при обработке специально созданного запроса в рабочем 
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version         8015
-#define NGINX_VERSION      "0.8.15"
+#define nginx_version         8016
+#define NGINX_VERSION      "0.8.16"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -255,11 +255,13 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
 #endif
 
     if (ngx_conf_param(&conf) != NGX_CONF_OK) {
+        environ = senv;
         ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
 
     if (ngx_conf_parse(&conf, &cycle->conf_file) != NGX_CONF_OK) {
+        environ = senv;
         ngx_destroy_cycle_pools(&conf);
         return NULL;
     }
@@ -280,6 +282,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle)
             if (module->init_conf(cycle, cycle->conf_ctx[ngx_modules[i]->index])
                 == NGX_CONF_ERROR)
             {
+                environ = senv;
                 ngx_destroy_cycle_pools(&conf);
                 return NULL;
             }
@@ -698,8 +701,8 @@ old_shm_zone_done:
     if (ngx_process == NGX_PROCESS_MASTER || ngx_is_init_cycle(old_cycle)) {
 
         /*
-         * perl_destruct() frees environ if it is not the same as it was at
-         * perl_construct() time.  So we have saved an previous cycle
+         * perl_destruct() frees environ, if it is not the same as it was at
+         * perl_construct() time, therefore we save the previous cycle
          * environment before ngx_conf_parse() where it will be changed.
          */
 
--- a/src/core/ngx_output_chain.c
+++ b/src/core/ngx_output_chain.c
@@ -571,9 +571,7 @@ ngx_output_chain_copy_buf(ngx_output_cha
             ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0,
                           ngx_read_file_n " read only %z of %O from \"%s\"",
                           n, size, src->file->name.data);
-            if (n == 0) {
-                return NGX_ERROR;
-            }
+            return NGX_ERROR;
         }
 
         dst->last += n;
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -1149,6 +1149,8 @@ ngx_resolver_process_a(ngx_resolver_t *r
         goto failed;
     }
 
+    ngx_resolver_free(r, name.data);
+
     if (code == 0 && nan == 0) {
         code = 3; /* NXDOMAIN */
     }
@@ -1400,6 +1402,8 @@ failed:
 
     /* unlock name mutex */
 
+    ngx_resolver_free(r, name.data);
+
     return;
 }
 
@@ -1595,7 +1599,6 @@ static ngx_resolver_node_t *
 ngx_resolver_lookup_name(ngx_resolver_t *r, ngx_str_t *name, uint32_t hash)
 {
     ngx_int_t             rc;
-    size_t                len;
     ngx_rbtree_node_t    *node, *sentinel;
     ngx_resolver_node_t  *rn;
 
@@ -1619,9 +1622,7 @@ ngx_resolver_lookup_name(ngx_resolver_t 
         do {
             rn = (ngx_resolver_node_t *) node;
 
-            len = (name->len > (size_t) rn->nlen) ? rn->nlen : name->len;
-
-            rc = ngx_strncmp(name->data, rn->name, len);
+            rc = ngx_memn2cmp(name->data, rn->name, name->len, rn->nlen);
 
             if (rc == 0) {
                 return rn;
@@ -1675,7 +1676,6 @@ static void
 ngx_resolver_rbtree_insert_value(ngx_rbtree_node_t *temp,
     ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel)
 {
-    size_t                 len;
     ngx_rbtree_node_t    **p;
     ngx_resolver_node_t   *rn, *rn_temp;
 
@@ -1694,10 +1694,8 @@ ngx_resolver_rbtree_insert_value(ngx_rbt
             rn = (ngx_resolver_node_t *) node;
             rn_temp = (ngx_resolver_node_t *) temp;
 
-            len = (rn->nlen > rn_temp->nlen) ? rn_temp->nlen : rn->nlen;
-
-            p = (ngx_strncmp(rn->name, rn_temp->name, len) < 0)
-                    ? &temp->left : &temp->right;
+            p = (ngx_memn2cmp(rn->name, rn_temp->name, rn->nlen, rn_temp->nlen)
+                 < 0) ? &temp->left : &temp->right;
         }
 
         if (*p == sentinel) {
--- a/src/http/modules/ngx_http_addition_filter_module.c
+++ b/src/http/modules/ngx_http_addition_filter_module.c
@@ -45,7 +45,7 @@ static ngx_command_t  ngx_http_addition_
       offsetof(ngx_http_addition_conf_t, after_body),
       NULL },
 
-    { ngx_string("addtion_types"),
+    { ngx_string("addition_types"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
       ngx_http_types_slot,
       NGX_HTTP_LOC_CONF_OFFSET,
--- a/src/http/modules/ngx_http_gzip_static_module.c
+++ b/src/http/modules/ngx_http_gzip_static_module.c
@@ -95,7 +95,13 @@ ngx_http_gzip_static_handler(ngx_http_re
 
     gzcf = ngx_http_get_module_loc_conf(r, ngx_http_gzip_static_module);
 
-    if (!gzcf->enable || ngx_http_gzip_ok(r) != NGX_OK) {
+    if (!gzcf->enable) {
+        return NGX_DECLINED;
+    }
+
+    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+    if (clcf->gzip_vary && ngx_http_gzip_ok(r) != NGX_OK) {
         return NGX_DECLINED;
     }
 
@@ -116,8 +122,6 @@ ngx_http_gzip_static_handler(ngx_http_re
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, log, 0,
                    "http filename: \"%s\"", path.data);
 
-    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
-
     ngx_memzero(&of, sizeof(ngx_open_file_info_t));
 
     of.directio = clcf->directio;
@@ -138,6 +142,7 @@ ngx_http_gzip_static_handler(ngx_http_re
         case NGX_ENOTDIR:
         case NGX_ENAMETOOLONG:
 
+            r->gzip = 0;
             return NGX_DECLINED;
 
         case NGX_EACCES:
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -40,6 +40,8 @@ typedef struct {
     ngx_uint_t                   height;
     ngx_int_t                    jpeg_quality;
 
+    ngx_flag_t                   transparency;
+
     ngx_http_complex_value_t    *wcv;
     ngx_http_complex_value_t    *hcv;
 
@@ -115,6 +117,13 @@ static ngx_command_t  ngx_http_image_fil
       offsetof(ngx_http_image_filter_conf_t, jpeg_quality),
       NULL },
 
+    { ngx_string("image_filter_transparency"),
+      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
+      ngx_conf_set_flag_slot,
+      NGX_HTTP_LOC_CONF_OFFSET,
+      offsetof(ngx_http_image_filter_conf_t, transparency),
+      NULL },
+
     { ngx_string("image_filter_buffer"),
       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
       ngx_conf_set_size_slot,
@@ -678,8 +687,9 @@ ngx_http_image_size(ngx_http_request_t *
 static ngx_buf_t *
 ngx_http_image_resize(ngx_http_request_t *r, ngx_http_image_filter_ctx_t *ctx)
 {
-    int                            sx, sy, dx, dy, ox, oy,
-                                   colors, transparent, red, green, blue, size;
+    int                            sx, sy, dx, dy, ox, oy, size,
+                                   colors, palette, transparent,
+                                   red, green, blue;
     u_char                        *out;
     ngx_buf_t                     *b;
     ngx_uint_t                     resize;
@@ -706,17 +716,29 @@ ngx_http_image_resize(ngx_http_request_t
     }
 
     colors = gdImageColorsTotal(src);
-    transparent = gdImageGetTransparent(src);
+
+    if (colors && conf->transparency) {
+        transparent = gdImageGetTransparent(src);
+
+        if (transparent != -1) {
+            palette = colors;
+            red = gdImageRed(src, transparent);
+            green = gdImageGreen(src, transparent);
+            blue = gdImageBlue(src, transparent);
 
-    if (transparent != -1 && colors) {
-        red = gdImageRed(src, transparent);
-        green = gdImageGreen(src, transparent);
-        blue = gdImageBlue(src, transparent);
-        gdImageColorTransparent(src, -1);
+            goto transparent;
+        }
+    }
 
-    } else {
-        red = 0; green = 0; blue = 0;
-    }
+    palette = 0;
+    transparent = -1;
+    red = 0;
+    green = 0;
+    blue = 0;
+
+transparent:
+
+    gdImageColorTransparent(src, -1);
 
     dx = sx;
     dy = sy;
@@ -762,14 +784,23 @@ ngx_http_image_resize(ngx_http_request_t
     }
 
     if (resize) {
-        dst = ngx_http_image_new(r, dx, dy, colors);
+        dst = ngx_http_image_new(r, dx, dy, palette);
         if (dst == NULL) {
             gdImageDestroy(src);
             return NULL;
         }
 
+        if (colors == 0) {
+            gdImageSaveAlpha(dst, 1);
+            gdImageAlphaBlending(dst, 0);
+        }
+
         gdImageCopyResampled(dst, src, 0, 0, 0, 0, dx, dy, sx, sy);
 
+        if (colors) {
+            gdImageTrueColorToPalette(dst, 1, 256);
+        }
+
         gdImageDestroy(src);
 
     } else {
@@ -810,8 +841,17 @@ ngx_http_image_resize(ngx_http_request_t
                            "image crop: %d x %d @ %d x %d",
                            dx, dy, ox, oy);
 
+            if (colors == 0) {
+                gdImageSaveAlpha(dst, 1);
+                gdImageAlphaBlending(dst, 0);
+            }
+
             gdImageCopy(dst, src, 0, 0, ox, oy, dx - ox, dy - oy);
 
+            if (colors) {
+                gdImageTrueColorToPalette(dst, 1, 256);
+            }
+
             gdImageDestroy(src);
         }
     }
@@ -1021,6 +1061,7 @@ ngx_http_image_filter_create_conf(ngx_co
 
     conf->filter = NGX_CONF_UNSET_UINT;
     conf->jpeg_quality = NGX_CONF_UNSET;
+    conf->transparency = NGX_CONF_UNSET;
     conf->buffer_size = NGX_CONF_UNSET_SIZE;
 
     return conf;
@@ -1050,6 +1091,8 @@ ngx_http_image_filter_merge_conf(ngx_con
     /* 75 is libjpeg default quality */
     ngx_conf_merge_value(conf->jpeg_quality, prev->jpeg_quality, 75);
 
+    ngx_conf_merge_value(conf->transparency, prev->transparency, 1);
+
     ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size,
                               1 * 1024 * 1024);
 
--- a/src/http/modules/ngx_http_ssl_module.c
+++ b/src/http/modules/ngx_http_ssl_module.c
@@ -406,9 +406,10 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t *
                                                ngx_http_ssl_servername)
         == 0)
     {
-        ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
-                      "SSL_CTX_set_tlsext_servername_callback() failed");
-        return NGX_CONF_ERROR;
+        ngx_log_error(NGX_LOG_WARN, cf->log, 0,
+            "nginx was build with SNI support, however, now it is linked "
+            "dynamically to an OpenSSL library which has no tlsext support, "
+            "therefore SNI is not available");
     }
 
 #endif
--- 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.8.15';
+our $VERSION = '0.8.16';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/modules/perl/ngx_http_perl_module.c
+++ b/src/http/modules/perl/ngx_http_perl_module.c
@@ -761,7 +761,10 @@ ngx_http_perl_eval_anon_sub(pTHX_ ngx_st
         }
     }
 
-    if (ngx_strncmp(p, "sub ", 4) == 0 || ngx_strncmp(p, "use ", 4) == 0) {
+    if (ngx_strncmp(p, "sub ", 4) == 0
+        || ngx_strncmp(p, "sub{", 4) == 0
+        || ngx_strncmp(p, "use ", 4) == 0)
+    {
         *sv = eval_pv((char *) p, FALSE);
 
         /* eval_pv() does not set ERRSV on failure */
--- a/src/http/ngx_http_file_cache.c
+++ b/src/http/ngx_http_file_cache.c
@@ -767,6 +767,7 @@ ngx_http_file_cache_update(ngx_http_requ
 ngx_int_t
 ngx_http_cache_send(ngx_http_request_t *r)
 {
+    off_t              size;
     ngx_int_t          rc;
     ngx_buf_t         *b;
     ngx_chain_t        out;
@@ -795,10 +796,15 @@ ngx_http_cache_send(ngx_http_request_t *
         return rc;
     }
 
+    size = c->length - c->body_start;
+    if (size == 0) {
+        return rc;
+    }
+
     b->file_pos = c->body_start;
     b->file_last = c->length;
 
-    b->in_file = (c->length - c->body_start) ? 1: 0;
+    b->in_file = size ? 1: 0;
     b->last_buf = (r == r->main) ? 1: 0;
     b->last_in_chain = 1;
 
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -2820,6 +2820,8 @@ ngx_http_post_action(ngx_http_request_t 
     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                    "post action: \"%V\"", &clcf->post_action);
 
+    r->main->count--;
+
     r->http_version = NGX_HTTP_VERSION_9;
     r->header_only = 1;
     r->post_action = 1;
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -25,6 +25,8 @@ static ngx_int_t ngx_http_variable_unkno
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_request_line(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
     ngx_http_variable_value_t *v, uintptr_t data);
 static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
@@ -164,8 +166,7 @@ static ngx_http_variable_t  ngx_http_cor
       offsetof(ngx_http_request_t, uri),
       NGX_HTTP_VAR_NOCACHEABLE, 0 },
 
-    { ngx_string("request"), NULL, ngx_http_variable_request,
-      offsetof(ngx_http_request_t, request_line), 0, 0 },
+    { ngx_string("request"), NULL, ngx_http_variable_request_line, 0, 0, 0 },
 
     { ngx_string("document_root"), NULL,
       ngx_http_variable_document_root, 0, NGX_HTTP_VAR_NOCACHEABLE, 0 },
@@ -751,6 +752,42 @@ ngx_http_variable_unknown_header(ngx_htt
 
 
 static ngx_int_t
+ngx_http_variable_request_line(ngx_http_request_t *r,
+    ngx_http_variable_value_t *v, uintptr_t data)
+{
+    u_char  *p, *s;
+
+    s = r->request_line.data;
+
+    if (s == NULL) {
+        s = r->request_start;
+
+        if (s == NULL) {
+            v->not_found = 1;
+            return NGX_OK;
+        }
+
+        for (p = s; p < r->header_in->last; p++) {
+            if (*p == CR || *p == LF) {
+                break;
+            }
+        }
+
+        r->request_line.len = p - s;
+        r->request_line.data = s;
+    }
+
+    v->len = r->request_line.len;
+    v->valid = 1;
+    v->no_cacheable = 0;
+    v->not_found = 0;
+    v->data = s;
+
+    return NGX_OK;
+}
+
+
+static ngx_int_t
 ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
     uintptr_t data)
 {