changeset 650:4d05413aebad NGINX_1_1_9

nginx 1.1.9 *) Change: now double quotes are encoded in an "echo" SSI-command output. Thanks to Zaur Abasmirzoev. *) Feature: the "valid" parameter of the "resolver" directive. By default TTL returned by a DNS server is used. Thanks to Kirill A. Korinskiy. *) Bugfix: nginx might hang after a worker process abnormal termination. *) Bugfix: a segmentation fault might occur in a worker process if SNI was used; the bug had appeared in 1.1.2. *) Bugfix: in the "keepalive_disable" directive; the bug had appeared in 1.1.8. Thanks to Alexander Usov. *) Bugfix: SIGWINCH signal did not work after first binary upgrade; the bug had appeared in 1.1.1. *) Bugfix: backend responses with length not matching "Content-Length" header line are no longer cached. *) Bugfix: in the "scgi_param" directive, if complex parameters were used. *) Bugfix: in the "epoll" event method. Thanks to Yichun Zhang. *) Bugfix: in the ngx_http_flv_module. Thanks to Piotr Sikora. *) Bugfix: in the ngx_http_mp4_module. *) Bugfix: IPv6 addresses are now handled properly in a request line and in a "Host" request header line. *) Bugfix: "add_header" and "expires" directives did not work if a request was proxied and response status code was 206. *) Bugfix: nginx could not be built on FreeBSD 10. *) Bugfix: nginx could not be built on AIX.
author Igor Sysoev <http://sysoev.ru>
date Mon, 28 Nov 2011 00:00:00 +0400
parents c5b99ec117cd
children 583a3cd2773c
files CHANGES CHANGES.ru auto/install auto/unix conf/mime.types src/core/nginx.c src/core/nginx.h src/core/ngx_cycle.c src/core/ngx_resolver.c src/core/ngx_shmtx.c src/core/ngx_shmtx.h src/core/ngx_slab.h src/core/ngx_string.c src/event/modules/ngx_epoll_module.c src/event/ngx_event.c src/http/modules/ngx_http_flv_module.c src/http/modules/ngx_http_headers_filter_module.c src/http/modules/ngx_http_image_filter_module.c src/http/modules/ngx_http_mp4_module.c src/http/modules/ngx_http_scgi_module.c src/http/modules/perl/nginx.pm src/http/ngx_http_core_module.c src/http/ngx_http_parse.c src/http/ngx_http_request.c src/http/ngx_http_upstream.c src/os/unix/ngx_files.c src/os/unix/ngx_process.c
diffstat 27 files changed, 484 insertions(+), 137 deletions(-) [+]
line wrap: on
line diff
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,51 @@
 
+Changes with nginx 1.1.9                                         28 Nov 2011
+
+    *) Change: now double quotes are encoded in an "echo" SSI-command
+       output.
+       Thanks to Zaur Abasmirzoev.
+
+    *) Feature: the "valid" parameter of the "resolver" directive. By
+       default TTL returned by a DNS server is used.
+       Thanks to Kirill A. Korinskiy.
+
+    *) Bugfix: nginx might hang after a worker process abnormal termination.
+
+    *) Bugfix: a segmentation fault might occur in a worker process if SNI
+       was used; the bug had appeared in 1.1.2.
+
+    *) Bugfix: in the "keepalive_disable" directive; the bug had appeared in
+       1.1.8.
+       Thanks to Alexander Usov.
+
+    *) Bugfix: SIGWINCH signal did not work after first binary upgrade; the
+       bug had appeared in 1.1.1.
+
+    *) Bugfix: backend responses with length not matching "Content-Length"
+       header line are no longer cached.
+
+    *) Bugfix: in the "scgi_param" directive, if complex parameters were
+       used.
+
+    *) Bugfix: in the "epoll" event method.
+       Thanks to Yichun Zhang.
+
+    *) Bugfix: in the ngx_http_flv_module.
+       Thanks to Piotr Sikora.
+
+    *) Bugfix: in the ngx_http_mp4_module.
+
+    *) Bugfix: IPv6 addresses are now handled properly in a request line and
+       in a "Host" request header line.
+
+    *) Bugfix: "add_header" and "expires" directives did not work if a
+       request was proxied and response status code was 206.
+
+    *) Bugfix: nginx could not be built on FreeBSD 10.
+
+    *) Bugfix: nginx could not be built on AIX.
+
+
 Changes with nginx 1.1.8                                         14 Nov 2011
 
     *) Change: the ngx_http_limit_zone_module was renamed to the
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,51 @@
 
