summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2009-04-02 06:49:14 +0000
committerJonathan Kolb <jon@b0g.us>2009-04-02 06:49:14 +0000
commit5e44792c14ec6bf5b0ea68717d754ba0105ae529 (patch)
tree96d1464377a96f9a1e46a7ec91492b71dcfa58ca
parentbc9bfd795a752dfa02eacca728a6be574c9d1932 (diff)
downloadnginx-0.6.36.tar.gz
Changes with nginx 0.6.36 02 Apr 2009v0.6.36
*) Change: now the "Invalid argument" error returned by setsockopt(TCP_NODELAY) on Solaris, is ignored. *) Change: now POSTs without "Content-Length" header line are allowed. *) Feature: the "try_files" directive. *) Feature: the --with-pcre option in the configure. *) Feature: the "if_modified_since" directive. *) Feature: the "$cookie_..." variables. *) Feature: the "$arg_..." variables. *) Bugfix: compatibility with Tru64 UNIX. Thanks to Dustin Marquess. *) Bugfix: a "ssl_engine" directive did not use a SSL-accelerator for asymmetric ciphers. Thanks to Marcin Gozdalik. *) Bugfix: in a redirect rewrite directive original arguments were concatenated with new arguments by a "?" rather than an "&"; the bug had appeared in 0.1.18. Thanks to Maxim Dounin. *) Bugfix: nginx could not be built on AIX. *) Bugfix: a double response might be returned if the epoll or rtsig methods are used and a redirect was returned to a request with body. Thanks to Eden Li. *) Bugfix: a segmentation fault might occur in worker process if "resolver" directive was used in SMTP proxy. *) Bugfix: fastcgi_store stored files not always. *) Bugfix: nginx did not process a FastCGI server response, if the server send too many messages to stderr before response.
-rw-r--r--CHANGES49
-rw-r--r--CHANGES.ru45
-rw-r--r--auto/options4
-rw-r--r--src/core/nginx.h3
-rw-r--r--src/core/ngx_conf_file.c42
-rw-r--r--src/core/ngx_conf_file.h2
-rw-r--r--src/core/ngx_connection.c11
-rw-r--r--src/core/ngx_connection.h7
-rw-r--r--src/core/ngx_log.c17
-rw-r--r--src/core/ngx_resolver.c30
-rw-r--r--src/core/ngx_shmtx.h14
-rw-r--r--src/core/ngx_string.h18
-rw-r--r--src/event/ngx_event_openssl.c59
-rw-r--r--src/http/modules/ngx_http_autoindex_module.c5
-rw-r--r--src/http/modules/ngx_http_not_modified_filter_module.c28
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/ngx_http.c15
-rw-r--r--src/http/ngx_http.h2
-rw-r--r--src/http/ngx_http_core_module.c272
-rw-r--r--src/http/ngx_http_core_module.h20
-rw-r--r--src/http/ngx_http_parse.c36
-rw-r--r--src/http/ngx_http_request.c13
-rw-r--r--src/http/ngx_http_script.c19
-rw-r--r--src/http/ngx_http_upstream.c95
-rw-r--r--src/http/ngx_http_variables.c120
-rw-r--r--src/mail/ngx_mail_smtp_handler.c23
-rw-r--r--src/os/unix/ngx_errno.c10
-rw-r--r--src/os/unix/ngx_process.c6
28 files changed, 810 insertions, 157 deletions
diff --git a/CHANGES b/CHANGES
index b01a5a899..066b0c708 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,49 @@
+Changes with nginx 0.6.36 02 Apr 2009
+
+ *) Change: now the "Invalid argument" error returned by
+ setsockopt(TCP_NODELAY) on Solaris, is ignored.
+
+ *) Change: now POSTs without "Content-Length" header line are allowed.
+
+ *) Feature: the "try_files" directive.
+
+ *) Feature: the --with-pcre option in the configure.
+
+ *) Feature: the "if_modified_since" directive.
+
+ *) Feature: the "$cookie_..." variables.
+
+ *) Feature: the "$arg_..." variables.
+
+ *) Bugfix: compatibility with Tru64 UNIX.
+ Thanks to Dustin Marquess.
+
+ *) Bugfix: a "ssl_engine" directive did not use a SSL-accelerator for
+ asymmetric ciphers.
+ Thanks to Marcin Gozdalik.
+
+ *) Bugfix: in a redirect rewrite directive original arguments were
+ concatenated with new arguments by a "?" rather than an "&";
+ the bug had appeared in 0.1.18.
+ Thanks to Maxim Dounin.
+
+ *) Bugfix: nginx could not be built on AIX.
+
+ *) Bugfix: a double response might be returned if the epoll or rtsig
+ methods are used and a redirect was returned to a request with
+ body.
+ Thanks to Eden Li.
+
+ *) Bugfix: a segmentation fault might occur in worker process if
+ "resolver" directive was used in SMTP proxy.
+
+ *) Bugfix: fastcgi_store stored files not always.
+
+ *) Bugfix: nginx did not process a FastCGI server response, if the
+ server send too many messages to stderr before response.
+
+
Changes with nginx 0.6.35 26 Jan 2009
*) Bugfix: in shared memory allocations if nginx was built without
@@ -3018,8 +3063,8 @@ Changes with nginx 0.1.18 09 Feb 2005
*) Bugfix: the proxy_set_x_var and fastcgi_set_var directives were not
inherited.
- *) Bugfix: in the redirect rewrite directive the arguments were
- concatenated with URI by the "&" rather than the "?".
+ *) Bugfix: in a redirect rewrite directive arguments were concatenated
+ with URI by an "&" rather than a "?".
*) Bugfix: the lines without trailing ";" in the file being included by
the ngx_http_geo_module were silently ignored.
diff --git a/CHANGES.ru b/CHANGES.ru
index 17f76fab3..6c4a02ae3 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,49 @@
+Изменения в nginx 0.6.36 02.04.2009
+
+ *) Изменение: ошибка "Invalid argument", возвращаемая
+ setsockopt(TCP_NODELAY) на Solaris, теперь игнорируется.
+
+ *) Изменение: теперь разрешаются POST'ы без строки "Content-Length" в
+ заголовке запроса.
+
+ *) Добавление: директива try_files.
+
+ *) Добавление: параметр --with-pcre в configure.
+
+ *) Добавление: директива if_modified_since.
+
+ *) Добавление: переменные "$cookie_...".
+
+ *) Добавление: переменные "$arg_...".
+
+ *) Исправление: совместимость с Tru64 UNIX.
+ Спасибо Dustin Marquess.
+
+ *) Исправление: директива ssl_engine не использовала SSL-акселератор
+ для асимметричных шифров.
+ Спасибо Marcin Gozdalik.
+
+ *) Исправление: в директиве rewrite, возвращающей редирект, старые
+ аргументы присоединялись к новым через символ "?" вместо "&";
+ ошибка появилась в 0.1.18.
+ Спасибо Максиму Дунину.
+
+ *) Исправление: nginx не собирался на AIX.
+
+ *) Исправление: если на запрос с телом возвращался редирект, то ответ
+ мог быть двойным при использовании методов epoll или rtsig.
+ Спасибо Eden Li.
+
+ *) Исправление: при использовании директивы resolver в SMTP
+ прокси-сервере в рабочем процессе мог произойти segmentation fault.
+
+ *) Исправление: fastcgi_store не всегда сохранял файлы.
+
+ *) Исправление: nginx не обрабатывал ответ FastCGI-сервера, если перед
+ ответом сервер передавал много сообщений в stderr.
+
+
Изменения в nginx 0.6.35 26.01.2009
*) Исправление: ошибки выделения больших блоков в разделяемой памяти,
diff --git a/auto/options b/auto/options
index e00bf9764..268ece99c 100644
--- a/auto/options
+++ b/auto/options
@@ -215,6 +215,7 @@ do
--with-debug) NGX_DEBUG=YES ;;
--without-pcre) USE_PCRE=DISABLED ;;
+ --with-pcre) USE_PCRE=YES ;;
--with-pcre=*) PCRE="$value" ;;
--with-pcre-opt=*) PCRE_OPT="$value" ;;
@@ -333,7 +334,8 @@ cat << END
pentium, pentiumpro, pentium3, pentium4,
athlon, opteron, sparc32, sparc64, ppc64
- --without-pcre disable PCRE libarary usage
+ --without-pcre disable PCRE library usage
+ --with-pcre force PCRE library usage
--with-pcre=DIR set path to PCRE library sources
--with-pcre-opt=OPTIONS set additional options for PCRE building
diff --git a/src/core/nginx.h b/src/core/nginx.h
index fdc747fce..ba51d4ac3 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,8 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VERSION "0.6.35"
+#define nginx_version 006036
+#define NGINX_VERSION "0.6.36"
#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
index 54ae237f3..cab32975d 100644
--- a/src/core/ngx_conf_file.c
+++ b/src/core/ngx_conf_file.c
@@ -201,14 +201,14 @@ done:
if (filename) {
ngx_free(cf->conf_file->buffer->start);
- cf->conf_file = prev;
-
if (ngx_close_file(fd) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno,
ngx_close_file_n " %s failed",
cf->conf_file->file.name.data);
return NGX_CONF_ERROR;
}
+
+ cf->conf_file = prev;
}
if (rc == NGX_ERROR) {
@@ -853,31 +853,47 @@ void ngx_cdecl
ngx_conf_log_error(ngx_uint_t level, ngx_conf_t *cf, ngx_err_t err,
char *fmt, ...)
{
- u_char errstr[NGX_MAX_CONF_ERRSTR], *buf, *last;
+ u_char errstr[NGX_MAX_CONF_ERRSTR], *p, *last;
va_list args;
last = errstr + NGX_MAX_CONF_ERRSTR;
va_start(args, fmt);
- buf = ngx_vsnprintf(errstr, last - errstr, fmt, args);
+ p = ngx_vsnprintf(errstr, last - errstr, fmt, args);
va_end(args);
- *buf = '\0';
-
if (err) {
- buf = ngx_snprintf(buf, last - buf - 1, " (%d: ", err);
- buf = ngx_strerror_r(err, buf, last - buf - 1);
- *buf++ = ')';
- *buf = '\0';
+
+ if (p > last - 50) {
+
+ /* leave a space for an error code */
+
+ p = last - 50;
+ *p++ = '.';
+ *p++ = '.';
+ *p++ = '.';
+ }
+
+#if (NGX_WIN32)
+ p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000)
+ ? " (%d: " : " (%Xd: ", err);
+#else
+ p = ngx_snprintf(p, last - p, " (%d: ", err);
+#endif
+
+ p = ngx_strerror_r(err, p, last - p);
+
+ *p++ = ')';
}
if (cf->conf_file == NULL) {
- ngx_log_error(level, cf->log, 0, "%s", errstr);
+ ngx_log_error(level, cf->log, 0, "%*s", p - errstr, errstr);
return;
}
- ngx_log_error(level, cf->log, 0, "%s in %s:%ui",
- errstr, cf->conf_file->file.name.data, cf->conf_file->line);
+ ngx_log_error(level, cf->log, 0, "%*s in %s:%ui",
+ p - errstr, errstr,
+ cf->conf_file->file.name.data, cf->conf_file->line);
}
diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h
index c3e3e9a91..9ea9c75bb 100644
--- a/src/core/ngx_conf_file.h
+++ b/src/core/ngx_conf_file.h
@@ -71,7 +71,7 @@
#define NGX_CONF_MODULE 0x464E4F43 /* "CONF" */
-#define NGX_MAX_CONF_ERRSTR 256
+#define NGX_MAX_CONF_ERRSTR 1024
struct ngx_command_s {
diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c
index b49a696f2..7982d963e 100644
--- a/src/core/ngx_connection.c
+++ b/src/core/ngx_connection.c
@@ -779,12 +779,16 @@ ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text)
{
ngx_uint_t level;
- if (err == NGX_ECONNRESET
- && c->log_error == NGX_ERROR_IGNORE_ECONNRESET)
- {
+ if (err == NGX_ECONNRESET && c->log_error == NGX_ERROR_IGNORE_ECONNRESET) {
return 0;
}
+#if (NGX_SOLARIS)
+ if (err == NGX_EINVAL && c->log_error == NGX_ERROR_IGNORE_EINVAL) {
+ return 0;
+ }
+#endif
+
if (err == 0
|| err == NGX_ECONNRESET
#if !(NGX_WIN32)
@@ -800,6 +804,7 @@ ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text)
{
switch (c->log_error) {
+ case NGX_ERROR_IGNORE_EINVAL:
case NGX_ERROR_IGNORE_ECONNRESET:
case NGX_ERROR_INFO:
level = NGX_LOG_INFO;
diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h
index a2ae690f5..ac8679697 100644
--- a/src/core/ngx_connection.h
+++ b/src/core/ngx_connection.h
@@ -71,10 +71,11 @@ struct ngx_listening_s {
typedef enum {
- NGX_ERROR_CRIT = 0,
+ NGX_ERROR_ALERT = 0,
NGX_ERROR_ERR,
NGX_ERROR_INFO,
- NGX_ERROR_IGNORE_ECONNRESET
+ NGX_ERROR_IGNORE_ECONNRESET,
+ NGX_ERROR_IGNORE_EINVAL
} ngx_connection_log_error_e;
@@ -135,7 +136,7 @@ struct ngx_connection_s {
unsigned buffered:8;
- unsigned log_error:2; /* ngx_connection_log_error_e */
+ unsigned log_error:3; /* ngx_connection_log_error_e */
unsigned single_connection:1;
unsigned unexpected_eof:1;
diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c
index e3abcd780..a9221db6e 100644
--- a/src/core/ngx_log.c
+++ b/src/core/ngx_log.c
@@ -127,18 +127,10 @@ ngx_log_error_core(ngx_uint_t level, ngx_log_t *log, ngx_err_t err,
}
#if (NGX_WIN32)
-
- if ((unsigned) err >= 0x80000000) {
- p = ngx_snprintf(p, last - p, " (%Xd: ", err);
-
- } else {
- p = ngx_snprintf(p, last - p, " (%d: ", err);
- }
-
+ p = ngx_snprintf(p, last - p, ((unsigned) err < 0x80000000)
+ ? " (%d: " : " (%Xd: ", err);
#else
-
p = ngx_snprintf(p, last - p, " (%d: ", err);
-
#endif
p = ngx_strerror_r(err, p, last - p);
@@ -310,7 +302,10 @@ ngx_set_error_log_levels(ngx_conf_t *cf, ngx_log_t *log)
}
}
- if (log->log_level == NGX_LOG_DEBUG) {
+ if (log->log_level == 0) {
+ log->log_level = NGX_LOG_ERR;
+
+ } else if (log->log_level == NGX_LOG_DEBUG) {
log->log_level = NGX_LOG_DEBUG_ALL;
}
diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c
index 2998bb2e0..b141b9ba5 100644
--- a/src/core/ngx_resolver.c
+++ b/src/core/ngx_resolver.c
@@ -578,6 +578,7 @@ failed:
ngx_int_t
ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
{
+ u_char *name;
ngx_resolver_t *r;
ngx_resolver_node_t *rn;
@@ -601,19 +602,21 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ngx_queue_insert_head(&r->addr_expire_queue, &rn->queue);
- ctx->name.len = rn->nlen;
- ctx->name.data = ngx_resolver_dup(r, rn->name, rn->nlen);
- if (ctx->name.data == NULL) {
+ name = ngx_resolver_dup(r, rn->name, rn->nlen);
+ if (name == NULL) {
goto failed;
}
+ ctx->name.len = rn->nlen;
+ ctx->name.data = name;
+
/* unlock addr mutex */
ctx->state = NGX_OK;
ctx->handler(ctx);
- ngx_resolver_free(r, ctx->name.data);
+ ngx_resolver_free(r, name);
return NGX_OK;
}
@@ -623,7 +626,9 @@ ngx_resolve_addr(ngx_resolver_ctx_t *ctx)
ctx->next = rn->waiting;
rn->waiting = ctx;
- return NGX_AGAIN;
+ /* unlock addr mutex */
+
+ return NGX_OK;
}
ngx_queue_remove(&rn->queue);
@@ -1306,7 +1311,7 @@ ngx_resolver_process_a(ngx_resolver_t *r, u_char *buf, size_t last,
ctx->handler(ctx);
}
- if (naddrs) {
+ if (naddrs > 1) {
ngx_resolver_free(r, addrs);
}
@@ -1483,20 +1488,23 @@ ngx_resolver_process_ptr(ngx_resolver_t *r, u_char *buf, size_t n,
goto short_response;
}
- len -= 2;
-
if (ngx_resolver_copy(r, &name, buf, &buf[i], &buf[n]) != NGX_OK) {
return;
}
ngx_log_debug1(NGX_LOG_DEBUG_CORE, r->log, 0, "resolver an:%V", &name);
- if (len != (size_t) rn->nlen || ngx_strncmp(name.data, rn->name, len) != 0)
+ if (name.len != (size_t) rn->nlen
+ || ngx_strncmp(name.data, rn->name, name.len) != 0)
{
- ngx_resolver_free(r, rn->name);
+ if (rn->nlen) {
+ ngx_resolver_free(r, rn->name);
+ }
+
+ rn->nlen = (u_short) name.len;
rn->name = name.data;
- name.data = ngx_resolver_dup(r, rn->name, len);
+ name.data = ngx_resolver_dup(r, rn->name, name.len);
if (name.data == NULL) {
goto failed;
}
diff --git a/src/core/ngx_shmtx.h b/src/core/ngx_shmtx.h
index e6fb6aa31..57fe0b9f5 100644
--- a/src/core/ngx_shmtx.h
+++ b/src/core/ngx_shmtx.h
@@ -57,7 +57,15 @@ ngx_shmtx_trylock(ngx_shmtx_t *mtx)
return 0;
}
- ngx_log_abort(err, ngx_trylock_fd_n " failed");
+#if __osf__ /* Tru64 UNIX */
+
+ if (err == NGX_EACCESS) {
+ return 0;
+ }
+
+#endif
+
+ ngx_log_abort(err, ngx_trylock_fd_n " %s failed", mtx->name);
return 0;
}
@@ -74,7 +82,7 @@ ngx_shmtx_lock(ngx_shmtx_t *mtx)
return;
}
- ngx_log_abort(err, ngx_lock_fd_n " failed");
+ ngx_log_abort(err, ngx_lock_fd_n " %s failed", mtx->name);
}
@@ -89,7 +97,7 @@ ngx_shmtx_unlock(ngx_shmtx_t *mtx)
return;
}
- ngx_log_abort(err, ngx_unlock_fd_n " failed");
+ ngx_log_abort(err, ngx_unlock_fd_n " %s failed", mtx->name);
}
diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h
index dfb3bc4cc..eff9e0be0 100644
--- a/src/core/ngx_string.h
+++ b/src/core/ngx_string.h
@@ -52,9 +52,25 @@ typedef struct {
#define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2)
-#define ngx_strchr(s1, c) strchr((const char *) s1, (int) c)
#define ngx_strlen(s) strlen((const char *) s)
+#define ngx_strchr(s1, c) strchr((const char *) s1, (int) c)
+
+static ngx_inline u_char *
+ngx_strlchr(u_char *p, u_char *last, u_char c)
+{
+ while (p < last) {
+
+ if (*p == c) {
+ return p;
+ }
+
+ p++;
+ }
+
+ return NULL;
+}
+
/*
* msvc and icc7 compile memset() to the inline "rep stos"
diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c
index 79b94144b..3e25dd8dd 100644
--- a/src/event/ngx_event_openssl.c
+++ b/src/event/ngx_event_openssl.c
@@ -10,7 +10,7 @@
typedef struct {
- ngx_str_t engine;
+ ngx_uint_t engine; /* unsigned engine:1; */
} ngx_openssl_conf_t;
@@ -37,26 +37,17 @@ static void ngx_ssl_session_rbtree_insert_value(ngx_rbtree_node_t *temp,
ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel);
static void *ngx_openssl_create_conf(ngx_cycle_t *cycle);
-static char *ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf);
+static char *ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
static void ngx_openssl_exit(ngx_cycle_t *cycle);
-#if !(NGX_SSL_ENGINE)
-static char *ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd,
- void *conf);
-#endif
-
static ngx_command_t ngx_openssl_commands[] = {
{ ngx_string("ssl_engine"),
NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1,
-#if (NGX_SSL_ENGINE)
- ngx_conf_set_str_slot,
-#else
- ngx_openssl_noengine,
-#endif
+ ngx_openssl_engine,
+ 0,
0,
- offsetof(ngx_openssl_conf_t, engine),
NULL },
ngx_null_command
@@ -66,7 +57,7 @@ static ngx_command_t ngx_openssl_commands[] = {
static ngx_core_module_t ngx_openssl_module_ctx = {
ngx_string("openssl"),
ngx_openssl_create_conf,
- ngx_openssl_init_conf
+ NULL
};
@@ -1921,8 +1912,7 @@ ngx_openssl_create_conf(ngx_cycle_t *cycle)
/*
* set by ngx_pcalloc():
*
- * oscf->engine.len = 0;
- * oscf->engine.data = NULL;
+ * oscf->engine = 0;
*/
return oscf;
@@ -1930,53 +1920,54 @@ ngx_openssl_create_conf(ngx_cycle_t *cycle)
static char *
-ngx_openssl_init_conf(ngx_cycle_t *cycle, void *conf)
+ngx_openssl_engine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
#if (NGX_SSL_ENGINE)
ngx_openssl_conf_t *oscf = conf;
- ENGINE *engine;
+ ENGINE *engine;
+ ngx_str_t *value;
- if (oscf->engine.len == 0) {
- return NGX_CONF_OK;
+ if (oscf->engine) {
+ return "is duplicate";
}
- engine = ENGINE_by_id((const char *) oscf->engine.data);
+ oscf->engine = 1;
+
+ value = cf->args->elts;
+
+ engine = ENGINE_by_id((const char *) value[1].data);
if (engine == NULL) {
- ngx_ssl_error(NGX_LOG_WARN, cycle->log, 0,
- "ENGINE_by_id(\"%V\") failed", &oscf->engine);
+ ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
+ "ENGINE_by_id(\"%V\") failed", &value[1]);
return NGX_CONF_ERROR;
}
if (ENGINE_set_default(engine, ENGINE_METHOD_ALL) == 0) {
- ngx_ssl_error(NGX_LOG_WARN, cycle->log, 0,
+ ngx_ssl_error(NGX_LOG_WARN, cf->log, 0,
"ENGINE_set_default(\"%V\", ENGINE_METHOD_ALL) failed",
- &oscf->engine);
+ &value[1]);
+
+ ENGINE_free(engine);
+
return NGX_CONF_ERROR;
}
ENGINE_free(engine);
-#endif
-
return NGX_CONF_OK;
-}
+#else
-#if !(NGX_SSL_ENGINE)
-
-static char *
-ngx_openssl_noengine(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
-{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"ssl_engine\" directive is available only in "
"OpenSSL 0.9.7 and higher,");
return NGX_CONF_ERROR;
-}
#endif
+}
static void
diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c
index 0ff500998..d4d9ac3b2 100644
--- a/src/http/modules/ngx_http_autoindex_module.c
+++ b/src/http/modules/ngx_http_autoindex_module.c
@@ -299,6 +299,11 @@ ngx_http_autoindex_handler(ngx_http_request_t *r)
if (err != NGX_ENOENT) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
ngx_de_info_n " \"%s\" failed", filename);
+
+ if (err == NGX_EACCES) {
+ continue;
+ }
+
return ngx_http_autoindex_error(r, &dir, &path);
}
diff --git a/src/http/modules/ngx_http_not_modified_filter_module.c b/src/http/modules/ngx_http_not_modified_filter_module.c
index ce4b55cf5..feed9cf54 100644
--- a/src/http/modules/ngx_http_not_modified_filter_module.c
+++ b/src/http/modules/ngx_http_not_modified_filter_module.c
@@ -50,7 +50,8 @@ static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
static
ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r)
{
- time_t ims;
+ time_t ims;
+ ngx_http_core_loc_conf_t *clcf;
if (r->headers_out.status != NGX_HTTP_OK
|| r != r->main
@@ -60,23 +61,32 @@ ngx_int_t ngx_http_not_modified_header_filter(ngx_http_request_t *r)
return ngx_http_next_header_filter(r);
}
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->if_modified_since == NGX_HTTP_IMS_OFF) {
+ return ngx_http_next_header_filter(r);
+ }
+
ims = ngx_http_parse_time(r->headers_in.if_modified_since->value.data,
r->headers_in.if_modified_since->value.len);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http ims:%d lm:%d", ims, r->headers_out.last_modified_time);
- /*
- * I think that the equality of the dates is correcter
- */
+ if (ims != r->headers_out.last_modified_time) {
- if (ims == r->headers_out.last_modified_time) {
- r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
- r->headers_out.content_type.len = 0;
- ngx_http_clear_content_length(r);
- ngx_http_clear_accept_ranges(r);
+ if (clcf->if_modified_since == NGX_HTTP_IMS_EXACT
+ || ims < r->headers_out.last_modified_time)
+ {
+ return ngx_http_next_header_filter(r);
+ }
}
+ r->headers_out.status = NGX_HTTP_NOT_MODIFIED;
+ r->headers_out.content_type.len = 0;
+ ngx_http_clear_content_length(r);
+ ngx_http_clear_accept_ranges(r);
+
return ngx_http_next_header_filter(r);
}
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index e3b03c939..df1a83724 100644
--- 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.35';
+our $VERSION = '0.6.36';
require XSLoader;
XSLoader::load('nginx', $VERSION);
diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c
index deb3636a4..f2b1c17d1 100644
--- a/src/http/ngx_http.c
+++ b/src/http/ngx_http.c
@@ -406,7 +406,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
- n = use_rewrite + use_access + 1; /* find config phase */
+ n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
n += cmcf->phases[i].handlers.nelts;
@@ -475,6 +475,15 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
continue;
+ case NGX_HTTP_TRY_FILES_PHASE:
+ if (cmcf->try_files) {
+ ph->checker = ngx_http_core_try_files_phase;
+ n++;
+ ph++;
+ }
+
+ continue;
+
case NGX_HTTP_CONTENT_PHASE:
checker = ngx_http_core_content_phase;
break;
@@ -896,8 +905,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
if (in_addr[i].hash.buckets == NULL
&& (in_addr[i].wc_head == NULL
|| in_addr[i].wc_head->hash.buckets == NULL)
- && (in_addr[i].wc_head == NULL
- || in_addr[i].wc_head->hash.buckets == NULL))
+ && (in_addr[i].wc_tail == NULL
+ || in_addr[i].wc_tail->hash.buckets == NULL))
{
continue;
}
diff --git a/src/http/ngx_http.h b/src/http/ngx_http.h
index 41b6c06b5..9041ff983 100644
--- a/src/http/ngx_http.h
+++ b/src/http/ngx_http.h
@@ -71,6 +71,8 @@ ngx_int_t ngx_http_parse_unsafe_uri(ngx_http_request_t *r, ngx_str_t *uri,
ngx_int_t ngx_http_parse_header_line(ngx_http_request_t *r, ngx_buf_t *b);
ngx_int_t ngx_http_parse_multi_header_lines(ngx_array_t *headers,
ngx_str_t *name, ngx_str_t *value);
+void ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri,
+ ngx_str_t *args);
ngx_int_t ngx_http_find_server_conf(ngx_http_request_t *r);
void ngx_http_update_location_config(ngx_http_request_t *r);
diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c
index 58072347a..cfc649299 100644
--- a/src/http/ngx_http_core_module.c
+++ b/src/http/ngx_http_core_module.c
@@ -62,6 +62,8 @@ static char *ngx_http_core_limit_except(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
+static char *ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd,
+ void *conf);
static char *ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd,
void *conf);
static char *ngx_http_core_error_log(ngx_conf_t *cf, ngx_command_t *cmd,
@@ -114,6 +116,14 @@ static ngx_conf_enum_t ngx_http_core_satisfy[] = {
};
+static ngx_conf_enum_t ngx_http_core_if_modified_since[] = {
+ { ngx_string("off"), NGX_HTTP_IMS_OFF },
+ { ngx_string("exact"), NGX_HTTP_IMS_EXACT },
+ { ngx_string("before"), NGX_HTTP_IMS_BEFORE },
+ { ngx_null_string, 0 }
+};
+
+
#if (NGX_HTTP_GZIP)
static ngx_conf_enum_t ngx_http_gzip_http_version[] = {
@@ -507,6 +517,13 @@ static ngx_command_t ngx_http_core_commands[] = {
offsetof(ngx_http_core_loc_conf_t, server_tokens),
NULL },
+ { ngx_string("if_modified_since"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
+ ngx_conf_set_enum_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_core_loc_conf_t, if_modified_since),
+ &ngx_http_core_if_modified_since },
+
{ ngx_string("error_page"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_2MORE,
@@ -515,6 +532,13 @@ static ngx_command_t ngx_http_core_commands[] = {
0,
NULL },
+ { ngx_string("try_files"),
+ NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_2MORE,
+ ngx_http_core_try_files,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ 0,
+ NULL },
+
{ ngx_string("post_action"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_HTTP_LIF_CONF
|NGX_CONF_TAKE1,
@@ -997,6 +1021,185 @@ ngx_http_core_post_access_phase(ngx_http_request_t *r,
ngx_int_t
+ngx_http_core_try_files_phase(ngx_http_request_t *r,
+ ngx_http_phase_handler_t *ph)
+{
+ size_t len, root, alias, reserve, allocated;
+ u_char *p, *name;
+ ngx_str_t path, args;
+ ngx_uint_t test_dir;
+ ngx_http_try_file_t *tf;
+ ngx_open_file_info_t of;
+ ngx_http_script_code_pt code;
+ ngx_http_script_engine_t e;
+ ngx_http_core_loc_conf_t *clcf;
+ ngx_http_script_len_code_pt lcode;
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "try files phase: %ui", r->phase_handler);
+
+ clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
+
+ if (clcf->try_files == NULL) {
+ r->phase_handler++;
+ return NGX_AGAIN;
+ }
+
+ allocated = 0;
+ root = 0;
+ name = NULL;
+ /* suppress MSVC warning */
+ path.data = NULL;
+
+ tf = clcf->try_files;
+
+ alias = clcf->alias ? clcf->name.len : 0;
+
+ for ( ;; ) {
+
+ if (tf->lengths) {
+ ngx_memzero(&e, sizeof(ngx_http_script_engine_t));
+
+ e.ip = tf->lengths->elts;
+ e.request = r;
+
+ /* 1 is for terminating '\0' as in static names */
+ len = 1;
+
+ while (*(uintptr_t *) e.ip) {
+ lcode = *(ngx_http_script_len_code_pt *) e.ip;
+ len += lcode(&e);
+ }
+
+ } else {
+ len = tf->name.len;
+ }
+
+ /* 16 bytes are preallocation */
+ reserve = ngx_abs((ssize_t) (len - r->uri.len)) + alias + 16;
+
+ if (reserve > allocated) {
+
+ /* we just need to allocate path and to copy a root */
+
+ if (ngx_http_map_uri_to_path(r, &path, &root, reserve) == NULL) {
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_OK;
+ }
+
+ name = path.data + root;
+ allocated = path.len - root - (r->uri.len - alias);
+ }
+
+ if (tf->values == NULL) {
+
+ /* tf->name.len includes the terminating '\0' */
+
+ ngx_memcpy(name, tf->name.data, tf->name.len);
+
+ path.len = (name + tf->name.len - 1) - path.data;
+
+ } else {
+ e.ip = tf->values->elts;
+ e.pos = name;
+ e.flushed = 1;
+
+ while (*(uintptr_t *) e.ip) {
+ code = *(ngx_http_script_code_pt *) e.ip;
+ code((ngx_http_script_engine_t *) &e);
+ }
+
+ path.len = e.pos - path.data;
+
+ *e.pos = '\0';
+
+ if (alias && ngx_strncmp(name, clcf->name.data, alias) == 0) {
+ ngx_memcpy(name, name + alias, len - alias);
+ path.len -= alias;
+ }
+ }
+
+ test_dir = tf->test_dir;
+
+ tf++;
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "try to use file: \"%s\" \"%s\"", name, path.data);
+
+ if (tf->lengths == NULL && tf->name.len == 0) {
+
+ path.len -= root;
+ path.data += root;
+
+ if (path.data[0] == '@') {
+ (void) ngx_http_named_location(r, &path);
+
+ } else {
+ ngx_http_split_args(r, &path, &args);
+
+ (void) ngx_http_internal_redirect(r, &path, &args);
+ }
+
+ return NGX_OK;
+ }
+
+ ngx_memzero(&of, sizeof(ngx_open_file_info_t));
+
+ of.valid = clcf->open_file_cache_valid;
+ of.min_uses = clcf->open_file_cache_min_uses;
+ of.errors = clcf->open_file_cache_errors;
+ of.events = clcf->open_file_cache_events;
+
+ if (ngx_open_cached_file(clcf->open_file_cache, &path, &of, r->pool)
+ != NGX_OK)
+ {
+ if (of.err != NGX_ENOENT && of.err != NGX_ENOTDIR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, of.err,
+ ngx_open_file_n " \"%s\" failed", path.data);
+ }
+
+ continue;
+ }
+
+ if (of.is_dir && !test_dir) {
+ continue;
+ }
+
+ path.len -= root;
+ path.data += root;
+
+ if (!alias) {
+ r->uri = path;
+
+ } else {
+ r->uri.len = alias + path.len;
+ r->uri.data = ngx_palloc(r->pool, r->uri.len);
+ if (r->uri.data == NULL) {
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_OK;
+ }
+
+ p = ngx_copy(r->uri.data, clcf->name.data, alias);
+ ngx_memcpy(p, name, path.len);
+ }
+
+ if (ngx_http_set_exten(r) != NGX_OK) {
+ ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return NGX_OK;
+ }
+
+ ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "try file uri: \"%V\"", &r->uri);
+
+ r->phase_handler++;
+ return NGX_AGAIN;
+ }
+
+ /* not reached */
+}
+
+
+ngx_int_t
ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
@@ -2672,6 +2875,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
* lcf->default_type = { 0, NULL };
* lcf->err_log = NULL;
* lcf->error_pages = NULL;
+ * lcf->try_files = NULL;
* lcf->client_body_path = NULL;
* lcf->regex = NULL;
* lcf->exact_match = 0;
@@ -2684,6 +2888,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t *cf)
lcf->client_body_buffer_size = NGX_CONF_UNSET_SIZE;
lcf->client_body_timeout = NGX_CONF_UNSET_MSEC;
lcf->satisfy = NGX_CONF_UNSET_UINT;
+ lcf->if_modified_since = NGX_CONF_UNSET_UINT;
lcf->internal = NGX_CONF_UNSET;
lcf->client_body_in_file_only = NGX_CONF_UNSET;
lcf->sendfile = NGX_CONF_UNSET;
@@ -2870,6 +3075,8 @@ ngx_http_core_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_conf_merge_uint_value(conf->satisfy, prev->satisfy,
NGX_HTTP_SATISFY_ALL);
+ ngx_conf_merge_uint_value(conf->if_modified_since, prev->if_modified_since,
+ NGX_HTTP_IMS_EXACT);
ngx_conf_merge_value(conf->internal, prev->internal, 0);
ngx_conf_merge_value(conf->client_body_in_file_only,
prev->client_body_in_file_only, 0);
@@ -3588,6 +3795,71 @@ ngx_http_core_error_page(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
static char *
+ngx_http_core_try_files(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ ngx_http_core_loc_conf_t *clcf = conf;
+
+ ngx_str_t *value;
+ ngx_uint_t i, n;
+ ngx_http_try_file_t *tf;
+ ngx_http_script_compile_t sc;
+ ngx_http_core_main_conf_t *cmcf;
+
+ if (clcf->try_files) {
+ return "is duplicate";
+ }
+
+ cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
+
+ cmcf->try_files = 1;
+
+ tf = ngx_pcalloc(cf->pool, cf->args->nelts * sizeof(ngx_http_try_file_t));
+ if (tf == NULL) {
+ return NGX_CONF_ERROR;
+ }
+
+ clcf->try_files = tf;
+
+ value = cf->args->elts;
+
+ for (i = 0; i < cf->args->nelts - 1; i++) {
+
+ tf[i].name = value[i + 1];
+
+ if (tf[i].name.data[tf[i].name.len - 1] == '/') {
+ tf[i].test_dir = 1;
+ tf[i].name.len--;
+ tf[i].name.data[tf[i].name.len] = '\0';
+ }
+
+ n = ngx_http_script_variables_count(&tf[i].name);
+
+ if (n) {
+ ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
+
+ sc.cf = cf;
+ sc.source = &tf[i].name;
+ sc.lengths = &tf[i].lengths;
+ sc.values = &tf[i].values;
+ sc.variables = n;
+ sc.complete_lengths = 1;
+ sc.complete_values = 1;
+
+ if (ngx_http_script_compile(&sc) != NGX_OK) {
+ return NGX_CONF_ERROR;
+ }
+
+ } else {
+ /* add trailing '\0' to length */
+ tf[i].name.len++;
+ }
+ }
+
+ return NGX_CONF_OK;
+}
+
+
+static char *
ngx_http_core_open_file_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *lcf = conf;
diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h
index bdc15d628..76d42150a 100644
--- a/src/http/ngx_http_core_module.h
+++ b/src/http/ngx_http_core_module.h
@@ -28,6 +28,11 @@
#define NGX_HTTP_SATISFY_ANY 1
+#define NGX_HTTP_IMS_OFF 0
+#define NGX_HTTP_IMS_EXACT 1
+#define NGX_HTTP_IMS_BEFORE 2
+
+
typedef struct {
unsigned default_server:1;
unsigned bind:1;
@@ -74,6 +79,7 @@ typedef enum {
NGX_HTTP_ACCESS_PHASE,
NGX_HTTP_POST_ACCESS_PHASE,
+ NGX_HTTP_TRY_FILES_PHASE,
NGX_HTTP_CONTENT_PHASE,
NGX_HTTP_LOG_PHASE
@@ -122,6 +128,8 @@ typedef struct {
ngx_hash_keys_arrays_t *variables_keys;
+ ngx_uint_t try_files; /* unsigned try_files:1 */
+
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;
@@ -231,6 +239,14 @@ typedef struct {
} ngx_http_err_page_t;
+typedef struct {
+ ngx_array_t *lengths;
+ ngx_array_t *values;
+ ngx_str_t name;
+ ngx_uint_t test_dir; /* unsigned test_dir:1; */
+} ngx_http_try_file_t;
+
+
typedef struct ngx_http_core_loc_conf_s ngx_http_core_loc_conf_t;
struct ngx_http_core_loc_conf_s {
@@ -292,6 +308,7 @@ struct ngx_http_core_loc_conf_s {
time_t keepalive_header; /* keepalive_timeout */
ngx_uint_t satisfy; /* satisfy */
+ ngx_uint_t if_modified_since; /* if_modified_since */
ngx_flag_t internal; /* internal */
ngx_flag_t client_body_in_file_only; /* client_body_in_file_only */
@@ -319,6 +336,7 @@ struct ngx_http_core_loc_conf_s {
#endif
ngx_array_t *error_pages; /* error_page */
+ ngx_http_try_file_t *try_files; /* try_files */
ngx_path_t *client_body_temp_path; /* client_body_temp_path */
@@ -350,6 +368,8 @@ ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
+ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r,
+ ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c
index 9777ebb98..7975361c4 100644
--- a/src/http/ngx_http_parse.c
+++ b/src/http/ngx_http_parse.c
@@ -1467,3 +1467,39 @@ ngx_http_parse_multi_header_lines(ngx_array_t *headers, ngx_str_t *name,
return NGX_DECLINED;
}
+
+
+void
+ngx_http_split_args(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args)
+{
+ u_char ch, *p, *last;
+
+ p = uri->data;
+
+ last = p + uri->len;
+
+ args->len = 0;
+
+ while (p < last) {
+
+ ch = *p++;
+
+ if (ch == '?') {
+ args->len = last - p;
+ args->data = p;
+
+ uri->len = p - 1 - uri->data;
+
+ if (ngx_strlchr(p, last, '\0') != NULL) {
+ r->zero_in_uri = 1;
+ }
+
+ return;
+ }
+
+ if (ch == '\0') {
+ r->zero_in_uri = 1;
+ continue;
+ }
+ }
+}
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 738c1fde9..f7c2ffa46 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -650,6 +650,7 @@ ngx_http_process_request_line(ngx_event_t *rev)
r->request_line.len = r->request_end - r->request_start;
r->request_line.data = r->request_start;
+ *r->request_end = '\0';
if (r->args_start) {
@@ -1387,9 +1388,7 @@ ngx_http_process_request_header(ngx_http_request_t *r)
}
}
- if (r->method & (NGX_HTTP_POST|NGX_HTTP_PUT)
- && r->headers_in.content_length_n == -1)
- {
+ if (r->method & NGX_HTTP_PUT && r->headers_in.content_length_n == -1) {
ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
"client sent %V method without \"Content-Length\" header",
&r->method_name);
@@ -2091,6 +2090,7 @@ ngx_http_set_keepalive(ngx_http_request_t *r)
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "set http keepalive handler");
if (r->discard_body) {
+ r->write_event_handler = ngx_http_request_empty_handler;
r->lingering_time = ngx_time() + (time_t) (clcf->lingering_time / 1000);
ngx_add_timer(rev, clcf->lingering_timeout);
return;
@@ -2264,8 +2264,15 @@ ngx_http_set_keepalive(ngx_http_request_t *r)
(const void *) &tcp_nodelay, sizeof(int))
== -1)
{
+#if (NGX_SOLARIS)
+ /* Solaris returns EINVAL if a socket has been shut down */
+ c->log_error = NGX_ERROR_IGNORE_EINVAL;
+#endif
+
ngx_connection_error(c, ngx_socket_errno,
"setsockopt(TCP_NODELAY) failed");
+
+ c->log_error = NGX_ERROR_INFO;
ngx_http_close_connection(c);
return;
}
diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c
index acd867fdb..fc980f4b0 100644
--- a/src/http/ngx_http_script.c
+++ b/src/http/ngx_http_script.c
@@ -244,10 +244,21 @@ ngx_http_script_compile(ngx_http_script_compile_t *sc)
name.data = &sc->source->data[i];
- while (i < sc->source->len
- && sc->source->data[i] != '$'
- && !(sc->source->data[i] == '?' && sc->compile_args))
- {
+ while (i < sc->source->len) {
+
+ if (sc->source->data[i] == '$') {
+ break;
+ }
+
+ if (sc->source->data[i] == '?') {
+
+ sc->args = 1;
+
+ if (sc->compile_args) {
+ break;
+ }
+ }
+
i++;
name.len++;
}
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index bb235db8a..0f9700967 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -1099,62 +1099,59 @@ ngx_http_upstream_process_header(ngx_event_t *rev)
#endif
}
- n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
+ for ( ;; ) {
+
+ n = c->recv(c, u->buffer.last, u->buffer.end - u->buffer.last);
- if (n == NGX_AGAIN) {
+ if (n == NGX_AGAIN) {
#if 0
- ngx_add_timer(rev, u->read_timeout);
+ ngx_add_timer(rev, u->read_timeout);
#endif
- if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u,
+ if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
+ ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
+ return;
+ }
+
return;
}
- return;
- }
-
- if (n == 0) {
- ngx_log_error(NGX_LOG_ERR, rev->log, 0,
- "upstream prematurely closed connection");
- }
+ if (n == 0) {
+ ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+ "upstream prematurely closed connection");
+ }
- if (n == NGX_ERROR || n == 0) {
- ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
- return;
- }
+ if (n == NGX_ERROR || n == 0) {
+ ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_ERROR);
+ return;
+ }
- u->buffer.last += n;
+ u->buffer.last += n;
#if 0
- u->valid_header_in = 0;
+ u->valid_header_in = 0;
- u->peer.cached = 0;
+ u->peer.cached = 0;
#endif
- rc = u->process_header(r);
+ rc = u->process_header(r);
- if (rc == NGX_AGAIN) {
-#if 0
- ngx_add_timer(rev, u->read_timeout);
-#endif
+ if (rc == NGX_AGAIN) {
- if (u->buffer.pos == u->buffer.end) {
- ngx_log_error(NGX_LOG_ERR, rev->log, 0,
- "upstream sent too big header");
+ if (u->buffer.pos == u->buffer.end) {
+ ngx_log_error(NGX_LOG_ERR, rev->log, 0,
+ "upstream sent too big header");
- ngx_http_upstream_next(r, u, NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
- return;
- }
+ ngx_http_upstream_next(r, u,
+ NGX_HTTP_UPSTREAM_FT_INVALID_HEADER);
+ return;
+ }
- if (ngx_handle_read_event(rev, 0) == NGX_ERROR) {
- ngx_http_upstream_finalize_request(r, u,
- NGX_HTTP_INTERNAL_SERVER_ERROR);
- return;
+ continue;
}
- return;
+ break;
}
if (rc == NGX_HTTP_UPSTREAM_INVALID_HEADER) {
@@ -1962,6 +1959,7 @@ ngx_http_upstream_process_downstream(ngx_http_request_t *r)
static void
ngx_http_upstream_process_body(ngx_event_t *ev)
{
+ ngx_uint_t del;
ngx_temp_file_t *tf;
ngx_event_pipe_t *p;
ngx_connection_t *c, *downstream;
@@ -2057,20 +2055,25 @@ ngx_http_upstream_process_body(ngx_event_t *ev)
if (u->store) {
+ del = p->upstream_error;
+
tf = u->pipe->temp_file;
- if (p->upstream_eof
- && u->headers_in.status_n == NGX_HTTP_OK
- && (u->headers_in.content_length_n == -1
- || (u->headers_in.content_length_n == tf->offset)))
- {
- ngx_http_upstream_store(r, u);
+ if (p->upstream_eof || p->upstream_done) {
+
+ if (u->headers_in.status_n == NGX_HTTP_OK
+ && (u->headers_in.content_length_n == -1
+ || (u->headers_in.content_length_n == tf->offset)))
+ {
+ ngx_http_upstream_store(r, u);
+
+ } else {
+ del = 1;
+ }
+ }
+
+ if (del && tf->file.fd != NGX_INVALID_FILE) {
- } else if ((p->upstream_error
- || (p->upstream_eof
- && u->headers_in.status_n != NGX_HTTP_OK))
- && tf->file.fd != NGX_INVALID_FILE)
- {
if (ngx_delete_file(tf->file.name.data) == NGX_FILE_ERROR) {
ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c
index 16f092305..9f6e2d166 100644
--- a/src/http/ngx_http_variables.c
+++ b/src/http/ngx_http_variables.c
@@ -26,6 +26,10 @@ static ngx_int_t ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_cookie(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
+static ngx_int_t ngx_http_variable_argument(ngx_http_request_t *r,
+ ngx_http_variable_value_t *v, uintptr_t data);
static ngx_int_t ngx_http_variable_host(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data);
@@ -481,6 +485,24 @@ ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key,
return NULL;
}
+ if (ngx_strncmp(name->data, "cookie_", 7) == 0) {
+
+ if (ngx_http_variable_cookie(r, vv, (uintptr_t) name) == NGX_OK) {
+ return vv;
+ }
+
+ return NULL;
+ }
+
+ if (ngx_strncmp(name->data, "arg_", 4) == 0) {
+
+ if (ngx_http_variable_argument(r, vv, (uintptr_t) name) == NGX_OK) {
+ return vv;
+ }
+
+ return NULL;
+ }
+
vv->not_found = 1;
if (nowarn == 0) {
@@ -712,6 +734,90 @@ ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var,
static ngx_int_t
+ngx_http_variable_cookie(ngx_http_request_t *r, ngx_http_variable_value_t *v,
+ uintptr_t data)
+{
+ ngx_str_t *name = (ngx_str_t *) data;
+
+ ngx_str_t cookie, s;
+
+ s.len = name->len - (sizeof("cookie_") - 1);
+ s.data = name->data + sizeof("cookie_") - 1;
+
+ if (ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &s, &cookie)
+ == NGX_DECLINED)
+ {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ v->len = cookie.len;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+ v->data = cookie.data;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
+ngx_http_variable_argument(ngx_http_request_t *r, ngx_http_variable_value_t *v,
+ uintptr_t data)
+{
+ ngx_str_t *name = (ngx_str_t *) data;
+
+ u_char *p, *arg;
+ size_t len;
+
+ if (r->args.len == 0) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ len = name->len - 1 - (sizeof("arg_") - 1);
+ arg = name->data + sizeof("arg_") - 1;
+
+ for (p = r->args.data; *p && *p != ' '; p++) {
+
+ /*
+ * although r->args.data is not null-terminated by itself,
+ * however, there is null in the end of request line
+ */
+
+ p = ngx_strcasestrn(p, (char *) arg, len);
+
+ if (p == NULL) {
+ v->not_found = 1;
+ return NGX_OK;
+ }
+
+ if ((p == r->args.data || *(p - 1) == '&') && *(p + len + 1) == '=') {
+
+ v->data = p + len + 2;
+
+ p = (u_char *) ngx_strchr(p, '&');
+
+ if (p == NULL) {
+ p = r->args.data + r->args.len;
+ }
+
+ v->len = p - v->data;
+ v->valid = 1;
+ v->no_cacheable = 0;
+ v->not_found = 0;
+
+ return NGX_OK;
+ }
+ }
+
+ v->not_found = 1;
+
+ return NGX_OK;
+}
+
+
+static ngx_int_t
ngx_http_variable_host(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
@@ -1396,6 +1502,20 @@ ngx_http_variables_init_vars(ngx_conf_t *cf)
continue;
}
+ if (ngx_strncmp(v[i].name.data, "cookie_", 7) == 0) {
+ v[i].get_handler = ngx_http_variable_cookie;
+ v[i].data = (uintptr_t) &v[i].name;
+
+ continue;
+ }
+
+ if (ngx_strncmp(v[i].name.data, "arg_", 4) == 0) {
+ v[i].get_handler = ngx_http_variable_argument;
+ v[i].data = (uintptr_t) &v[i].name;
+
+ continue;
+ }
+
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unknown \"%V\" variable", &v[i].name);
diff --git a/src/mail/ngx_mail_smtp_handler.c b/src/mail/ngx_mail_smtp_handler.c
index 6e944738f..307ec697d 100644
--- a/src/mail/ngx_mail_smtp_handler.c
+++ b/src/mail/ngx_mail_smtp_handler.c
@@ -12,6 +12,7 @@
static void ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx);
+static void ngx_mail_smtp_resolve_name(ngx_event_t *rev);
static void ngx_mail_smtp_resolve_name_handler(ngx_resolver_ctx_t *ctx);
static void ngx_mail_smtp_greeting(ngx_mail_session_t *s, ngx_connection_t *c);
static void ngx_mail_smtp_invalid_pipelining(ngx_event_t *rev);
@@ -88,9 +89,8 @@ ngx_mail_smtp_init_session(ngx_mail_session_t *s, ngx_connection_t *c)
static void
ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx)
{
- ngx_connection_t *c;
- ngx_mail_session_t *s;
- ngx_mail_core_srv_conf_t *cscf;
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
s = ctx->data;
c = s->connection;
@@ -131,6 +131,23 @@ ngx_mail_smtp_resolve_addr_handler(ngx_resolver_ctx_t *ctx)
ngx_log_debug1(NGX_LOG_DEBUG_MAIL, c->log, 0,
"address resolved: %V", &s->host);
+ c->read->handler = ngx_mail_smtp_resolve_name;
+
+ ngx_post_event(c->read, &ngx_posted_events);
+}
+
+
+static void
+ngx_mail_smtp_resolve_name(ngx_event_t *rev)
+{
+ ngx_connection_t *c;
+ ngx_mail_session_t *s;
+ ngx_resolver_ctx_t *ctx;
+ ngx_mail_core_srv_conf_t *cscf;
+
+ c = rev->data;
+ s = c->data;
+
cscf = ngx_mail_get_module_srv_conf(s, ngx_mail_core_module);
ctx = ngx_resolve_start(cscf->resolver, NULL);
diff --git a/src/os/unix/ngx_errno.c b/src/os/unix/ngx_errno.c
index a3addf00c..a250f496d 100644
--- a/src/os/unix/ngx_errno.c
+++ b/src/os/unix/ngx_errno.c
@@ -10,10 +10,11 @@
#if (NGX_HAVE_STRERROR_R)
-u_char *ngx_strerror_r(int err, u_char *errstr, size_t size)
+u_char *
+ngx_strerror_r(int err, u_char *errstr, size_t size)
{
if (size == 0) {
- return 0;
+ return errstr;
}
errstr[0] = '\0';
@@ -32,12 +33,13 @@ u_char *ngx_strerror_r(int err, u_char *errstr, size_t size)
/* Linux strerror_r() */
-u_char *ngx_strerror_r(int err, u_char *errstr, size_t size)
+u_char *
+ngx_strerror_r(int err, u_char *errstr, size_t size)
{
char *str;
if (size == 0) {
- return 0;
+ return errstr;
}
errstr[0] = '\0';
diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c
index ca3eae108..18b2601af 100644
--- a/src/os/unix/ngx_process.c
+++ b/src/os/unix/ngx_process.c
@@ -494,10 +494,16 @@ ngx_process_get_status(void)
}
if (WTERMSIG(status)) {
+#ifdef WCOREDUMP
ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
"%s %P exited on signal %d%s",
process, pid, WTERMSIG(status),
WCOREDUMP(status) ? " (core dumped)" : "");
+#else
+ ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0,
+ "%s %P exited on signal %d",
+ process, pid, WTERMSIG(status));
+#endif
} else {
ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0,