# HG changeset patch # User Igor Sysoev # Date 1209412800 -14400 # Node ID 6639b93e81b2bd6a016b310953215108aad0c379 # Parent b6a2a305fdad3838244e6c8c2ee19ed377862ad8 nginx 0.6.30 *) Change: now if an "include" directive pattern does not match any file, then nginx does not issue an error. *) Feature: now the time in directives may be specified without spaces, for example, "1h50m". *) Bugfix: memory leaks if the "ssl_verify_client" directive was on. Thanks to Chavelle Vincent. *) Bugfix: the "sub_filter" directive might set text to change into output. *) Bugfix: the "error_page" directive did not take into account arguments in redirected URI. *) Bugfix: now nginx always opens files in binary mode under Cygwin. *) Bugfix: nginx could not be built on OpenBSD; bug appeared in 0.6.15. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,15 +1,37 @@ +Changes with nginx 0.6.30 29 Apr 2008 + + *) Change: now if an "include" directive pattern does not match any + file, then nginx does not issue an error. + + *) Feature: now the time in directives may be specified without spaces, + for example, "1h50m". + + *) Bugfix: memory leaks if the "ssl_verify_client" directive was on. + Thanks to Chavelle Vincent. + + *) Bugfix: the "sub_filter" directive might set text to change into + output. + + *) Bugfix: the "error_page" directive did not take into account + arguments in redirected URI. + + *) Bugfix: now nginx always opens files in binary mode under Cygwin. + + *) Bugfix: nginx could not be built on OpenBSD; bug appeared in 0.6.15. + + Changes with nginx 0.6.29 18 Mar 2008 *) Feature: the ngx_google_perftools_module. - *) Bugfix: the ngx_http_perl_module could be not built on 64-bit + *) Bugfix: the ngx_http_perl_module could not be built on 64-bit platforms; bug appeared in 0.6.27. Changes with nginx 0.6.28 13 Mar 2008 - *) Bugfix: the rtsig method could be not built; bug appeared in 0.6.27. + *) Bugfix: the rtsig method could not be built; bug appeared in 0.6.27. Changes with nginx 0.6.27 12 Mar 2008 @@ -665,7 +687,8 @@ Changes with nginx 0.5.20 Studio. Thanks to Andrei Nigmatulin. - *) Bugfix: the ngx_http_perl_module could not built by Solaris make. + *) Bugfix: the ngx_http_perl_module could not be built by Solaris + make. Thanks to Andrei Nigmatulin. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,29 @@ +Изменения в nginx 0.6.30 29.04.2008 + + *) Изменение: теперь, если маске, заданной в директиве include, не + соответствует ни один файл, то nginx не выдаёт ошибку. + + *) Добавление: теперь время в директивах можно задавать без пробела, + например, "1h50m". + + *) Исправление: утечек памяти, если директива ssl_verify_client имела + значение on. + Спасибо Chavelle Vincent. + + *) Исправление: директива sub_filter могла вставлять заменяемый текст в + вывод. + + *) Исправление: директива error_page не воспринимала параметры в + перенаправляемом URI. + + *) Исправление: теперь при сборке с Cygwin nginx всегда открывает файлы + в бинарном режиме. + + *) Исправление: nginx не собирался под OpenBSD; ошибка появилась в + 0.6.15. + + Изменения в nginx 0.6.29 18.03.2008 *) Добавление: модуль ngx_google_perftools_module. diff --git a/auto/headers b/auto/headers --- a/auto/headers +++ b/auto/headers @@ -7,4 +7,3 @@ ngx_include="inttypes.h"; . auto/includ ngx_include="limits.h"; . auto/include ngx_include="sys/filio.h"; . auto/include ngx_include="crypt.h"; . auto/include -ngx_include="malloc.h"; . auto/include diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -150,8 +150,8 @@ do --without-poll_module) EVENT_POLL=NONE ;; --with-aio_module) EVENT_AIO=YES ;; - --with-threads=*) USE_THREADS="$value" ;; - --with-threads) USE_THREADS="pthreads" ;; + #--with-threads=*) USE_THREADS="$value" ;; + #--with-threads) USE_THREADS="pthreads" ;; --without-http) HTTP=NO ;; --http-log-path=*) NGX_HTTP_LOG_PATH="$value" ;; diff --git a/auto/summary b/auto/summary --- a/auto/summary +++ b/auto/summary @@ -21,15 +21,15 @@ echo echo "Configuration summary" -case $USE_THREADS in - rfork) echo " + using rfork()ed threads" ;; - pthreads) echo " + using libpthread threads library" ;; - libthr) echo " + using FreeBSD libthr threads library" ;; - libc_r) echo " + using FreeBSD libc_r threads library" ;; - linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; - NO) echo " + threads are not used" ;; - *) echo " + using lib$USE_THREADS threads library" ;; -esac +#case $USE_THREADS in +# rfork) echo " + using rfork()ed threads" ;; +# pthreads) echo " + using libpthread threads library" ;; +# libthr) echo " + using FreeBSD libthr threads library" ;; +# libc_r) echo " + using FreeBSD libc_r threads library" ;; +# linuxthreads) echo " + using FreeBSD LinuxThreads port library" ;; +# NO) echo " + threads are not used" ;; +# *) echo " + using lib$USE_THREADS threads library" ;; +#esac if [ $USE_PCRE = DISABLED ]; then echo " + PCRE library is disabled" diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.6.29" +#define NGINX_VERSION "0.6.30" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -645,10 +645,18 @@ ngx_conf_include(ngx_conf_t *cf, ngx_com return NGX_CONF_ERROR; } + if (strpbrk((char *) file.data, "*?[") == NULL) { + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + return ngx_conf_parse(cf, &file); + } + ngx_memzero(&gl, sizeof(ngx_glob_t)); gl.pattern = file.data; gl.log = cf->log; + gl.test = 1; if (ngx_open_glob(&gl) != NGX_OK) { ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno, diff --git a/src/core/ngx_log.h b/src/core/ngx_log.h --- a/src/core/ngx_log.h +++ b/src/core/ngx_log.h @@ -195,9 +195,6 @@ void ngx_cdecl ngx_log_debug_core(ngx_lo /*********************************/ -#define ngx_log_alloc_log(pool, log) ngx_palloc(pool, log, sizeof(ngx_log_t)) -#define ngx_log_copy_log(new, old) ngx_memcpy(new, old, sizeof(ngx_log_t)) - ngx_log_t *ngx_log_init(void); ngx_log_t *ngx_log_create_errlog(ngx_cycle_t *cycle, ngx_array_t *args); char *ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log); diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -433,8 +433,11 @@ ngx_chain_writer(void *data, ngx_chain_t { ngx_chain_writer_ctx_t *ctx = data; - off_t size; - ngx_chain_t *cl; + off_t size; + ngx_chain_t *cl; + ngx_connection_t *c; + + c = ctx->connection; for (size = 0; in; in = in->next) { @@ -446,7 +449,7 @@ ngx_chain_writer(void *data, ngx_chain_t size += ngx_buf_size(in->buf); - ngx_log_debug2(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, + ngx_log_debug2(NGX_LOG_DEBUG_CORE, c->log, 0, "chain writer buf fl:%d s:%uO", in->buf->flush, ngx_buf_size(in->buf)); @@ -461,7 +464,7 @@ ngx_chain_writer(void *data, ngx_chain_t ctx->last = &cl->next; } - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, "chain writer in: %p", ctx->out); for (cl = ctx->out; cl; cl = cl->next) { @@ -476,14 +479,13 @@ ngx_chain_writer(void *data, ngx_chain_t size += ngx_buf_size(cl->buf); } - if (size == 0 && !ctx->connection->buffered) { + if (size == 0 && !c->buffered) { return NGX_OK; } - ctx->out = ctx->connection->send_chain(ctx->connection, ctx->out, - ctx->limit); + ctx->out = c->send_chain(c, ctx->out, ctx->limit); - ngx_log_debug1(NGX_LOG_DEBUG_CORE, ctx->connection->log, 0, + ngx_log_debug1(NGX_LOG_DEBUG_CORE, c->log, 0, "chain writer out: %p", ctx->out); if (ctx->out == NGX_CHAIN_ERROR) { @@ -493,7 +495,7 @@ ngx_chain_writer(void *data, ngx_chain_t if (ctx->out == NULL) { ctx->last = &ctx->out; - if (!ctx->connection->buffered) { + if (!c->buffered) { return NGX_OK; } } diff --git a/src/core/ngx_parse.c b/src/core/ngx_parse.c --- a/src/core/ngx_parse.c +++ b/src/core/ngx_parse.c @@ -11,15 +11,15 @@ ssize_t ngx_parse_size(ngx_str_t *line) { - u_char last; + u_char unit; size_t len; ssize_t size; ngx_int_t scale; len = line->len; - last = line->data[len - 1]; + unit = line->data[len - 1]; - switch (last) { + switch (unit) { case 'K': case 'k': len--; @@ -50,15 +50,15 @@ ngx_parse_size(ngx_str_t *line) off_t ngx_parse_offset(ngx_str_t *line) { - u_char last; + u_char unit; off_t offset; size_t len; ngx_int_t scale; len = line->len; - last = line->data[len - 1]; + unit = line->data[len - 1]; - switch (last) { + switch (unit) { case 'K': case 'k': len--; @@ -93,12 +93,11 @@ ngx_parse_offset(ngx_str_t *line) ngx_int_t -ngx_parse_time(ngx_str_t *line, ngx_int_t sec) +ngx_parse_time(ngx_str_t *line, ngx_uint_t sec) { - size_t len; - u_char *start, last; + u_char *p, *last; ngx_int_t value, total, scale; - ngx_uint_t max, i; + ngx_uint_t max, valid; enum { st_start = 0, st_year, @@ -112,39 +111,30 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ st_last } step; - - start = line->data; - len = 0; + valid = 0; + value = 0; total = 0; step = sec ? st_start : st_month; + scale = sec ? 1 : 1000; - for (i = 0; /* void */ ; i++) { + p = line->data; + last = p + line->len; - if (i < line->len) { - if (line->data[i] != ' ') { - len++; - continue; - } + while (p < last) { - if (line->data[i] == ' ' && len == 0) { - start = &line->data[i + 1]; - continue; - } + if (*p >= '0' && *p <= '9') { + value = value * 10 + (*p++ - '0'); + valid = 1; + continue; } - if (len == 0) { - break; - } + switch (*p++) { - last = line->data[i - 1]; - - switch (last) { case 'y': if (step > st_start) { return NGX_ERROR; } step = st_year; - len--; max = 68; scale = 60 * 60 * 24 * 365; break; @@ -154,7 +144,6 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_month; - len--; max = 828; scale = 60 * 60 * 24 * 30; break; @@ -164,7 +153,6 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_week; - len--; max = 3550; scale = 60 * 60 * 24 * 7; break; @@ -174,7 +162,6 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_day; - len--; max = 24855; scale = 60 * 60 * 24; break; @@ -184,52 +171,49 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ return NGX_ERROR; } step = st_hour; - len--; max = 596523; scale = 60 * 60; break; case 'm': + if (*p == 's') { + if (sec || step > st_sec) { + return NGX_ERROR; + } + p++; + step = st_msec; + max = 2147483647; + scale = 1; + break; + } + if (step > st_hour) { return NGX_ERROR; } step = st_min; - len--; max = 35791394; scale = 60; break; case 's': - len--; - - if (line->data[i - 2] == 'm') { - if (sec || step > st_sec) { - return NGX_ERROR; - } - step = st_msec; - len--; - max = 2147483647; - scale = 1; - break; - } - if (step > st_min) { return NGX_ERROR; } - step = st_sec; max = 2147483647; scale = 1; break; - default: + case ' ': + if (step > st_min) { + return NGX_ERROR; + } step = st_last; max = 2147483647; scale = 1; - } + break; - value = ngx_atoi(start, len); - if (value == NGX_ERROR) { + default: return NGX_ERROR; } @@ -238,23 +222,27 @@ ngx_parse_time(ngx_str_t *line, ngx_int_ max /= 1000; } - if ((u_int) value > max) { - return NGX_PARSE_LARGE_TIME; + if ((ngx_uint_t) value > max) { + return NGX_ERROR; } total += value * scale; - if ((u_int) total > 2147483647) { - return NGX_PARSE_LARGE_TIME; + if ((ngx_uint_t) total > 2147483647) { + return NGX_ERROR; } - if (i >= line->len) { - break; + value = 0; + scale = sec ? 1 : 1000; + + while (p < last && *p == ' ') { + p++; } - - len = 0; - start = &line->data[i + 1]; } - return total; + if (valid) { + return total + value * scale; + } + + return NGX_ERROR; } diff --git a/src/core/ngx_parse.h b/src/core/ngx_parse.h --- a/src/core/ngx_parse.h +++ b/src/core/ngx_parse.h @@ -17,7 +17,7 @@ ssize_t ngx_parse_size(ngx_str_t *line); off_t ngx_parse_offset(ngx_str_t *line); -ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_int_t sec); +ngx_int_t ngx_parse_time(ngx_str_t *line, ngx_uint_t sec); #endif /* _NGX_PARSE_H_INCLUDED_ */ 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 @@ -369,6 +369,7 @@ ngx_resolve_name_locked(ngx_resolver_t * { uint32_t hash; in_addr_t addr, *addrs; + ngx_int_t rc; ngx_uint_t naddrs; ngx_resolver_ctx_t *next; ngx_resolver_node_t *rn; @@ -434,10 +435,29 @@ ngx_resolve_name_locked(ngx_resolver_t * /* NGX_RESOLVE_CNAME */ - ctx->name.len = rn->cnlen; - ctx->name.data = rn->u.cname; - - return ngx_resolve_name_locked(r, ctx); + if (ctx->recursion++ < NGX_RESOLVER_MAX_RECURSION) { + + ctx->name.len = rn->cnlen; + ctx->name.data = rn->u.cname; + + return ngx_resolve_name_locked(r, ctx); + } + + ctx->next = rn->waiting; + rn->waiting = NULL; + + /* unlock name mutex */ + + do { + ctx->state = NGX_RESOLVE_NXDOMAIN; + next = ctx->next; + + ctx->handler(ctx); + + ctx = next; + } while (ctx); + + return NGX_OK; } if (rn->waiting) { @@ -453,6 +473,7 @@ ngx_resolve_name_locked(ngx_resolver_t * /* lock alloc mutex */ ngx_resolver_free_locked(r, rn->query); + rn->query = NULL; if (rn->cnlen) { ngx_resolver_free_locked(r, rn->u.cname); @@ -479,14 +500,30 @@ ngx_resolve_name_locked(ngx_resolver_t * rn->node.key = hash; rn->nlen = (u_short) ctx->name.len; + rn->query = NULL; ngx_rbtree_insert(&r->name_rbtree, &rn->node); } - if (ngx_resolver_create_name_query(rn, ctx) != NGX_OK) { + rc = ngx_resolver_create_name_query(rn, ctx); + + if (rc == NGX_ERROR) { goto failed; } + if (rc == NGX_DECLINED) { + ngx_rbtree_delete(&r->name_rbtree, &rn->node); + + ngx_resolver_free(r, rn->query); + ngx_resolver_free(r, rn->name); + ngx_resolver_free(r, rn); + + ctx->state = NGX_RESOLVE_NXDOMAIN; + ctx->handler(ctx); + + return NGX_OK; + } + if (ngx_resolver_send_query(r, rn) != NGX_OK) { goto failed; } @@ -526,6 +563,10 @@ failed: ngx_rbtree_delete(&r->name_rbtree, &rn->node); + if (rn->query) { + ngx_resolver_free(r, rn->query); + } + ngx_resolver_free(r, rn->name); ngx_resolver_free(r, rn); @@ -588,6 +629,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx ngx_queue_remove(&rn->queue); ngx_resolver_free(r, rn->query); + rn->query = NULL; } else { rn = ngx_resolver_alloc(r, sizeof(ngx_resolver_node_t)); @@ -596,6 +638,7 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx } rn->node.key = ctx->addr; + rn->query = NULL; ngx_rbtree_insert(&r->addr_rbtree, &rn->node); } @@ -646,6 +689,10 @@ failed: if (rn) { ngx_rbtree_delete(&r->addr_rbtree, &rn->node); + if (rn->query) { + ngx_resolver_free(r, rn->query); + } + ngx_resolver_free(r, rn); } @@ -925,14 +972,14 @@ ngx_resolver_process_response(ngx_resolv nan = (query->nan_hi << 8) + query->nan_lo; ngx_log_debug6(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver DNS response %d fl:%04Xud %d/%d/%d/%d", + "resolver DNS response %ui fl:%04Xui %ui/%ui/%ui/%ui", ident, flags, nqs, nan, (query->nns_hi << 8) + query->nns_lo, (query->nar_hi << 8) + query->nar_lo); if (!(flags & 0x8000)) { ngx_log_error(r->log_level, r->log, 0, - "invalid DNS response %d fl:%04Xud", ident, flags); + "invalid DNS response %ui fl:%04Xui", ident, flags); return; } @@ -940,7 +987,7 @@ ngx_resolver_process_response(ngx_resolv if (code == NGX_RESOLVE_FORMERR || code > NGX_RESOLVE_REFUSED) { ngx_log_error(r->log_level, r->log, 0, - "DNS error (%d: %s), query id:%d", + "DNS error (%ui: %s), query id:%ui", code, ngx_resolver_strerror(code), ident); return; } @@ -982,11 +1029,11 @@ found: qclass = (qs->class_hi << 8) + qs->class_lo; ngx_log_debug2(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver DNS response qt:%d cl:%d", qtype, qclass); + "resolver DNS response qt:%ui cl:%ui", qtype, qclass); if (qclass != 1) { ngx_log_error(r->log_level, r->log, 0, - "unknown query class %d in DNS response", qclass); + "unknown query class %ui in DNS response", qclass); return; } @@ -1007,7 +1054,7 @@ found: default: ngx_log_error(r->log_level, r->log, 0, - "unknown query type %d in DNS response", qtype); + "unknown query type %ui in DNS response", qtype); return; } @@ -1062,7 +1109,7 @@ ngx_resolver_process_a(ngx_resolver_t *r if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %d response for %V, expect %d", + "wrong ident %ui response for %V, expect %ui", ident, &name, qident); goto failed; } @@ -1158,6 +1205,13 @@ ngx_resolver_process_a(ngx_resolver_t *r } else if (qtype == NGX_RESOLVE_CNAME) { cname = &buf[i] + sizeof(ngx_resolver_an_t); i += sizeof(ngx_resolver_an_t) + len; + + } else if (qtype == NGX_RESOLVE_DNAME) { + i += sizeof(ngx_resolver_an_t) + len; + + } else { + ngx_log_error(r->log_level, r->log, 0, + "unexpected qtype %ui", qtype); } } @@ -1291,8 +1345,8 @@ ngx_resolver_process_a(ngx_resolver_t *r } ngx_log_error(r->log_level, r->log, 0, - "no A or CNAME types in DNS responses, unknown query type: %d", - qtype); + "no A or CNAME types in DNS responses, unknown query type: %ui", + qtype); return; short_response: @@ -1368,9 +1422,9 @@ ngx_resolver_process_ptr(ngx_resolver_t if (ident != qident) { ngx_log_error(r->log_level, r->log, 0, - "wrong ident %d response for %ud.%ud.%ud.%ud, expect %d", - ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff, - (addr >> 8) & 0xff, addr & 0xff, qident); + "wrong ident %ui response for %ud.%ud.%ud.%ud, expect %ui", + ident, (addr >> 24) & 0xff, (addr >> 16) & 0xff, + (addr >> 8) & 0xff, addr & 0xff, qident); goto failed; } @@ -1421,7 +1475,7 @@ ngx_resolver_process_ptr(ngx_resolver_t len = (an->len_hi << 8) + an->len_lo; ngx_log_debug3(NGX_LOG_DEBUG_CORE, r->log, 0, - "resolver qt:%d cl:%d len:%uz", qtype, qclass, len); + "resolver qt:%ui cl:%ui len:%uz", qtype, qclass, len); i += 2 + sizeof(ngx_resolver_an_t); @@ -1684,6 +1738,10 @@ ngx_resolver_create_name_query(ngx_resol len++; } else { + if (len == 0) { + return NGX_DECLINED; + } + *p = (u_char) len; len = 0; } diff --git a/src/core/ngx_resolver.h b/src/core/ngx_resolver.h --- a/src/core/ngx_resolver.h +++ b/src/core/ngx_resolver.h @@ -17,6 +17,7 @@ #define NGX_RESOLVE_PTR 12 #define NGX_RESOLVE_MX 15 #define NGX_RESOLVE_TXT 16 +#define NGX_RESOLVE_DNAME 39 #define NGX_RESOLVE_FORMERR 1 #define NGX_RESOLVE_SERVFAIL 2 @@ -28,6 +29,8 @@ #define NGX_NO_RESOLVER (void *) -1 +#define NGX_RESOLVER_MAX_RECURSION 50 + typedef struct { ngx_connection_t *connection; @@ -127,6 +130,7 @@ struct ngx_resolver_ctx_s { ngx_msec_t timeout; ngx_uint_t quick; /* unsigned quick:1; */ + ngx_uint_t recursion; ngx_event_t *event; }; 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 @@ -1430,26 +1430,32 @@ ngx_escape_html(u_char *dst, u_char *src void ngx_sort(void *base, size_t n, size_t size, - int (*cmp)(const void *, const void *)) + ngx_int_t (*cmp)(const void *, const void *)) { - u_char *p1, *p2; - u_char buf[256]; + u_char *p1, *p2, *p; + + p = ngx_alloc(size, ngx_cycle->log); + if (p == NULL) { + return; + } for (p1 = (u_char *) base + size; p1 < (u_char *) base + n * size; p1 += size) { - ngx_memcpy(buf, p1, size); + ngx_memcpy(p, p1, size); for (p2 = p1; - p2 > (u_char *) base && cmp(p2 - size, buf) > 0; + p2 > (u_char *) base && cmp(p2 - size, p) > 0; p2 -= size) { ngx_memcpy(p2, p2 - size, size); } - ngx_memcpy(p2, buf, size); + ngx_memcpy(p2, p, size); } + + ngx_free(p); } diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -173,7 +173,7 @@ uintptr_t ngx_escape_html(u_char *dst, u void ngx_sort(void *base, size_t n, size_t size, - int (*cmp)(const void *, const void *)); + ngx_int_t (*cmp)(const void *, const void *)); #define ngx_qsort qsort diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -203,14 +203,17 @@ ngx_http_cookie_time(u_char *buf, time_t void ngx_gmtime(time_t t, ngx_tm_t *tp) { - ngx_uint_t n, sec, min, hour, mday, mon, year, wday, yday, days; + ngx_int_t yday; + ngx_uint_t n, sec, min, hour, mday, mon, year, wday, days, leap; /* the calculation is valid for positive time_t only */ + n = (ngx_uint_t) t; days = n / 86400; /* Jaunary 1, 1970 was Thursday */ + wday = (4 + days) % 7; n %= 86400; @@ -219,57 +222,65 @@ ngx_gmtime(time_t t, ngx_tm_t *tp) min = n / 60; sec = n % 60; - /* the algorithm based on Gauss's formula */ + /* + * the algorithm based on Gauss' formula, + * see src/http/ngx_http_parse_time.c + */ + /* days since March 1, 1 BC */ days = days - (31 + 28) + 719527; - year = days * 400 / (365 * 400 + 100 - 4 + 1); + /* + * The "days" should be adjusted to 1 only, however, some March 1st's go + * to previous year, so we adjust them to 2. This causes also shift of the + * last Feburary days to next year, but we catch the case when "yday" + * becomes negative. + */ + + year = (days + 2) * 400 / (365 * 400 + 100 - 4 + 1); + yday = days - (365 * year + year / 4 - year / 100 + year / 400); - mon = (yday + 31) * 12 / 367; - mday = yday - (mon * 367 / 12 - 31); + if (yday < 0) { + leap = (year % 4 == 0) && (year % 100 || (year % 400 == 0)); + yday = 365 + leap + yday; + year--; + } - mon += 2; + /* + * The empirical formula that maps "yday" to month. + * There are at least 10 variants, some of them are: + * mon = (yday + 31) * 15 / 459 + * mon = (yday + 31) * 17 / 520 + * mon = (yday + 31) * 20 / 612 + */ + + mon = (yday + 31) * 10 / 306; + + /* the Gauss' formula that evaluates days before the month */ + + mday = yday - (367 * mon / 12 - 30) + 1; if (yday >= 306) { + year++; + mon -= 10; + /* * there is no "yday" in Win32 SYSTEMTIME * * yday -= 306; */ - year++; - mon -= 12; - - if (mday == 0) { - /* Jaunary 31 */ - mon = 1; - mday = 31; + } else { - } else if (mon == 2) { - - if ((year % 4 == 0) && (year % 100 || (year % 400 == 0))) { - if (mday > 29) { - mon = 3; - mday -= 29; - } + mon += 2; - } else if (mday > 28) { - mon = 3; - mday -= 28; - } - } -/* - * there is no "yday" in Win32 SYSTEMTIME - * - * } else { - * yday += 31 + 28; - * - * if ((year % 4 == 0) && (year % 100 || (year % 400 == 0))) { - * yday++; - * } - */ + /* + * there is no "yday" in Win32 SYSTEMTIME + * + * yday += 31 + 28 + leap; + */ } tp->ngx_tm_sec = (ngx_tm_sec_t) sec; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -285,10 +285,11 @@ ngx_ssl_client_certificate(ngx_conf_t *c static int ngx_http_ssl_verify_callback(int ok, X509_STORE_CTX *x509_store) { +#if (NGX_DEBUG) char *subject, *issuer; int err, depth; X509 *cert; - X509_NAME *name; + X509_NAME *sname, *iname; ngx_connection_t *c; ngx_ssl_conn_t *ssl_conn; @@ -301,17 +302,26 @@ ngx_http_ssl_verify_callback(int ok, X50 err = X509_STORE_CTX_get_error(x509_store); depth = X509_STORE_CTX_get_error_depth(x509_store); - name = X509_get_subject_name(cert); - subject = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; - - name = X509_get_issuer_name(cert); - issuer = name ? X509_NAME_oneline(name, NULL, 0) : "(none)"; + sname = X509_get_subject_name(cert); + subject = sname ? X509_NAME_oneline(sname, NULL, 0) : "(none)"; + + iname = X509_get_issuer_name(cert); + issuer = iname ? X509_NAME_oneline(iname, NULL, 0) : "(none)"; ngx_log_debug5(NGX_LOG_DEBUG_EVENT, c->log, 0, "verify:%d, error:%d, depth:%d, " "subject:\"%s\",issuer: \"%s\"", ok, err, depth, subject, issuer); + if (sname) { + OPENSSL_free(subject); + } + + if (iname) { + OPENSSL_free(issuer); + } +#endif + return 1; } @@ -1778,6 +1788,7 @@ ngx_ssl_get_subject_dn(ngx_connection_t name = X509_get_subject_name(cert); if (name == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -1789,12 +1800,14 @@ ngx_ssl_get_subject_dn(ngx_connection_t s->data = ngx_palloc(pool, len); if (s->data == NULL) { OPENSSL_free(p); + X509_free(cert); return NGX_ERROR; } ngx_memcpy(s->data, p, len); OPENSSL_free(p); + X509_free(cert); return NGX_OK; } @@ -1817,6 +1830,7 @@ ngx_ssl_get_issuer_dn(ngx_connection_t * name = X509_get_issuer_name(cert); if (name == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -1828,12 +1842,14 @@ ngx_ssl_get_issuer_dn(ngx_connection_t * s->data = ngx_palloc(pool, len); if (s->data == NULL) { OPENSSL_free(p); + X509_free(cert); return NGX_ERROR; } ngx_memcpy(s->data, p, len); OPENSSL_free(p); + X509_free(cert); return NGX_OK; } @@ -1855,6 +1871,7 @@ ngx_ssl_get_serial_number(ngx_connection bio = BIO_new(BIO_s_mem()); if (bio == NULL) { + X509_free(cert); return NGX_ERROR; } @@ -1865,11 +1882,13 @@ ngx_ssl_get_serial_number(ngx_connection s->data = ngx_palloc(pool, len); if (s->data == NULL) { BIO_free(bio); + X509_free(cert); return NGX_ERROR; } BIO_read(bio, s->data, len); BIO_free(bio); + X509_free(cert); return NGX_OK; } diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -590,7 +590,7 @@ ngx_http_sub_parse(ngx_http_request_t *r ctx->state = sub_start_state; ctx->pos = p + 1; - ctx->looked = looked; + ctx->looked = 0; ctx->copy_end = copy_end; if (ctx->copy_start == NULL && copy_end) { diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.6.29'; +our $VERSION = '0.6.30'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -19,7 +19,7 @@ static ngx_int_t ngx_http_add_names(ngx_ static char *ngx_http_merge_locations(ngx_conf_t *cf, ngx_array_t *locations, void **loc_conf, ngx_http_module_t *module, ngx_uint_t ctx_index); -static int ngx_http_cmp_conf_in_addrs(const void *one, const void *two); +static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two); static int ngx_libc_cdecl ngx_http_cmp_dns_wildcards(const void *one, const void *two); @@ -1089,7 +1089,7 @@ ngx_http_merge_locations(ngx_conf_t *cf, } -static int +static ngx_int_t ngx_http_cmp_conf_in_addrs(const void *one, const void *two) { ngx_http_conf_in_addr_t *first, *second; 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 @@ -45,7 +45,8 @@ static char *ngx_http_core_server(ngx_co void *dummy); static char *ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy); -static int ngx_http_core_cmp_locations(const void *first, const void *second); +static ngx_int_t ngx_http_core_cmp_locations(const void *first, + const void *second); static char *ngx_http_core_types(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -2297,7 +2298,7 @@ ngx_http_core_location(ngx_conf_t *cf, n } -static int +static ngx_int_t ngx_http_core_cmp_locations(const void *one, const void *two) { ngx_int_t rc; @@ -2361,7 +2362,7 @@ ngx_http_core_cmp_locations(const void * return 1; } - return (int) rc; + return rc; } @@ -3470,6 +3471,7 @@ ngx_http_core_error_page(ngx_conf_t *cf, { ngx_http_core_loc_conf_t *lcf = conf; + u_char *args; ngx_int_t overwrite; ngx_str_t *value, uri; ngx_uint_t i, n, nvar; @@ -3538,6 +3540,8 @@ ngx_http_core_error_page(ngx_conf_t *cf, } } + args = (u_char *) ngx_strchr(uri.data, '?'); + for (i = 1; i < cf->args->nelts - n; i++) { err = ngx_array_push(lcf->error_pages); if (err == NULL) { @@ -3576,7 +3580,19 @@ ngx_http_core_error_page(ngx_conf_t *cf, } } - err->uri = uri; + if (args) { + err->uri.len = args - uri.data; + err->uri.data = uri.data; + args++; + err->args.len = (uri.data + uri.len) - args; + err->args.data = args; + + } else { + err->uri = uri; + err->args.len = 0; + err->args.data = NULL; + } + err->uri_lengths = uri_lengths; err->uri_values = uri_values; } diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -225,6 +225,7 @@ typedef struct { ngx_int_t status; ngx_int_t overwrite; ngx_str_t uri; + ngx_str_t args; ngx_array_t *uri_lengths; ngx_array_t *uri_values; } ngx_http_err_page_t; diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -240,7 +240,7 @@ ngx_http_parse_time(u_char *value, size_ /* * shift new year to March 1 and start months from 1 (not 0), - * it is needed for Gauss's formula + * it is needed for Gauss' formula */ if (--month <= 0) { @@ -248,11 +248,20 @@ ngx_http_parse_time(u_char *value, size_ year -= 1; } - /* Gauss's formula for Grigorian days from March 1, 1 BC */ + /* Gauss' formula for Grigorian days since March 1, 1 BC */ + + return ( + /* days in years including leap years since March 1, 1 BC */ + + 365 * year + year / 4 - year / 100 + year / 400 - return (365 * year + year / 4 - year / 100 + year / 400 - + 367 * month / 12 - 31 - + day + /* days before the month */ + + + 367 * month / 12 - 30 + + /* days before the day */ + + + day - 1 /* * 719527 days were between March 1, 1 BC and March 1, 1970, 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 @@ -1419,6 +1419,7 @@ ngx_http_process_request(ngx_http_reques if (c->ssl) { long rc; + X509 *cert; ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); @@ -1438,9 +1439,9 @@ ngx_http_process_request(ngx_http_reques return; } - if (SSL_get_peer_certificate(c->ssl->connection) - == NULL) - { + cert = SSL_get_peer_certificate(c->ssl->connection); + + if (cert == NULL) { ngx_log_error(NGX_LOG_INFO, c->log, 0, "client sent no required SSL certificate"); @@ -1450,6 +1451,8 @@ ngx_http_process_request(ngx_http_reques ngx_http_finalize_request(r, NGX_HTTPS_NO_CERT); return; } + + X509_free(cert); } } diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -441,8 +441,6 @@ ngx_http_send_error_page(ngx_http_reques r->zero_in_uri = 0; - args = NULL; - if (err_page->uri_lengths) { if (ngx_http_script_run(r, &u, err_page->uri_lengths->elts, 0, err_page->uri_values->elts) @@ -453,6 +451,7 @@ ngx_http_send_error_page(ngx_http_reques p = u.data; uri = &u; + args = NULL; if (*p == '/') { @@ -488,6 +487,7 @@ ngx_http_send_error_page(ngx_http_reques } else { uri = &err_page->uri; + args = &err_page->args; } if (uri->data[0] == '/') { 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 @@ -333,7 +333,6 @@ ngx_http_upstream_init(ngx_http_request_ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - u->output.sendfile = c->sendfile; u->output.pool = r->pool; u->output.bufs.num = 1; u->output.bufs.size = clcf->client_body_buffer_size; @@ -422,13 +421,14 @@ ngx_http_upstream_init(ngx_http_request_ ctx->data = r; ctx->timeout = clcf->resolver_timeout; + u->resolved->ctx = ctx; + if (ngx_resolve_name(ctx) != NGX_OK) { + u->resolved->ctx = NULL; ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); return; } - u->resolved->ctx = ctx; - return; } @@ -702,6 +702,7 @@ ngx_http_upstream_connect(ngx_http_reque c->read->handler = ngx_http_upstream_process_header; c->sendfile &= r->connection->sendfile; + u->output.sendfile = c->sendfile; c->pool = r->pool; c->read->log = c->write->log = c->log = r->connection->log; @@ -2612,6 +2613,10 @@ ngx_http_upstream_copy_content_type(ngx_ while (*++p == ' ') { /* void */ } + if (*p == '\0') { + return NGX_OK; + } + if (ngx_strncasecmp(p, (u_char *) "charset=", 8) != 0) { continue; } @@ -3200,7 +3205,7 @@ ngx_http_upstream_server(ngx_conf_t *cf, fail_timeout = ngx_parse_time(&s, 1); - if (fail_timeout < 0) { + if (fail_timeout == NGX_ERROR) { goto invalid; } diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -9,7 +9,8 @@ #include -static int ngx_http_upstream_cmp_servers(const void *one, const void *two); +static ngx_int_t ngx_http_upstream_cmp_servers(const void *one, + const void *two); static ngx_uint_t ngx_http_upstream_get_peer(ngx_http_upstream_rr_peers_t *peers); @@ -185,7 +186,7 @@ ngx_http_upstream_init_round_robin(ngx_c } -static int +static ngx_int_t ngx_http_upstream_cmp_servers(const void *one, const void *two) { ngx_http_upstream_rr_peer_t *first, *second; diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -11,7 +11,7 @@ static char *ngx_mail_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); -static int ngx_mail_cmp_conf_in_addrs(const void *one, const void *two); +static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two); ngx_uint_t ngx_mail_max_module; @@ -388,7 +388,7 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma } -static int +static ngx_int_t ngx_mail_cmp_conf_in_addrs(const void *one, const void *two) { ngx_mail_conf_in_addr_t *first, *second; diff --git a/src/mail/ngx_mail_proxy_module.c b/src/mail/ngx_mail_proxy_module.c --- a/src/mail/ngx_mail_proxy_module.c +++ b/src/mail/ngx_mail_proxy_module.c @@ -171,6 +171,8 @@ ngx_mail_proxy_init(ngx_mail_session_t * return; } + s->out.len = 0; + switch (s->protocol) { case NGX_MAIL_POP3_PROTOCOL: 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 @@ -257,7 +257,15 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t ngx_int_t ngx_open_glob(ngx_glob_t *gl) { - if (glob((char *) gl->pattern, GLOB_NOSORT, NULL, &gl->pglob) == 0) { + int n; + + n = glob((char *) gl->pattern, GLOB_NOSORT, NULL, &gl->pglob); + + if (n == 0) { + return NGX_OK; + } + + if (n == GLOB_NOMATCH && gl->test) { return NGX_OK; } diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -17,8 +17,18 @@ +#ifdef __CYGWIN__ + +#define ngx_open_file(name, mode, create, access) \ + open((const char *) name, mode|create|O_BINARY, access) + +#else + #define ngx_open_file(name, mode, create, access) \ open((const char *) name, mode|create, access) + +#endif + #define ngx_open_file_n "open()" #define NGX_FILE_RDONLY O_RDONLY @@ -144,10 +154,11 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, typedef struct { - size_t n; - glob_t pglob; - u_char *pattern; - ngx_log_t *log; + size_t n; + glob_t pglob; + u_char *pattern; + ngx_log_t *log; + ngx_uint_t test; } ngx_glob_t; diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -70,7 +70,7 @@ #include /* IOV_MAX */ #endif -#if (NGX_HAVE_MALLOC_H) +#ifdef __CYGWIN__ #include /* memalign() */ #endif 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 @@ -452,7 +452,7 @@ ngx_process_get_status(void) * * When several processes exit at the same time FreeBSD may * erroneously call the signal handler for exited process - * despite waitpid() may be already called for this process + * despite waitpid() may be already called for this process. */ if (err == NGX_ECHILD) { @@ -507,8 +507,9 @@ ngx_process_get_status(void) if (WEXITSTATUS(status) == 2 && ngx_processes[i].respawn) { ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, - "%s %P exited with fatal code %d and could not respawn", - process, pid, WEXITSTATUS(status)); + "%s %P exited with fatal code %d " + "and can not be respawn", + process, pid, WEXITSTATUS(status)); ngx_processes[i].respawn = 0; } }