+Изменения в nginx 1.1.9                                           28.11.2011
+
+    *) Изменение: теперь двойные кавычки экранируется при выводе
+       SSI-командой echo.
+       Спасибо Зауру Абасмирзоеву.
+
+    *) Добавление: параметр valid в директиве resolver. По умолчанию теперь
+       используется TTL, возвращённый DNS-сервером.
+       Спасибо Кириллу Коринскому.
+
+    *) Исправление: nginx мог перестать отвечать, если рабочий процесс
+       завершался аварийно.
+
+    *) Исправление: в рабочем процессе мог произойти segmentation fault,
+       если использовалось SNI; ошибка появилась в 1.1.2.
+
+    *) Исправление: в директиве keepalive_disable; ошибка появилась в 1.1.8.
+       Спасибо Александру Усову.
+
+    *) Исправление: сигнал SIGWINCH переставал работать после первого
+       обновления исполняемого файла; ошибка появилась в 1.1.1.
+
+    *) Исправление: теперь ответы бэкендов, длина которых не соответствует
+       заголовку Content-Length, не кэширутся.
+
+    *) Исправление: в директиве scgi_param при использовании составных
+       параметров.
+
+    *) Исправление: в методе epoll.
+       Спасибо Yichun Zhang.
+
+    *) Исправление: в модуле ngx_http_flv_module.
+       Спасибо Piotr Sikora.
+
+    *) Исправление: в модуле ngx_http_mp4_module.
+
+    *) Исправление: теперь nginx понимает IPv6-адреса в строке запроса и в
+       заголовке Host.
+
+    *) Исправление: директивы add_header и expires не работали для ответов с
+       кодом 206, если запрос проксировался.
+
+    *) Исправление: nginx не собирался на FreeBSD 10.
+
+    *) Исправление: nginx не собирался на AIX.
+
+
 Изменения в nginx 1.1.8                                           14.11.2011
 
     *) Изменение: модуль ngx_http_limit_zone_module переименован в
--- a/auto/install
+++ b/auto/install
@@ -72,16 +72,28 @@ case ".$NGX_HTTP_LOG_PATH" in
 esac
 
 
+if test -e man/nginx.8 ; then
+    NGX_MAN=man/nginx.8
+else
+    NGX_MAN=docs/man/nginx.8
+fi
+
+if test -d html ; then
+    NGX_HTML=html
+else
+    NGX_HTML=docs/html
+fi
+
 cat << END                                                    >> $NGX_MAKEFILE
 
 manpage:	$NGX_OBJS/nginx.8
 
-$NGX_OBJS/nginx.8:	man/nginx.8 $NGX_AUTO_CONFIG_H
+$NGX_OBJS/nginx.8:	$NGX_MAN $NGX_AUTO_CONFIG_H
 	sed -e "s|%%PREFIX%%|$NGX_PREFIX|" \\
 		-e "s|%%PID_PATH%%|$NGX_PID_PATH|" \\
 		-e "s|%%CONF_PATH%%|$NGX_CONF_PATH|" \\
 		-e "s|%%ERROR_LOG_PATH%%|${NGX_ERROR_LOG_PATH:-stderr}|" \\
-		< man/nginx.8 > $NGX_OBJS/nginx.8
+		< $NGX_MAN > \$@
 
 install:	$NGX_OBJS${ngx_dirsep}nginx${ngx_binext} \
 		$NGX_INSTALL_PERL_MODULES
@@ -135,7 +147,7 @@ install:	$NGX_OBJS${ngx_dirsep}nginx${ng
 		mkdir -p '\$(DESTDIR)`dirname "$NGX_HTTP_LOG_PATH"`'
 
 	test -d '\$(DESTDIR)$NGX_PREFIX/html' \
-		|| cp -r html '\$(DESTDIR)$NGX_PREFIX'
+		|| cp -R $NGX_HTML '\$(DESTDIR)$NGX_PREFIX'
 END
 
 
--- a/auto/unix
+++ b/auto/unix
@@ -496,7 +496,8 @@ ngx_feature_test="char buf[1]; ssize_t n
 ngx_feature="sys_nerr"
 ngx_feature_name="NGX_SYS_NERR"
 ngx_feature_run=value
-ngx_feature_incs='#include <stdio.h>'
+ngx_feature_incs='#include <errno.h>
+                  #include <stdio.h>'
 ngx_feature_path=
 ngx_feature_libs=
 ngx_feature_test='printf("%d", sys_nerr);'
@@ -538,10 +539,10 @@ if [ $ngx_found = no ]; then
                               || p == NULL
                               || strncmp(p, "Unknown error", 13) == 0)
                           {
-                              printf("%d", n);
-                              return 0;
+                              break;
                           }
-                     }'
+                      }
+                      printf("%d", n);'
     . auto/feature
 fi
 
--- a/conf/mime.types
+++ b/conf/mime.types
@@ -21,7 +21,7 @@ types {
     image/x-icon                          ico;
     image/x-jng                           jng;
     image/x-ms-bmp                        bmp;
-    image/svg+xml                         svg;
+    image/svg+xml                         svg svgz;
     image/webp                            webp;
 
     application/java-archive              jar war ear;
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -374,6 +374,10 @@ main(int argc, char *const *argv)
         ngx_daemonized = 1;
     }
 
