# HG changeset patch # User Igor Sysoev # Date 1322424000 -14400 # Node ID 4d05413aebad279d486d0dcfa284827c070f1614 # Parent c5b99ec117cde7984bdc8102e72b047bf4adeeeb 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. diff --git a/CHANGES b/CHANGES --- 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 diff --git a/CHANGES.ru b/CHANGES.ru --- 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 переименован в diff --git a/auto/install b/auto/install --- 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 diff --git a/auto/unix b/auto/unix --- 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 ' +ngx_feature_incs='#include + #include ' 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 diff --git a/conf/mime.types b/conf/mime.types --- 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; diff --git a/src/core/nginx.c b/src/core/nginx.c --- 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) { 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 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" diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- 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; } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- 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); diff --git a/src/core/ngx_shmtx.c b/src/core/ngx_shmtx.c --- 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 diff --git a/src/core/ngx_shmtx.h b/src/core/ngx_shmtx.h --- 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_ */ diff --git a/src/core/ngx_slab.h b/src/core/ngx_slab.h --- 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; diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- 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("&") - 2; break; + case '"': + len += sizeof(""") - 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; diff --git a/src/event/modules/ngx_epoll_module.c b/src/event/modules/ngx_epoll_module.c --- 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) { diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- 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; diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- 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 = { diff --git a/src/http/modules/ngx_http_headers_filter_module.c b/src/http/modules/ngx_http_headers_filter_module.c --- 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)) diff --git a/src/http/modules/ngx_http_image_filter_module.c b/src/http/modules/ngx_http_image_filter_module.c --- 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; } diff --git a/src/http/modules/ngx_http_mp4_module.c b/src/http/modules/ngx_http_mp4_module.c --- 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); diff --git a/src/http/modules/ngx_http_scgi_module.c b/src/http/modules/ngx_http_scgi_module.c --- 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); } } 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 @@ -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); 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 @@ -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; 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 @@ -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; 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 @@ -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; } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- 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); diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- 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) diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- 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); + } } }