summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIgor Sysoev <igor@sysoev.ru>2007-07-12 11:23:11 +0000
committerJonathan Kolb <jon@b0g.us>2007-07-12 11:23:11 +0000
commit7f4fcbdaef8d52d0a390c980cb1a7fa85330fecc (patch)
treece4ffa8a6ed6f7c06b2117868c85f9c586dd4c0c
parent8aa92bfd2642d24b664564c39290185efe1ed670 (diff)
downloadnginx-7f4fcbdaef8d52d0a390c980cb1a7fa85330fecc.tar.gz
Changes with nginx 0.6.3 12 Jul 2007v0.6.3
*) Feature: the "proxy_store" and "fastcgi_store" directives. *) Bugfix: a segmentation fault might occur in worker process if the "auth_http_header" directive was used. *) Bugfix: a segmentation fault occurred in worker process if the CRAM-MD5 authentication method was used, but it was not enabled. *) Bugfix: a segmentation fault might occur in worker process when the HTTPS protocol was used in the "proxy_pass" directive. *) Bugfix: a segmentation fault might occur in worker process if the eventport method was used. *) Bugfix: the "proxy_ignore_client_abort" and "fastcgi_ignore_client_abort" directives did not work; bug appeared in 0.5.13.
-rw-r--r--CHANGES23
-rw-r--r--CHANGES.ru20
-rw-r--r--src/core/nginx.c4
-rw-r--r--src/core/nginx.h2
-rw-r--r--src/core/ngx_file.c66
-rw-r--r--src/core/ngx_file.h1
-rw-r--r--src/event/modules/ngx_eventport_module.c4
-rw-r--r--src/event/ngx_event_connect.h48
-rw-r--r--src/http/modules/ngx_http_dav_module.c4
-rw-r--r--src/http/modules/ngx_http_fastcgi_module.c11
-rw-r--r--src/http/modules/ngx_http_proxy_module.c11
-rw-r--r--src/http/modules/ngx_http_upstream_ip_hash_module.c3
-rw-r--r--src/http/modules/perl/nginx.pm2
-rw-r--r--src/http/ngx_http_request.c25
-rw-r--r--src/http/ngx_http_request_body.c1
-rw-r--r--src/http/ngx_http_upstream.c169
-rw-r--r--src/http/ngx_http_upstream.h2
-rw-r--r--src/http/ngx_http_upstream_round_robin.c59
-rw-r--r--src/http/ngx_http_upstream_round_robin.h7
-rw-r--r--src/mail/ngx_mail_auth_http_module.c1
-rw-r--r--src/mail/ngx_mail_handler.c13
21 files changed, 427 insertions, 49 deletions
diff --git a/CHANGES b/CHANGES
index d053b0e20..8ee8b4c8d 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,4 +1,25 @@
+Changes with nginx 0.6.3 12 Jul 2007
+
+ *) Feature: the "proxy_store" and "fastcgi_store" directives.
+
+ *) Bugfix: a segmentation fault might occur in worker process if the
+ "auth_http_header" directive was used.
+
+ *) Bugfix: a segmentation fault occurred in worker process if the
+ CRAM-MD5 authentication method was used, but it was not enabled.
+
+ *) Bugfix: a segmentation fault might occur in worker process when the
+ HTTPS protocol was used in the "proxy_pass" directive.
+
+ *) Bugfix: a segmentation fault might occur in worker process if the
+ eventport method was used.
+
+ *) Bugfix: the "proxy_ignore_client_abort" and
+ "fastcgi_ignore_client_abort" directives did not work; bug appeared
+ in 0.5.13.
+
+
Changes with nginx 0.6.2 09 Jul 2007
*) Bugfix: if the FastCGI header was split in records, then nginx
@@ -227,7 +248,7 @@ Changes with nginx 0.5.13 19 Feb 2007
send timeout only.
*) Bugfix: nginx could not be built on platforms different from i386,
- amd64, sparc и ppc; bug appeared in 0.5.8.
+ amd64, sparc and ppc; bug appeared in 0.5.8.
Changes with nginx 0.5.12 12 Feb 2007
diff --git a/CHANGES.ru b/CHANGES.ru
index 356178611..ed95f68d2 100644
--- a/CHANGES.ru
+++ b/CHANGES.ru
@@ -1,4 +1,24 @@
+Изменения в nginx 0.6.3 12.07.2007
+
+ *) Добавление: директивы proxy_store и fastcgi_store.
+
+ *) Исправление: при использовании директивы auth_http_header в рабочем
+ процессе мог произойти segmentation fault.
+
+ *) Исправление: если использовался метод аутентификации CRAM-MD5, но он
+ не был разрешён, то в рабочем процессе происходил segmentation fault.
+
+ *) Исправление: при использовании протокола HTTPS в директиве
+ proxy_pass в рабочем процессе мог произойти segmentation fault.
+
+ *) Исправление: в рабочем процессе мог произойти segmentation fault,
+ если использовался метод eventport.
+
+ *) Исправление: директивы proxy_ignore_client_abort и
+ fastcgi_ignore_client_abort не работали; ошибка появилась в 0.5.13.
+
+
Изменения в nginx 0.6.2 09.07.2007
*) Исправление: если заголовок ответа был разделён в FastCGI-записях,
diff --git a/src/core/nginx.c b/src/core/nginx.c
index 357b1b9cd..df6c72cfd 100644
--- a/src/core/nginx.c
+++ b/src/core/nginx.c
@@ -796,6 +796,7 @@ ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf)
if (ccf->user == (uid_t) NGX_CONF_UNSET_UINT && geteuid() == 0) {
+ ngx_set_errno(0);
pwd = getpwnam(NGX_USER);
if (pwd == NULL) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
@@ -806,6 +807,7 @@ ngx_core_module_init_conf(ngx_cycle_t *cycle, void *conf)
ccf->username = NGX_USER;
ccf->user = pwd->pw_uid;
+ ngx_set_errno(0);
grp = getgrnam(NGX_GROUP);
if (grp == NULL) {
ngx_log_error(NGX_LOG_EMERG, cycle->log, ngx_errno,
@@ -920,6 +922,7 @@ ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
ccf->username = (char *) value[1].data;
+ ngx_set_errno(0);
pwd = getpwnam((const char *) value[1].data);
if (pwd == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
@@ -931,6 +934,7 @@ ngx_set_user(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
group = (char *) ((cf->args->nelts == 2) ? value[1].data : value[2].data);
+ ngx_set_errno(0);
grp = getgrnam(group);
if (grp == NULL) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
diff --git a/src/core/nginx.h b/src/core/nginx.h
index 8a99384e8..5c52e36c2 100644
--- a/src/core/nginx.h
+++ b/src/core/nginx.h
@@ -8,7 +8,7 @@
#define _NGINX_H_INCLUDED_
-#define NGINX_VERSION "0.6.2"
+#define NGINX_VERSION "0.6.3"
#define NGINX_VER "nginx/" NGINX_VERSION
#define NGINX_VAR "NGINX"
diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c
index cef4dc1b8..656610dc8 100644
--- a/src/core/ngx_file.c
+++ b/src/core/ngx_file.c
@@ -293,6 +293,72 @@ ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
}
+char *
+ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
+{
+ char *confp = conf;
+
+ u_char *p;
+ ngx_str_t *value;
+ ngx_uint_t i, right, shift, *access;
+
+ access = (ngx_uint_t *) (confp + cmd->offset);
+
+ if (*access != NGX_CONF_UNSET_UINT) {
+ return "is duplicate";
+ }
+
+ value = cf->args->elts;
+
+ *access = 0600;
+
+ for (i = 1; i < cf->args->nelts; i++) {
+
+ p = value[i].data;
+
+ if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) {
+ shift = 6;
+ p += sizeof("user:") - 1;
+
+ } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) {
+ shift = 3;
+ p += sizeof("group:") - 1;
+
+ } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) {
+ shift = 0;
+ p += sizeof("all:") - 1;
+
+ } else if (ngx_strncmp(p, "off", sizeof("off") - 1) == 0) {
+ *access = 0;
+ return NGX_CONF_OK;
+
+ } else {
+ goto invalid;
+ }
+
+ if (ngx_strcmp(p, "rw") == 0) {
+ right = 6;
+
+ } else if (ngx_strcmp(p, "r") == 0) {
+ right = 4;
+
+ } else {
+ goto invalid;
+ }
+
+ *access |= right << shift;
+ }
+
+ return NGX_CONF_OK;
+
+invalid:
+
+ ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "invalid value \"%V\"", &value[i]);
+
+ return NGX_CONF_ERROR;
+}
+
+
ngx_int_t
ngx_add_path(ngx_conf_t *cf, ngx_path_t **slot)
{
diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h
index e42489d8d..0f819a1b8 100644
--- a/src/core/ngx_file.h
+++ b/src/core/ngx_file.h
@@ -95,6 +95,7 @@ void ngx_init_temp_number(void);
ngx_atomic_uint_t ngx_next_temp_number(ngx_uint_t collision);
char *ngx_conf_set_path_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
+char *ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_command_t *cmd, void *conf);
#define ngx_conf_merge_path_value(curr, prev, path, l1, l2, l3, clean, cf) \
diff --git a/src/event/modules/ngx_eventport_module.c b/src/event/modules/ngx_eventport_module.c
index bd046edbb..0abb2eec1 100644
--- a/src/event/modules/ngx_eventport_module.c
+++ b/src/event/modules/ngx_eventport_module.c
@@ -514,6 +514,10 @@ ngx_eventport_process_events(ngx_cycle_t *cycle, ngx_msec_t timer,
} else {
rev->handler(rev);
+
+ if (ev->closed) {
+ continue;
+ }
}
if (rev->accept) {
diff --git a/src/event/ngx_event_connect.h b/src/event/ngx_event_connect.h
index f8a7de944..6cad04279 100644
--- a/src/event/ngx_event_connect.h
+++ b/src/event/ngx_event_connect.h
@@ -13,50 +13,56 @@
#include <ngx_event.h>
-#define NGX_PEER_KEEPALIVE 1
-#define NGX_PEER_NEXT 2
-#define NGX_PEER_FAILED 4
+#define NGX_PEER_KEEPALIVE 1
+#define NGX_PEER_NEXT 2
+#define NGX_PEER_FAILED 4
typedef struct ngx_peer_connection_s ngx_peer_connection_t;
typedef ngx_int_t (*ngx_event_get_peer_pt)(ngx_peer_connection_t *pc,
void *data);
-#if (NGX_SSL)
-typedef void (*ngx_event_save_peer_pt)(ngx_peer_connection_t *pc, void *data);
-#endif
typedef void (*ngx_event_free_peer_pt)(ngx_peer_connection_t *pc, void *data,
ngx_uint_t state);
+#if (NGX_SSL)
+
+typedef ngx_int_t (*ngx_event_set_peer_session_pt)(ngx_peer_connection_t *pc,
+ void *data);
+typedef void (*ngx_event_save_peer_session_pt)(ngx_peer_connection_t *pc,
+ void *data);
+#endif
struct ngx_peer_connection_s {
- ngx_connection_t *connection;
+ ngx_connection_t *connection;
- struct sockaddr *sockaddr;
- socklen_t socklen;
- ngx_str_t *name;
+ struct sockaddr *sockaddr;
+ socklen_t socklen;
+ ngx_str_t *name;
- ngx_uint_t tries;
+ ngx_uint_t tries;
- ngx_event_get_peer_pt get;
- ngx_event_free_peer_pt free;
- void *data;
+ ngx_event_get_peer_pt get;
+ ngx_event_free_peer_pt free;
+ void *data;
#if (NGX_SSL)
- ngx_ssl_session_t *ssl_session;
- ngx_event_save_peer_pt save_session;
+ ngx_event_set_peer_session_pt set_session;
+ ngx_event_save_peer_session_pt save_session;
#endif
#if (NGX_THREADS)
- ngx_atomic_t *lock;
+ ngx_atomic_t *lock;
#endif
- int rcvbuf;
+ int rcvbuf;
+
+ ngx_log_t *log;
- ngx_log_t *log;
+ unsigned cached:1;
- unsigned cached:1;
- unsigned log_error:2; /* ngx_connection_log_error_e */
+ /* ngx_connection_log_error_e */
+ unsigned log_error:2;
};
diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c
index 9fab59bf7..5539f6195 100644
--- a/src/http/modules/ngx_http_dav_module.c
+++ b/src/http/modules/ngx_http_dav_module.c
@@ -239,9 +239,7 @@ ngx_http_dav_put_handler(ngx_http_request_t *r)
#if !(NGX_WIN32)
- if (ngx_change_file_access(temp->data, dlcf->access)
- == NGX_FILE_ERROR)
- {
+ if (ngx_change_file_access(temp->data, dlcf->access) == NGX_FILE_ERROR) {
err = ngx_errno;
not_found = NGX_HTTP_INTERNAL_SERVER_ERROR;
failed = ngx_change_file_access_n;
diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c
index 246574b13..dc4a85cce 100644
--- a/src/http/modules/ngx_http_fastcgi_module.c
+++ b/src/http/modules/ngx_http_fastcgi_module.c
@@ -200,6 +200,13 @@ static ngx_command_t ngx_http_fastcgi_commands[] = {
offsetof(ngx_http_fastcgi_loc_conf_t, index),
NULL },
+ { ngx_string("fastcgi_store"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+ ngx_conf_set_access_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store),
+ NULL },
+
{ ngx_string("fastcgi_ignore_client_abort"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -1633,6 +1640,7 @@ ngx_http_fastcgi_create_loc_conf(ngx_conf_t *cf)
* conf->index.data = NULL;
*/
+ conf->upstream.store = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
@@ -1677,6 +1685,9 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_script_compile_t sc;
ngx_http_script_copy_code_t *copy;
+ ngx_conf_merge_uint_value(conf->upstream.store,
+ prev->upstream.store, 0);
+
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
diff --git a/src/http/modules/ngx_http_proxy_module.c b/src/http/modules/ngx_http_proxy_module.c
index 3ea8006fe..d77e183a3 100644
--- a/src/http/modules/ngx_http_proxy_module.c
+++ b/src/http/modules/ngx_http_proxy_module.c
@@ -154,6 +154,13 @@ static ngx_command_t ngx_http_proxy_commands[] = {
0,
NULL },
+ { ngx_string("proxy_store"),
+ NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123,
+ ngx_conf_set_access_slot,
+ NGX_HTTP_LOC_CONF_OFFSET,
+ offsetof(ngx_http_proxy_loc_conf_t, upstream.store),
+ NULL },
+
{ ngx_string("proxy_buffering"),
NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG,
ngx_conf_set_flag_slot,
@@ -1502,6 +1509,7 @@ ngx_http_proxy_create_loc_conf(ngx_conf_t *cf)
* conf->rewrite_locations = NULL;
*/
+ conf->upstream.store = NGX_CONF_UNSET_UINT;
conf->upstream.buffering = NGX_CONF_UNSET;
conf->upstream.ignore_client_abort = NGX_CONF_UNSET;
@@ -1553,6 +1561,9 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child)
ngx_http_script_compile_t sc;
ngx_http_script_copy_code_t *copy;
+ ngx_conf_merge_uint_value(conf->upstream.store,
+ prev->upstream.store, 0);
+
ngx_conf_merge_value(conf->upstream.buffering,
prev->upstream.buffering, 1);
diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
index ba1cd53ff..3ef424921 100644
--- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
+++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
@@ -198,9 +198,6 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
pc->sockaddr = peer->sockaddr;
pc->socklen = peer->socklen;
pc->name = &peer->name;
-#if (NGX_SSL)
- pc->ssl_session = peer->ssl_session;
-#endif
/* ngx_unlock_mutex(iphp->rrp.peers->mutex); */
diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm
index 5cab67d3a..a9e9837d4 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.2';
+our $VERSION = '0.6.3';
require XSLoader;
XSLoader::load('nginx', $VERSION);
diff --git a/src/http/ngx_http_request.c b/src/http/ngx_http_request.c
index 66381e031..21812e636 100644
--- a/src/http/ngx_http_request.c
+++ b/src/http/ngx_http_request.c
@@ -34,6 +34,7 @@ static ngx_int_t ngx_http_set_write_handler(ngx_http_request_t *r);
static void ngx_http_writer(ngx_http_request_t *r);
static void ngx_http_block_read(ngx_http_request_t *r);
+static void ngx_http_test_read(ngx_http_request_t *r);
static void ngx_http_set_keepalive(ngx_http_request_t *r);
static void ngx_http_keepalive_handler(ngx_event_t *ev);
static void ngx_http_set_lingering_close(ngx_http_request_t *r);
@@ -1701,7 +1702,7 @@ ngx_http_set_write_handler(ngx_http_request_t *r)
r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
- r->read_event_handler = ngx_http_block_read;
+ r->read_event_handler = ngx_http_test_read;
r->write_event_handler = ngx_http_writer;
wev = r->connection->write;
@@ -1814,6 +1815,26 @@ ngx_http_writer(ngx_http_request_t *r)
static void
ngx_http_block_read(ngx_http_request_t *r)
{
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "http read blocked");
+
+ /* aio does not call this handler */
+
+ if ((ngx_event_flags & NGX_USE_LEVEL_EVENT)
+ && r->connection->read->active)
+ {
+ if (ngx_del_event(r->connection->read, NGX_READ_EVENT, 0)
+ == NGX_ERROR)
+ {
+ ngx_http_close_request(r, 0);
+ }
+ }
+}
+
+
+static void
+ngx_http_test_read(ngx_http_request_t *r)
+{
int n;
char buf[1];
ngx_err_t err;
@@ -1823,7 +1844,7 @@ ngx_http_block_read(ngx_http_request_t *r)
c = r->connection;
rev = c->read;
- ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http read blocked");
+ ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http test read");
#if (NGX_HAVE_KQUEUE)
diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c
index bfdc8e443..494f48416 100644
--- a/src/http/ngx_http_request_body.c
+++ b/src/http/ngx_http_request_body.c
@@ -88,6 +88,7 @@ ngx_http_read_client_request_body(ngx_http_request_t *r,
}
post_handler(r);
+
return NGX_OK;
}
diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c
index c1bae266c..bf892fcd6 100644
--- a/src/http/ngx_http_upstream.c
+++ b/src/http/ngx_http_upstream.c
@@ -33,6 +33,8 @@ static ngx_int_t ngx_http_upstream_non_buffered_filter(void *data,
ssize_t bytes);
static void ngx_http_upstream_process_downstream(ngx_http_request_t *r);
static void ngx_http_upstream_process_body(ngx_event_t *ev);
+static void ngx_http_upstream_store(ngx_http_request_t *r,
+ ngx_http_upstream_t *u);
static void ngx_http_upstream_dummy_handler(ngx_event_t *wev);
static void ngx_http_upstream_next(ngx_http_request_t *r,
ngx_http_upstream_t *u, ngx_uint_t ft_type);
@@ -116,6 +118,12 @@ ngx_http_upstream_header_t ngx_http_upstream_headers_in[] = {
ngx_http_upstream_copy_header_line,
offsetof(ngx_http_headers_out_t, date), 0 },
+ { ngx_string("Last-Modified"),
+ ngx_http_upstream_process_header_line,
+ offsetof(ngx_http_upstream_headers_in_t, last_modified),
+ ngx_http_upstream_copy_header_line,
+ offsetof(ngx_http_headers_out_t, last_modified), 0 },
+
{ ngx_string("Server"),
ngx_http_upstream_process_header_line,
offsetof(ngx_http_upstream_headers_in_t, server),
@@ -364,6 +372,8 @@ ngx_http_upstream_init(ngx_http_request_t *r)
cln->data = r;
u->cleanup = &cln->handler;
+ u->store = (u->conf->store != 0);
+
ngx_http_upstream_connect(r, u);
}
@@ -424,7 +434,7 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
ev->error = 1;
}
- if (!u->cachable && u->peer.connection) {
+ if (!u->cachable && !u->store && u->peer.connection) {
ngx_log_error(NGX_LOG_INFO, ev->log, ev->kq_errno,
"kevent() reported that client closed prematurely "
"connection, so upstream connection is closed too");
@@ -490,7 +500,7 @@ ngx_http_upstream_check_broken_connection(ngx_http_request_t *r,
ev->eof = 1;
c->error = 1;
- if (!u->cachable && u->peer.connection) {
+ if (!u->cachable && !u->store && u->peer.connection) {
ngx_log_error(NGX_LOG_INFO, ev->log, err,
"client closed prematurely connection, "
"so upstream connection is closed too");
@@ -657,7 +667,7 @@ ngx_http_upstream_ssl_init_connection(ngx_http_request_t *r,
c->sendfile = 0;
u->output.sendfile = 0;
- if (ngx_ssl_set_session(c, u->peer.ssl_session) != NGX_OK) {
+ if (u->peer.set_session(&u->peer, u->peer.data) != NGX_OK) {
ngx_http_upstream_finalize_request(r, u,
NGX_HTTP_INTERNAL_SERVER_ERROR);
return;
@@ -1523,7 +1533,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->pool = r->pool;
p->log = c->log;
- p->cachable = u->cachable;
+ p->cachable = u->cachable || u->store;
p->temp_file = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
if (p->temp_file == NULL) {
@@ -1536,8 +1546,9 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->temp_file->path = u->conf->temp_path;
p->temp_file->pool = r->pool;
- if (u->cachable) {
+ if (u->cachable || u->store) {
p->temp_file->persistent = 1;
+
} else {
p->temp_file->log_level = NGX_LOG_WARN;
p->temp_file->warn = "an upstream response is buffered "
@@ -1552,6 +1563,7 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
+
p->preread_bufs->buf = &u->buffer;
p->preread_bufs->next = NULL;
u->buffer.recycled = 1;
@@ -1559,11 +1571,13 @@ ngx_http_upstream_send_response(ngx_http_request_t *r, ngx_http_upstream_t *u)
p->preread_size = u->buffer.last - u->buffer.pos;
if (u->cachable) {
+
p->buf_to_file = ngx_calloc_buf(r->pool);
if (p->buf_to_file == NULL) {
ngx_http_upstream_finalize_request(r, u, 0);
return;
}
+
p->buf_to_file->pos = u->buffer.start;
p->buf_to_file->last = u->buffer.pos;
p->buf_to_file->temporary = 1;
@@ -1910,6 +1924,27 @@ ngx_http_upstream_process_body(ngx_event_t *ev)
if (u->peer.connection) {
+ if (u->store) {
+
+ if (p->upstream_eof && u->headers_in.status_n == NGX_HTTP_OK) {
+
+ ngx_http_upstream_store(r, u);
+
+ } else if ((p->upstream_error
+ || (p->upstream_eof
+ && u->headers_in.status_n != NGX_HTTP_OK))
+ && u->pipe->temp_file->file.fd != NGX_INVALID_FILE)
+ {
+ if (ngx_delete_file(u->pipe->temp_file->file.name.data)
+ == NGX_FILE_ERROR)
+ {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed",
+ u->pipe->temp_file->file.name.data);
+ }
+ }
+ }
+
#if (NGX_HTTP_FILE_CACHE)
if (p->upstream_done && u->cachable) {
@@ -1955,6 +1990,130 @@ ngx_http_upstream_process_body(ngx_event_t *ev)
static void
+ngx_http_upstream_store(ngx_http_request_t *r, ngx_http_upstream_t *u)
+{
+ char *failed;
+ u_char *name;
+ size_t root;
+ time_t lm;
+ ngx_err_t err;
+ ngx_str_t *temp, path, *last_modified;
+ ngx_temp_file_t *tf;
+
+ if (u->pipe->temp_file->file.fd == NGX_INVALID_FILE) {
+
+ /* create file for empty 200 response */
+
+ tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
+ if (tf == NULL) {
+ return;
+ }
+
+ tf->file.fd = NGX_INVALID_FILE;
+ tf->file.log = r->connection->log;
+ tf->path = u->conf->temp_path;
+ tf->pool = r->pool;
+ tf->persistent = 1;
+
+ if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
+ tf->persistent, tf->clean, tf->access)
+ != NGX_OK)
+ {
+ return;
+ }
+
+ u->pipe->temp_file = tf;
+ }
+
+ temp = &u->pipe->temp_file->file.name;
+
+#if !(NGX_WIN32)
+
+ if (ngx_change_file_access(temp->data, u->conf->store) == NGX_FILE_ERROR) {
+ err = ngx_errno;
+ failed = ngx_change_file_access_n;
+ name = temp->data;
+
+ goto failed;
+ }
+
+#endif
+
+ if (r->upstream->headers_in.last_modified) {
+
+ last_modified = &r->upstream->headers_in.last_modified->value;
+
+ lm = ngx_http_parse_time(last_modified->data, last_modified->len);
+
+ if (lm != NGX_ERROR) {
+ if (ngx_set_file_time(temp->data, u->pipe->temp_file->file.fd, lm)
+ != NGX_OK)
+ {
+ err = ngx_errno;
+ failed = ngx_set_file_time_n;
+ name = temp->data;
+
+ goto failed;
+ }
+ }
+ }
+
+ ngx_http_map_uri_to_path(r, &path, &root, 0);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
+ "upstream stores \"%s\" to \"%s\"", temp->data, path.data);
+
+ failed = ngx_rename_file_n;
+ name = path.data;
+
+ if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
+ return;
+ }
+
+ err = ngx_errno;
+
+ if (err == NGX_ENOENT) {
+
+ err = ngx_create_full_path(path.data, ngx_dir_access(u->conf->store));
+
+ if (err == 0) {
+ if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
+ return;
+ }
+
+ err = ngx_errno;
+ }
+ }
+
+#if (NGX_WIN32)
+
+ if (err == NGX_EEXIST) {
+ if (ngx_win32_rename_file(temp, &path, r->pool) != NGX_ERROR) {
+
+ if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) {
+ return;
+ }
+ }
+
+ err = ngx_errno;
+ }
+
+#endif
+
+failed:
+
+ if (ngx_delete_file(temp->data) == NGX_FILE_ERROR) {
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno,
+ ngx_delete_file_n " \"%s\" failed",
+ temp->data);
+ }
+
+ ngx_log_error(NGX_LOG_CRIT, r->connection->log, err,
+ "%s \"%s\" failed", failed, name);
+}
+
+
+static void
ngx_http_upstream_dummy_handler(ngx_event_t *wev)
{
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, wev->log, 0,
diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h
index b2e3f3e93..4ba38ec0f 100644
--- a/src/http/ngx_http_upstream.h
+++ b/src/http/ngx_http_upstream.h
@@ -118,6 +118,7 @@ typedef struct {
size_t temp_file_write_size_conf;
ngx_uint_t next_upstream;
+ ngx_uint_t store;
ngx_bufs_t bufs;
@@ -237,6 +238,7 @@ struct ngx_http_upstream_s {
ngx_http_cleanup_pt *cleanup;
+ unsigned store:1;
unsigned cachable:1;
unsigned accel:1;
diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
index b54e7a72d..af90d1d59 100644
--- a/src/http/ngx_http_upstream_round_robin.c
+++ b/src/http/ngx_http_upstream_round_robin.c
@@ -152,7 +152,10 @@ ngx_http_upstream_init_round_robin_peer(ngx_http_request_t *r,
r->upstream->peer.free = ngx_http_upstream_free_round_robin_peer;
r->upstream->peer.tries = rrp->peers->number;
#if (NGX_HTTP_SSL)
- r->upstream->peer.save_session = ngx_http_upstream_save_round_robin_peer;
+ r->upstream->peer.set_session =
+ ngx_http_upstream_set_round_robin_peer_session;
+ r->upstream->peer.save_session =
+ ngx_http_upstream_save_round_robin_peer_session;
#endif
return NGX_OK;
@@ -328,9 +331,6 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
pc->sockaddr = peer->sockaddr;
pc->socklen = peer->socklen;
pc->name = &peer->name;
-#if (NGX_SSL)
- pc->ssl_session = peer->ssl_session;
-#endif
/* ngx_unlock_mutex(rrp->peers->mutex); */
@@ -408,29 +408,72 @@ ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc, void *data,
#if (NGX_HTTP_SSL)
-void
-ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc, void *data)
+ngx_int_t
+ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
+ void *data)
{
ngx_http_upstream_rr_peer_data_t *rrp = data;
+ ngx_int_t rc;
ngx_ssl_session_t *ssl_session;
ngx_http_upstream_rr_peer_t *peer;
+ peer = &rrp->peers->peer[rrp->current];
+
+ /* TODO: threads only mutex */
+ /* ngx_lock_mutex(rrp->peers->mutex); */
+
+ ssl_session = peer->ssl_session;
+
+ rc = ngx_ssl_set_session(pc->connection, ssl_session);
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "set session: %p:%d",
+ ssl_session, ssl_session ? ssl_session->references : 0);
+
+ /* ngx_unlock_mutex(rrp->peers->mutex); */
+
+ return rc;
+}
+
+
+void
+ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
+ void *data)
+{
+ ngx_http_upstream_rr_peer_data_t *rrp = data;
+
+ ngx_ssl_session_t *old_ssl_session, *ssl_session;
+ ngx_http_upstream_rr_peer_t *peer;
+
ssl_session = ngx_ssl_get_session(pc->connection);
if (ssl_session == NULL) {
return;
}
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "save session: %p:%d", ssl_session, ssl_session->references);
+
peer = &rrp->peers->peer[rrp->current];
+ /* TODO: threads only mutex */
/* ngx_lock_mutex(rrp->peers->mutex); */
+
+ old_ssl_session = peer->ssl_session;
peer->ssl_session = ssl_session;
+
/* ngx_unlock_mutex(rrp->peers->mutex); */
- if (pc->ssl_session) {
+ if (old_ssl_session) {
+
+ ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0,
+ "old session: %p:%d",
+ old_ssl_session, old_ssl_session->references);
+
/* TODO: may block */
- ngx_ssl_free_session(pc->ssl_session);
+
+ ngx_ssl_free_session(old_ssl_session);
}
}
diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
index 5d952217b..2e2bf132f 100644
--- a/src/http/ngx_http_upstream_round_robin.h
+++ b/src/http/ngx_http_upstream_round_robin.h
@@ -30,7 +30,7 @@ typedef struct {
ngx_uint_t down; /* unsigned down:1; */
#if (NGX_SSL)
- ngx_ssl_session_t *ssl_session;
+ ngx_ssl_session_t *ssl_session; /* local to a process */
#endif
} ngx_http_upstream_rr_peer_t;
@@ -68,7 +68,10 @@ void ngx_http_upstream_free_round_robin_peer(ngx_peer_connection_t *pc,
void *data, ngx_uint_t state);
#if (NGX_HTTP_SSL)
-void ngx_http_upstream_save_round_robin_peer(ngx_peer_connection_t *pc,
+ngx_int_t
+ ngx_http_upstream_set_round_robin_peer_session(ngx_peer_connection_t *pc,
+ void *data);
+void ngx_http_upstream_save_round_robin_peer_session(ngx_peer_connection_t *pc,
void *data);
#endif
diff --git a/src/mail/ngx_mail_auth_http_module.c b/src/mail/ngx_mail_auth_http_module.c
index 8028c957a..c7e0fc038 100644
--- a/src/mail/ngx_mail_auth_http_module.c
+++ b/src/mail/ngx_mail_auth_http_module.c
@@ -1169,6 +1169,7 @@ ngx_mail_auth_http_create_request(ngx_mail_session_t *s, ngx_pool_t *pool,
+ sizeof(CRLF) - 1
+ sizeof("Client-IP: ") - 1 + s->connection->addr_text.len
+ sizeof(CRLF) - 1
+ + ahcf->header.len
+ sizeof(CRLF) - 1;
b = ngx_create_temp_buf(pool, len);
diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c
index e41983248..8fee001bb 100644
--- a/src/mail/ngx_mail_handler.c
+++ b/src/mail/ngx_mail_handler.c
@@ -708,7 +708,10 @@ ngx_pop3_auth_state(ngx_event_t *rev)
(u_char *) "CRAM-MD5", 8)
== 0)
{
- if (s->args.nelts != 1) {
+ if (!(cscf->pop3_auth_methods
+ & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
+ || s->args.nelts != 1)
+ {
rc = NGX_MAIL_PARSE_INVALID_COMMAND;
break;
}
@@ -1368,7 +1371,13 @@ ngx_smtp_auth_state(ngx_event_t *rev)
(u_char *) "CRAM-MD5", 8)
== 0)
{
- if (s->args.nelts != 1) {
+ cscf = ngx_mail_get_module_srv_conf(s,
+ ngx_mail_core_module);
+
+ if (!(cscf->smtp_auth_methods
+ & NGX_MAIL_AUTH_CRAM_MD5_ENABLED)
+ || s->args.nelts != 1)
+ {
rc = NGX_MAIL_PARSE_INVALID_COMMAND;
break;
}