# HG changeset patch # User Igor Sysoev # Date 1184184000 -14400 # Node ID fc223117327fbb2e852840dcb533ba5ff998d9ee # Parent fcdf0e42c859032013b5a1d42966e1d558be2538 nginx 0.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. Thanks to Maxim Dounin. *) 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. diff --git a/CHANGES b/CHANGES --- 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 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 --- 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 --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -796,6 +796,7 @@ ngx_core_module_init_conf(ngx_cycle_t *c 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 *c 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 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 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 --- 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 --- 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, n } +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 --- 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 --- 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 } 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 --- a/src/event/ngx_event_connect.h +++ b/src/event/ngx_event_connect.h @@ -13,50 +13,56 @@ #include -#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 --- 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_reques #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 --- 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_c 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_con * 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 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 --- 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_com 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_ * 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 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 --- 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_p 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 --- 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 --- 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_hand 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_requ 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 * 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 --- 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_ht } post_handler(r); + return NGX_OK; } 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 @@ -33,6 +33,8 @@ static ngx_int_t ngx_http_upstream_non_b 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_ups 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_ 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_connectio 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_connectio 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(ng 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 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 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 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 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 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 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 --- 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 --- 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( 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(n 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( #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 --- 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_ 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 --- 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_ma + 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 --- 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; }