+    if (ngx_inherited) {
+        ngx_daemonized = 1;
+    }
+
 #endif
 
     if (ngx_create_pidfile(&ccf->pid, cycle->log) != NGX_OK) {
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,8 +8,8 @@
 #define _NGINX_H_INCLUDED_
 
 
-#define nginx_version      1001008
-#define NGINX_VERSION      "1.1.8"
+#define nginx_version      1001009
+#define NGINX_VERSION      "1.1.9"
 #define NGINX_VER          "nginx/" NGINX_VERSION
 
 #define NGINX_VAR          "NGINX"
--- a/src/core/ngx_cycle.c
+++ b/src/core/ngx_cycle.c
@@ -952,7 +952,7 @@ ngx_init_zone_pool(ngx_cycle_t *cycle, n
 
 #endif
 
-    if (ngx_shmtx_create(&sp->mutex, (void *) &sp->lock, file) != NGX_OK) {
+    if (ngx_shmtx_create(&sp->mutex, &sp->lock, file) != NGX_OK) {
         return NGX_ERROR;
     }
 
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -93,6 +93,7 @@ static u_char *ngx_resolver_log_error(ng
 ngx_resolver_t *
 ngx_resolver_create(ngx_conf_t *cf, ngx_str_t *names, ngx_uint_t n)
 {
+    ngx_str_t              s;
     ngx_url_t              u;
     ngx_uint_t             i;
     ngx_resolver_t        *r;
@@ -146,12 +147,27 @@ ngx_resolver_create(ngx_conf_t *cf, ngx_
 
     r->resend_timeout = 5;
     r->expire = 30;
-    r->valid = 300;
+    r->valid = 0;
 
     r->log = &cf->cycle->new_log;
     r->log_level = NGX_LOG_ERR;
 
     for (i = 0; i < n; i++) {
+        if (ngx_strncmp(names[i].data, "valid=", 6) == 0) {
+            s.len = names[i].len - 6;
+            s.data = names[i].data + 6;
+
+            r->valid = ngx_parse_time(&s, 1);
+
+            if (r->valid == NGX_ERROR) {
+                ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
+                                   "invalid parameter: %V", &names[i]);
+                return NULL;
+            }
+
+            continue;
+        }
+
         ngx_memzero(&u, sizeof(ngx_url_t));
 
         u.host = names[i];
@@ -1149,6 +1165,7 @@ ngx_resolver_process_a(ngx_resolver_t *r
     char                 *err;
     u_char               *cname;
     size_t                len;
+    int32_t               ttl;
     uint32_t              hash;
     in_addr_t             addr, *addrs;
     ngx_str_t             name;
@@ -1219,6 +1236,7 @@ ngx_resolver_process_a(ngx_resolver_t *r
     addrs = NULL;
     cname = NULL;
     qtype = 0;
+    ttl = 0;
 
     for (a = 0; a < nan; a++) {
 
@@ -1258,6 +1276,12 @@ ngx_resolver_process_a(ngx_resolver_t *r
 
         qtype = (an->type_hi << 8) + an->type_lo;
         len = (an->len_hi << 8) + an->len_lo;
+        ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+            + (an->ttl[2] << 8) + (an->ttl[3]);
+
+        if (ttl < 0) {
+            ttl = 0;
+        }
 
         if (qtype == NGX_RESOLVE_A) {
 
@@ -1287,8 +1311,9 @@ ngx_resolver_process_a(ngx_resolver_t *r
         }
     }
 
-    ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0,
-                   "resolver naddrs:%ui cname:%p", naddrs, cname);
+    ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
+                   "resolver naddrs:%ui cname:%p ttl:%d",
+                   naddrs, cname, ttl);
 
     if (naddrs) {
 
@@ -1357,7 +1382,7 @@ ngx_resolver_process_a(ngx_resolver_t *r
 
         ngx_queue_remove(&rn->queue);
 
-        rn->valid = ngx_time() + r->valid;
+        rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
         rn->expire = ngx_time() + r->expire;
 
         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1399,7 +1424,8 @@ ngx_resolver_process_a(ngx_resolver_t *r
 
         rn->cnlen = (u_short) name.len;
         rn->u.cname = name.data;
-        rn->valid = ngx_time() + r->valid;
+
+        rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
         rn->expire = ngx_time() + r->expire;
 
         ngx_queue_insert_head(&r->name_expire_queue, &rn->queue);
@@ -1450,6 +1476,7 @@ ngx_resolver_process_ptr(ngx_resolver_t 
     char                 *err;
     size_t                len;
     in_addr_t             addr;
+    int32_t               ttl;
     ngx_int_t             digit;
     ngx_str_t             name;
     ngx_uint_t            i, mask, qident;
@@ -1545,6 +1572,12 @@ ngx_resolver_process_ptr(ngx_resolver_t 
     an = (ngx_resolver_an_t *) &buf[i + 2];
 
     len = (an->len_hi << 8) + an->len_lo;
+    ttl = (an->ttl[0] << 24) + (an->ttl[1] << 16)
+        + (an->ttl[2] << 8) + (an->ttl[3]);
+
+    if (ttl < 0) {
+        ttl = 0;
+    }
 
     ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0,
                   "resolver qt:%ui cl:%ui len:%uz",
@@ -1581,7 +1614,7 @@ ngx_resolver_process_ptr(ngx_resolver_t 
 
     ngx_queue_remove(&rn->queue);
 
-    rn->valid = ngx_time() + r->valid;
+    rn->valid = ngx_time() + (r->valid ? r->valid : ttl);
     rn->expire = ngx_time() + r->expire;
 
     ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
--- a/src/core/ngx_shmtx.c
+++ b/src/core/ngx_shmtx.c
@@ -11,10 +11,13 @@
 #if (NGX_HAVE_ATOMIC_OPS)
 
 
+static void ngx_shmtx_wakeup(ngx_shmtx_t *mtx);
+
+
 ngx_int_t
-ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name)
+ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
 {
-    mtx->lock = addr;
+    mtx->lock = &addr->lock;
 
     if (mtx->spin == (ngx_uint_t) -1) {
         return NGX_OK;
@@ -24,6 +27,8 @@ ngx_shmtx_create(ngx_shmtx_t *mtx, void 
 
 #if (NGX_HAVE_POSIX_SEM)
 
+    mtx->wait = &addr->wait;
+
     if (sem_init(&mtx->sem, 1, 0) == -1) {
         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
                       "sem_init() failed");
@@ -56,12 +61,7 @@ ngx_shmtx_destory(ngx_shmtx_t *mtx)
 ngx_uint_t
 ngx_shmtx_trylock(ngx_shmtx_t *mtx)
 {
-    ngx_atomic_uint_t  val;
-
-    val = *mtx->lock;
-
-    return ((val & 0x80000000) == 0
-            && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000));
+    return (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid));
 }
 
 
@@ -69,17 +69,12 @@ void
 ngx_shmtx_lock(ngx_shmtx_t *mtx)
 {
     ngx_uint_t         i, n;
-    ngx_atomic_uint_t  val;
 
     ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx lock");
 
     for ( ;; ) {
 
-        val = *mtx->lock;
-
-        if ((val & 0x80000000) == 0
-            && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
-        {
+        if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
             return;
         }
 
@@ -91,10 +86,8 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
                     ngx_cpu_pause();
                 }
 
-                val = *mtx->lock;
-
-                if ((val & 0x80000000) == 0
-                    && ngx_atomic_cmp_set(mtx->lock, val, val | 0x80000000))
+                if (*mtx->lock == 0
+                    && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid))
                 {
                     return;
                 }
@@ -104,24 +97,24 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
 #if (NGX_HAVE_POSIX_SEM)
 
         if (mtx->semaphore) {
-            val = *mtx->lock;
+            (void) ngx_atomic_fetch_add(mtx->wait, 1);
 
-            if ((val & 0x80000000)
-                && ngx_atomic_cmp_set(mtx->lock, val, val + 1))
-            {
-                ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
-                               "shmtx wait %XA", val);
+            if (*mtx->lock == 0 && ngx_atomic_cmp_set(mtx->lock, 0, ngx_pid)) {
+                return;
+            }
+
+            ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+                           "shmtx wait %uA", *mtx->wait);
 
-                while (sem_wait(&mtx->sem) == -1) {
-                    ngx_err_t  err;
+            while (sem_wait(&mtx->sem) == -1) {
+                ngx_err_t  err;
 
-                    err = ngx_errno;
+                err = ngx_errno;
 
-                    if (err != NGX_EINTR) {
-                        ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
-                                   "sem_wait() failed while waiting on shmtx");
-                        break;
-                    }
+                if (err != NGX_EINTR) {
+                    ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, err,
+                                  "sem_wait() failed while waiting on shmtx");
+                    break;
                 }
 
                 ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
@@ -141,31 +134,56 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
 void
 ngx_shmtx_unlock(ngx_shmtx_t *mtx)
 {
-    ngx_atomic_uint_t  val, old, wait;
-
     if (mtx->spin != (ngx_uint_t) -1) {
         ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0, "shmtx unlock");
     }
 
+    if (ngx_atomic_cmp_set(mtx->lock, ngx_pid, 0)) {
+        ngx_shmtx_wakeup(mtx);
+    }
+}
+
+
+ngx_uint_t
+ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
+{
+    ngx_log_debug0(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
+                   "shmtx forced unlock");
+
+    if (ngx_atomic_cmp_set(mtx->lock, pid, 0)) {
+        ngx_shmtx_wakeup(mtx);
+        return 1;
+    }
+
+    return 0;
+}
+
+
+static void
+ngx_shmtx_wakeup(ngx_shmtx_t *mtx)
+{
+#if (NGX_HAVE_POSIX_SEM)
+    ngx_atomic_uint_t  wait;
+
+    if (!mtx->semaphore) {
+        return;
+    }
+
     for ( ;; ) {
 
-        old = *mtx->lock;
-        wait = old & 0x7fffffff;
-        val = wait ? wait - 1 : 0;
+        wait = *mtx->wait;
 
-        if (ngx_atomic_cmp_set(mtx->lock, old, val)) {
+        if (wait == 0) {
+            return;
+        }
+
+        if (ngx_atomic_cmp_set(mtx->wait, wait, wait - 1)) {
             break;
         }
     }
 
-#if (NGX_HAVE_POSIX_SEM)
-
-    if (wait == 0 || !mtx->semaphore) {
-        return;
-    }
-
     ngx_log_debug1(NGX_LOG_DEBUG_CORE, ngx_cycle->log, 0,
-                   "shmtx wake %XA", old);
+                   "shmtx wake %uA", wait);
 
     if (sem_post(&mtx->sem) == -1) {
         ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, ngx_errno,
@@ -180,7 +198,7 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx)
 
 
 ngx_int_t
-ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name)
+ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr, u_char *name)
 {
     if (mtx->name) {
 
@@ -280,4 +298,11 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx)
     ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
 }
 
+
+ngx_uint_t
+ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid)
+{
+    return 0;
+}
+
 #endif
--- a/src/core/ngx_shmtx.h
+++ b/src/core/ngx_shmtx.h
@@ -13,9 +13,18 @@
 
 
 typedef struct {
+    ngx_atomic_t   lock;
+#if (NGX_HAVE_POSIX_SEM)
+    ngx_atomic_t   wait;
+#endif
+} ngx_shmtx_sh_t;
+
+
+typedef struct {
 #if (NGX_HAVE_ATOMIC_OPS)
     ngx_atomic_t  *lock;
 #if (NGX_HAVE_POSIX_SEM)
+    ngx_atomic_t  *wait;
     ngx_uint_t     semaphore;
     sem_t          sem;
 #endif
@@ -27,11 +36,13 @@ typedef struct {
 } ngx_shmtx_t;
 
 
-ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, void *addr, u_char *name);
+ngx_int_t ngx_shmtx_create(ngx_shmtx_t *mtx, ngx_shmtx_sh_t *addr,
+    u_char *name);
 void ngx_shmtx_destory(ngx_shmtx_t *mtx);
 ngx_uint_t ngx_shmtx_trylock(ngx_shmtx_t *mtx);
 void ngx_shmtx_lock(ngx_shmtx_t *mtx);
 void ngx_shmtx_unlock(ngx_shmtx_t *mtx);
+ngx_uint_t ngx_shmtx_force_unlock(ngx_shmtx_t *mtx, ngx_pid_t pid);
 
 
 #endif /* _NGX_SHMTX_H_INCLUDED_ */
--- a/src/core/ngx_slab.h
+++ b/src/core/ngx_slab.h
@@ -22,7 +22,7 @@ struct ngx_slab_page_s {
 
 
 typedef struct {
-    ngx_atomic_t      lock;
+    ngx_shmtx_sh_t    lock;
 
     size_t            min_size;
     size_t            min_shift;
--- a/src/core/ngx_string.c
+++ b/src/core/ngx_string.c
@@ -1657,6 +1657,10 @@ ngx_escape_html(u_char *dst, u_char *src
                 len += sizeof("&amp;") - 2;
                 break;
 
+            case '"':
+                len += sizeof("&quot;") - 2;
+                break;
+
             default:
                 break;
             }
@@ -1684,6 +1688,11 @@ ngx_escape_html(u_char *dst, u_char *src
             *dst++ = ';';
             break;
 
+        case '"':
+            *dst++ = '&'; *dst++ = 'q'; *dst++ = 'u'; *dst++ = 'o';
+            *dst++ = 't'; *dst++ = ';';
+            break;
+
         default:
             *dst++ = ch;
             break;
--- a/src/event/modules/ngx_epoll_module.c
+++ b/src/event/modules/ngx_epoll_module.c
@@ -681,6 +681,18 @@ ngx_epoll_process_events(ngx_cycle_t *cy
 
         wev = c->write;
 
+        if (c->fd == -1 || wev->instance != instance) {
+
+            /*
+             * the stale event from a file descriptor
+             * that was just closed in this iteration
+             */
+
+            ngx_log_debug1(NGX_LOG_DEBUG_EVENT, cycle->log, 0,
+                           "epoll: stale event %p", c);
+            continue;
+        }
+
         if ((revents & EPOLLOUT) && wev->active) {
 
             if (flags & NGX_POST_THREAD_EVENTS) {
--- a/src/event/ngx_event.c
+++ b/src/event/ngx_event.c
@@ -521,7 +521,8 @@ ngx_event_module_init(ngx_cycle_t *cycle
     ngx_accept_mutex_ptr = (ngx_atomic_t *) shared;
     ngx_accept_mutex.spin = (ngx_uint_t) -1;
 
-    if (ngx_shmtx_create(&ngx_accept_mutex, shared, cycle->lock_file.data)
+    if (ngx_shmtx_create(&ngx_accept_mutex, (ngx_shmtx_sh_t *) shared,
+                         cycle->lock_file.data)
         != NGX_OK)
     {
         return NGX_ERROR;
--- a/src/http/modules/ngx_http_flv_module.c
+++ b/src/http/modules/ngx_http_flv_module.c
@@ -23,7 +23,7 @@ static ngx_command_t  ngx_http_flv_comma
 };
 
 
-static u_char  ngx_flv_header[] = "FLV\x1\x1\0\0\0\x9\0\0\0\x9";
+static u_char  ngx_flv_header[] = "FLV\x1\x5\0\0\0\x9\0\0\0\0";
 
 
 static ngx_http_module_t  ngx_http_flv_module_ctx = {
--- a/src/http/modules/ngx_http_headers_filter_module.c
+++ b/src/http/modules/ngx_http_headers_filter_module.c
@@ -145,6 +145,7 @@ ngx_http_headers_filter(ngx_http_request
         || r != r->main
         || (r->headers_out.status != NGX_HTTP_OK
             && r->headers_out.status != NGX_HTTP_NO_CONTENT
+            && r->headers_out.status != NGX_HTTP_PARTIAL_CONTENT
             && r->headers_out.status != NGX_HTTP_MOVED_PERMANENTLY
             && r->headers_out.status != NGX_HTTP_MOVED_TEMPORARILY
             && r->headers_out.status != NGX_HTTP_NOT_MODIFIED))
--- a/src/http/modules/ngx_http_image_filter_module.c
+++ b/src/http/modules/ngx_http_image_filter_module.c
@@ -115,7 +115,7 @@ static ngx_int_t ngx_http_image_filter_i
 static ngx_command_t  ngx_http_image_filter_commands[] = {
 
     { ngx_string("image_filter"),
-      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE13|NGX_CONF_TAKE2,
+      NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
       ngx_http_image_filter,
       NGX_HTTP_LOC_CONF_OFFSET,
       0,
@@ -1262,7 +1262,11 @@ ngx_http_image_filter(ngx_conf_t *cf, ng
     } else if (cf->args->nelts == 3) {
 
         if (ngx_strcmp(value[i].data, "rotate") == 0) {
-            imcf->filter = NGX_HTTP_IMAGE_ROTATE;
+            if (imcf->filter != NGX_HTTP_IMAGE_RESIZE
+                && imcf->filter != NGX_HTTP_IMAGE_CROP)
+            {
+                imcf->filter = NGX_HTTP_IMAGE_ROTATE;
+            }
 
             ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
 
@@ -1405,7 +1409,7 @@ ngx_http_image_filter_jpeg_quality(ngx_c
 
         if (n <= 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid parameter \"%V\"", &value[1]);
+                               "invalid value \"%V\"", &value[1]);
             return NGX_CONF_ERROR;
         }
 
@@ -1452,7 +1456,7 @@ ngx_http_image_filter_sharpen(ngx_conf_t
 
         if (n < 0) {
             ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
-                               "invalid parameter \"%V\"", &value[1]);
+                               "invalid value \"%V\"", &value[1]);
             return NGX_CONF_ERROR;
         }
 
--- a/src/http/modules/ngx_http_mp4_module.c
+++ b/src/http/modules/ngx_http_mp4_module.c
@@ -1899,7 +1899,7 @@ ngx_http_mp4_update_stts_atom(ngx_http_m
         ngx_log_debug2(NGX_LOG_DEBUG_HTTP, mp4->file.log, 0,
                        "count:%uD, duration:%uD", count, duration);
 
-        if (start_time < count * duration) {
+        if (start_time < (uint64_t) count * duration) {
             start_sample += (ngx_uint_t) (start_time / duration);
             count -= start_sample;
             ngx_mp4_set_32value(entry->count, count);
--- a/src/http/modules/ngx_http_scgi_module.c
+++ b/src/http/modules/ngx_http_scgi_module.c
@@ -558,8 +558,10 @@ ngx_http_scgi_create_request(ngx_http_re
 
             while (*(uintptr_t *) le.ip) {
                 lcode = *(ngx_http_script_len_code_pt *) le.ip;
-                len += lcode(&le) + 1;
+                len += lcode(&le);
             }
+            len++;
+
             le.ip += sizeof(uintptr_t);
         }
     }
--- a/src/http/modules/perl/nginx.pm
+++ b/src/http/modules/perl/nginx.pm
@@ -48,7 +48,7 @@ our @EXPORT = qw(
     HTTP_INSUFFICIENT_STORAGE
 );
 
-our $VERSION = '1.1.8';
+our $VERSION = '1.1.9';
 
 require XSLoader;
 XSLoader::load('nginx', $VERSION);
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -3267,12 +3267,12 @@ ngx_http_core_create_loc_conf(ngx_conf_t
      *     clcf->auto_redirect = 0;
      *     clcf->alias = 0;
      *     clcf->gzip_proxied = 0;
+     *     clcf->keepalive_disable = 0;
      */
 
     clcf->client_max_body_size = NGX_CONF_UNSET;
     clcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
     clcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
-    clcf->keepalive_disable = NGX_CONF_UNSET_UINT;
     clcf->satisfy = NGX_CONF_UNSET_UINT;
     clcf->if_modified_since = NGX_CONF_UNSET_UINT;
     clcf->max_ranges = NGX_CONF_UNSET_UINT;
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -110,7 +110,10 @@ ngx_http_parse_request_line(ngx_http_req
         sw_schema,
         sw_schema_slash,
         sw_schema_slash_slash,
+        sw_host_start,
         sw_host,
+        sw_host_end,
+        sw_host_ip_literal,
         sw_port,
         sw_host_http_09,
         sw_after_slash_in_uri,
@@ -323,14 +326,26 @@ ngx_http_parse_request_line(ngx_http_req
         case sw_schema_slash_slash:
             switch (ch) {
             case '/':
-                r->host_start = p + 1;
-                state = sw_host;
+                state = sw_host_start;
                 break;
             default:
                 return NGX_HTTP_PARSE_INVALID_REQUEST;
             }
             break;
 
+        case sw_host_start:
+
+            r->host_start = p;
+
+            if (ch == '[') {
+                state = sw_host_ip_literal;
+                break;
+            }
+
+            state = sw_host;
+
+            /* fall through */
+
         case sw_host:
 
             c = (u_char) (ch | 0x20);
@@ -342,6 +357,10 @@ ngx_http_parse_request_line(ngx_http_req
                 break;
             }
 
+            /* fall through */
+
+        case sw_host_end:
+
             r->host_end = p;
 
             switch (ch) {
@@ -366,6 +385,47 @@ ngx_http_parse_request_line(ngx_http_req
             }
             break;
 
+        case sw_host_ip_literal:
+
+            if (ch >= '0' && ch <= '9') {
+                break;
+            }
+
+            c = (u_char) (ch | 0x20);
+            if (c >= 'a' && c <= 'z') {
+                break;
+            }
+
+            switch (ch) {
+            case ':':
+                break;
+            case ']':
+                state = sw_host_end;
+                break;
+            case '-':
+            case '.':
+            case '_':
+            case '~':
+                /* unreserved */
+                break;
+            case '!':
+            case '$':
+            case '&':
+            case '\'':
+            case '(':
+            case ')':
+            case '*':
+            case '+':
+            case ',':
+            case ';':
+            case '=':
+                /* sub-delims */
+                break;
+            default:
+                return NGX_HTTP_PARSE_INVALID_REQUEST;
+            }
+            break;
+
         case sw_port:
             if (ch >= '0' && ch <= '9') {
                 break;
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -671,25 +671,27 @@ ngx_http_ssl_servername(ngx_ssl_conn_t *
 
     sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module);
 
-    SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx);
-
-    /*
-     * SSL_set_SSL_CTX() only changes certs as of 1.0.0d
-     * adjust other things we care about
-     */
-
-    SSL_set_verify(ssl_conn, SSL_CTX_get_verify_mode(sscf->ssl.ctx),
-                   SSL_CTX_get_verify_callback(sscf->ssl.ctx));
-
-    SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx));
+    if (sscf->ssl.ctx) {
+        SSL_set_SSL_CTX(ssl_conn, sscf->ssl.ctx);
+
+        /*
+         * SSL_set_SSL_CTX() only changes certs as of 1.0.0d
+         * adjust other things we care about
+         */
+
+        SSL_set_verify(ssl_conn, SSL_CTX_get_verify_mode(sscf->ssl.ctx),
+                       SSL_CTX_get_verify_callback(sscf->ssl.ctx));
+
+        SSL_set_verify_depth(ssl_conn, SSL_CTX_get_verify_depth(sscf->ssl.ctx));
 
 #ifdef SSL_CTRL_CLEAR_OPTIONS
-    /* only in 0.9.8m+ */
-    SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) &
-                                ~SSL_CTX_get_options(sscf->ssl.ctx));
+        /* only in 0.9.8m+ */
+        SSL_clear_options(ssl_conn, SSL_get_options(ssl_conn) &
+                                    ~SSL_CTX_get_options(sscf->ssl.ctx));
 #endif
 
-    SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx));
+        SSL_set_options(ssl_conn, SSL_CTX_get_options(sscf->ssl.ctx));
+    }
 
     return SSL_TLSEXT_ERR_OK;
 }
@@ -1672,56 +1674,85 @@ static ssize_t
 ngx_http_validate_host(ngx_http_request_t *r, u_char **host, size_t len,
     ngx_uint_t alloc)
 {
-    u_char      *h, ch;
-    size_t       i, last;
-    ngx_uint_t   dot;
-
-    last = len;
+    u_char  *h, ch;
+    size_t   i, dot_pos, host_len;
+
+    enum {
+        sw_usual = 0,
+        sw_literal,
+        sw_rest
+    } state;
+
+    dot_pos = len;
+    host_len = len;
+
     h = *host;
-    dot = 0;
+
+    state = sw_usual;
 
     for (i = 0; i < len; i++) {
         ch = h[i];
 
-        if (ch == '.') {
-            if (dot) {
+        switch (ch) {
+
+        case '.':
+            if (dot_pos == i - 1) {
                 return 0;
             }
-
-            dot = 1;
-            continue;
-        }
-
-        dot = 0;
-
-        if (ch == ':') {
-            last = i;
-            continue;
-        }
-
-        if (ngx_path_separator(ch) || ch == '\0') {
+            dot_pos = i;
+            break;
+
+        case ':':
+            if (state == sw_usual) {
+                host_len = i;
+                state = sw_rest;
+            }
+            break;
+
+        case '[':
+            if (i == 0) {
+                state = sw_literal;
+            }
+            break;
+
+        case ']':
+            if (state == sw_literal) {
+                host_len = i + 1;
+                state = sw_rest;
+            }
+            break;
+
+        case '\0':
             return 0;
-        }
-
-        if (ch >= 'A' || ch < 'Z') {
-            alloc = 1;
+
+        default:
+
+            if (ngx_path_separator(ch)) {
+                return 0;
+            }
+
+            if (ch >= 'A' && ch <= 'Z') {
+                alloc = 1;
+            }
+
+            break;
         }
     }
 
-    if (dot) {
-        last--;
+    if (dot_pos == host_len - 1) {
+        host_len--;
     }
 
     if (alloc) {
-        *host = ngx_pnalloc(r->pool, last) ;
+        *host = ngx_pnalloc(r->pool, host_len);
         if (*host == NULL) {
             return -1;
         }
 
-        ngx_strlow(*host, h, last);
+        ngx_strlow(*host, h, host_len);
     }
 
-    return last;
+    return host_len;
 }
 
 
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -2696,9 +2696,17 @@ ngx_http_upstream_process_request(ngx_ht
 
             } else if (p->upstream_eof) {
 
-                /* TODO: check length & update cache */
-
-                ngx_http_file_cache_update(r, u->pipe->temp_file);
+                tf = u->pipe->temp_file;
+
+                if (u->headers_in.content_length_n == -1
+                    || u->headers_in.content_length_n
+                       == tf->offset - (off_t) r->cache->body_start)
+                {
+                    ngx_http_file_cache_update(r, tf);
+
+                } else {
+                    ngx_http_file_cache_free(r->cache, tf);
+                }
 
             } else if (p->upstream_error) {
                 ngx_http_file_cache_free(r->cache, u->pipe->temp_file);
--- a/src/os/unix/ngx_files.c
+++ b/src/os/unix/ngx_files.c
@@ -464,7 +464,7 @@ ngx_unlock_fd(ngx_fd_t fd)
 }
 
 
-#if (NGX_HAVE_POSIX_FADVISE)
+#if (NGX_HAVE_POSIX_FADVISE) && !(NGX_HAVE_F_READAHEAD)
 
 ngx_int_t
 ngx_read_ahead(ngx_fd_t fd, size_t n)
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -22,6 +22,7 @@ typedef struct {
 static void ngx_execute_proc(ngx_cycle_t *cycle, void *data);
 static void ngx_signal_handler(int signo);
 static void ngx_process_get_status(void);
+static void ngx_unlock_mutexes(ngx_pid_t pid);
 
 
 int              ngx_argc;
@@ -497,17 +498,6 @@ ngx_process_get_status(void)
         }
 
 
-        if (ngx_accept_mutex_ptr) {
-
-            /*
-             * unlock the accept mutex if the abnormally exited process
-             * held it
-             */
-
-            ngx_atomic_cmp_set(ngx_accept_mutex_ptr, pid, 0);
-        }
-
-
         one = 1;
         process = "unknown process";
 
@@ -545,6 +535,55 @@ ngx_process_get_status(void)
                           process, pid, WEXITSTATUS(status));
             ngx_processes[i].respawn = 0;
         }
+
+        ngx_unlock_mutexes(pid);
+    }
+}
+
+
+static void
+ngx_unlock_mutexes(ngx_pid_t pid)
+{ 
+    ngx_uint_t        i;
+    ngx_shm_zone_t   *shm_zone;
+    ngx_list_part_t  *part;
+    ngx_slab_pool_t  *sp;
+
+    /*
+     * unlock the accept mutex if the abnormally exited process
+     * held it
+     */
+
+    if (ngx_accept_mutex_ptr) {
+        (void) ngx_shmtx_force_unlock(&ngx_accept_mutex, pid);
+    }
+
+    /*
+     * unlock shared memory mutexes if held by the abnormally exited
+     * process
+     */
+
+    part = (ngx_list_part_t *) &ngx_cycle->shared_memory.part;
+    shm_zone = part->elts;
+
+    for (i = 0; /* void */ ; i++) {
+
+        if (i >= part->nelts) {
+            if (part->next == NULL) {
+                break;
+            }
+            part = part->next;
+            shm_zone = part->elts;
+            i = 0;
+        }
+
+        sp = (ngx_slab_pool_t *) shm_zone[i].shm.addr;
+
+        if (ngx_shmtx_force_unlock(&sp->mutex, pid)) {
+            ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+                          "shared memory zone \"%V\" was locked by %P",
+                          &shm_zone[i].shm.name, pid);
+        }
     }
 }