# HG changeset patch # User Igor Sysoev # Date 1125950400 -14400 # Node ID e916a291e9aa2077661a7c1df488b7b04610e0a4 # Parent 5b7ec80c3c40f85d2df50b3744a739693765710f nginx 0.1.44 *) Feature: the IMAP/POP3 proxy supports SSL. *) Feature: the "proxy_timeout" directive of the ngx_imap_proxy_module. *) Feature: the "userid_mark" directive. *) Feature: the $remote_user variable value is determined independently of authorization use. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,15 @@ + +Changes with nginx 0.1.44 06 Sep 2005 + + *) Feature: the IMAP/POP3 proxy supports SSL. + + *) Feature: the "proxy_timeout" directive. + + *) Feature: the "userid_mark" directive. + + *) Feature: the $remote_user variable value is determined independently + of authorization use. + Changes with nginx 0.1.43 30 Aug 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,15 @@ + +Изменения в nginx 0.1.44 06.09.2005 + + *) Добавление: IMAP/POP3 прокси поддерживает SSL. + + *) Добавление: директива proxy_timeout. + + *) Добавление: директива userid_mark. + + *) Добавление: значение переменной $remote_user определяется независимо + от того, используется ли авторизация или нет. + Изменения в nginx 0.1.43 30.08.2005 diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -228,6 +228,14 @@ fi if [ $IMAP = YES ]; then modules="$modules $IMAP_MODULES" + if [ $IMAP_SSL = YES ]; then + modules="$modules $IMAP_SSL_MODULE" + IMAP_DEPS="$IMAP_DEPS $IMAP_SSL_DEPS" + IMAP_SRCS="$IMAP_SRCS $IMAP_SSL_SRCS" + have=NGX_IMAP_SSL . auto/have + USE_OPENSSL=YES + fi + modules="$modules $IMAP_AUTH_HTTP_MODULE" IMAP_SRCS="$IMAP_SRCS $IMAP_AUTH_HTTP_SRCS" diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -64,6 +64,7 @@ HTTP_FASTCGI=YES HTTP_STUB_STATUS=NO IMAP=NO +IMAP_SSL=NO NGX_ADDONS= @@ -141,6 +142,7 @@ do --with-http_stub_status_module) HTTP_STUB_STATUS=YES ;; --with-imap) IMAP=YES ;; + --with-imap_ssl_module) IMAP_SSL=YES ;; --add-module=*) NGX_ADDONS="$NGX_ADDONS $value" ;; diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -346,6 +346,10 @@ IMAP_SRCS="src/imap/ngx_imap.c \ src/imap/ngx_imap_handler.c \ src/imap/ngx_imap_parse.c" +IMAP_SSL_MODULE="ngx_imap_ssl_module" +IMAP_SSL_DEPS="src/imap/ngx_imap_ssl_module.h" +IMAP_SSL_SRCS="src/imap/ngx_imap_ssl_module.c" + IMAP_AUTH_HTTP_MODULE="ngx_imap_auth_http_module" IMAP_AUTH_HTTP_SRCS="src/imap/ngx_imap_auth_http_module.c" diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -236,6 +236,10 @@ main(int argc, char *const *argv) #else + if (ngx_init_signals(cycle->log) == NGX_ERROR) { + return 1; + } + if (!ngx_inherited && ccf->daemon) { if (ngx_daemon(cycle->log) == NGX_ERROR) { return 1; 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_VER "nginx/0.1.43" +#define NGINX_VER "nginx/0.1.44" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_connection.h b/src/core/ngx_connection.h --- a/src/core/ngx_connection.h +++ b/src/core/ngx_connection.h @@ -92,6 +92,7 @@ struct ngx_connection_s { ngx_socket_t fd; ngx_recv_pt recv; + ngx_send_pt send; ngx_send_chain_pt send_chain; ngx_listening_t *listening; diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -256,6 +256,7 @@ ngx_event_accept(ngx_event_t *ev) c->servers = ls->servers; c->recv = ngx_recv; + c->send = ngx_send; c->send_chain = ngx_send_chain; c->log = log; diff --git a/src/event/ngx_event_connect.c b/src/event/ngx_event_connect.c --- a/src/event/ngx_event_connect.c +++ b/src/event/ngx_event_connect.c @@ -229,6 +229,10 @@ ngx_event_connect_peer(ngx_peer_connecti c->write = wev; wev->write = 1; + c->recv = ngx_recv; + c->send = ngx_send; + c->send_chain = ngx_send_chain; + c->log = pc->log; rev->log = pc->log; wev->log = pc->log; diff --git a/src/event/ngx_event_openssl.c b/src/event/ngx_event_openssl.c --- a/src/event/ngx_event_openssl.c +++ b/src/event/ngx_event_openssl.c @@ -13,7 +13,6 @@ static ngx_int_t ngx_ssl_handle_recv(ngx_connection_t *c, int n); static void ngx_ssl_write_handler(ngx_event_t *wev); -static ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); static void ngx_ssl_read_handler(ngx_event_t *rev); @@ -209,8 +208,10 @@ ngx_ssl_handle_recv(ngx_connection_t *c, } if (sslerr == SSL_ERROR_WANT_WRITE) { - ngx_log_error(NGX_LOG_ALERT, c->log, err, - "SSL wants to write%s", handshake); + + ngx_log_error(NGX_LOG_INFO, c->log, err, + "client does SSL %shandshake", + SSL_is_init_finished(c->ssl->ssl) ? "re" : ""); c->write->ready = 0; @@ -391,12 +392,11 @@ ngx_ssl_send_chain(ngx_connection_t *c, } -static ssize_t +ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size) { - int n, sslerr; - ngx_err_t err; - char *handshake; + int n, sslerr; + ngx_err_t err; ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL to write: %d", size); @@ -405,6 +405,47 @@ ngx_ssl_write(ngx_connection_t *c, u_cha ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, "SSL_write: %d", n); if (n > 0) { + +#if (NGX_DEBUG) + + if (!c->ssl->handshaked && SSL_is_init_finished(c->ssl->ssl)) { + char buf[129], *s, *d; + SSL_CIPHER *cipher; + + c->ssl->handshaked = 1; + + cipher = SSL_get_current_cipher(c->ssl->ssl); + + if (cipher) { + SSL_CIPHER_description(cipher, &buf[1], 128); + + for (s = &buf[1], d = buf; *s; s++) { + if (*s == ' ' && *d == ' ') { + continue; + } + + if (*s == LF || *s == CR) { + continue; + } + + *++d = *s; + } + + if (*d != ' ') { + d++; + } + + *d = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL cipher: \"%s\"", &buf[1]); + } else { + ngx_log_debug0(NGX_LOG_DEBUG_EVENT, c->log, 0, + "SSL no shared ciphers"); + } + } +#endif + if (c->ssl->saved_read_handler) { c->read->handler = c->ssl->saved_read_handler; @@ -440,15 +481,9 @@ ngx_ssl_write(ngx_connection_t *c, u_cha if (sslerr == SSL_ERROR_WANT_READ) { - if (!SSL_is_init_finished(c->ssl->ssl)) { - handshake = " in SSL handshake"; - - } else { - handshake = ""; - } - - ngx_log_error(NGX_LOG_ALERT, c->log, err, - "SSL wants to read%s", handshake); + ngx_log_error(NGX_LOG_INFO, c->log, err, + "client does SSL %shandshake", + SSL_is_init_finished(c->ssl->ssl) ? "re" : ""); c->read->ready = 0; diff --git a/src/event/ngx_event_openssl.h b/src/event/ngx_event_openssl.h --- a/src/event/ngx_event_openssl.h +++ b/src/event/ngx_event_openssl.h @@ -49,6 +49,7 @@ ngx_int_t ngx_ssl_create_session(ngx_ssl #define ngx_ssl_handshake(c) NGX_OK ssize_t ngx_ssl_recv(ngx_connection_t *c, u_char *buf, size_t size); +ssize_t ngx_ssl_write(ngx_connection_t *c, u_char *data, size_t size); ngx_chain_t *ngx_ssl_send_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit); ngx_int_t ngx_ssl_shutdown(ngx_connection_t *c); diff --git a/src/http/modules/ngx_http_auth_basic_module.c b/src/http/modules/ngx_http_auth_basic_module.c --- a/src/http/modules/ngx_http_auth_basic_module.c +++ b/src/http/modules/ngx_http_auth_basic_module.c @@ -90,8 +90,9 @@ ngx_http_auth_basic_handler(ngx_http_req off_t offset; ssize_t n; ngx_fd_t fd; - ngx_str_t auth, encoded, pwd; - ngx_uint_t i, login, len, left, passwd; + ngx_int_t rc; + ngx_str_t pwd; + ngx_uint_t i, login, left, passwd; ngx_file_t file; ngx_http_auth_basic_ctx_t *ctx; ngx_http_auth_basic_loc_conf_t *alcf; @@ -115,57 +116,16 @@ ngx_http_auth_basic_handler(ngx_http_req &alcf->realm); } - if (r->headers_in.authorization == NULL) { - return ngx_http_auth_basic_set_realm(r, &alcf->realm); - } - - encoded = r->headers_in.authorization->value; + rc = ngx_http_auth_basic_user(r); - if (encoded.len < sizeof("Basic ") - 1 - || ngx_strncasecmp(encoded.data, "Basic ", sizeof("Basic ") - 1) != 0) - { - return ngx_http_auth_basic_set_realm(r, &alcf->realm); - } - - encoded.len -= sizeof("Basic ") - 1; - encoded.data += sizeof("Basic ") - 1; - - while (encoded.len && encoded.data[0] == ' ') { - encoded.len--; - encoded.data++; - } - - if (encoded.len == 0) { + if (rc == NGX_DECLINED) { return ngx_http_auth_basic_set_realm(r, &alcf->realm); } - auth.len = ngx_base64_decoded_length(encoded.len); - auth.data = ngx_palloc(r->pool, auth.len + 1); - if (auth.data == NULL) { + if (rc == NGX_ERROR) { return NGX_HTTP_INTERNAL_SERVER_ERROR; } - if (ngx_decode_base64(&auth, &encoded) != NGX_OK) { - return ngx_http_auth_basic_set_realm(r, &alcf->realm); - } - - auth.data[auth.len] = '\0'; - - for (len = 0; len < auth.len; len++) { - if (auth.data[len] == ':') { - break; - } - } - - if (len == auth.len) { - return ngx_http_auth_basic_set_realm(r, &alcf->realm); - } - - r->headers_in.user.len = len; - r->headers_in.user.data = auth.data; - r->headers_in.passwd.len = auth.len - len - 1; - r->headers_in.passwd.data = &auth.data[len + 1]; - fd = ngx_open_file(alcf->user_file.data, NGX_FILE_RDONLY, NGX_FILE_OPEN); if (fd == NGX_INVALID_FILE) { @@ -208,12 +168,12 @@ ngx_http_auth_basic_handler(ngx_http_req break; } - if (buf[i] != auth.data[login]) { + if (buf[i] != r->headers_in.user.data[login]) { state = sw_skip; break; } - if (login == len) { + if (login == r->headers_in.user.len) { state = sw_passwd; passwd = i + 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 @@ -424,10 +424,10 @@ ngx_http_proxy_create_request(ngx_http_r escape = 0; - loc_len = r->valid_location ? u->conf->location->len : 1; + loc_len = r->valid_location ? u->conf->location->len - 1 : 0; if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { - len += r->unparsed_uri.len - 1; + len += r->unparsed_uri.len; } else { if (r->quoted_uri) { @@ -508,11 +508,11 @@ ngx_http_proxy_create_request(ngx_http_r r->method_name.len + 1); } - b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len); + b->last = ngx_cpymem(b->last, u->conf->uri.data, u->conf->uri.len - 1); if (plcf->upstream.pass_unparsed_uri && r->valid_unparsed_uri) { - b->last = ngx_cpymem(b->last, r->unparsed_uri.data + 1, - r->unparsed_uri.len - 1); + b->last = ngx_cpymem(b->last, r->unparsed_uri.data, + r->unparsed_uri.len); } else { if (escape) { ngx_escape_uri(b->last, r->uri.data + loc_len, diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -26,18 +26,22 @@ typedef struct { ngx_str_t name; ngx_str_t domain; ngx_str_t path; + ngx_str_t p3p; + time_t expires; - ngx_str_t p3p; + + u_char mark; } ngx_http_userid_conf_t; typedef struct { uint32_t uid_got[4]; uint32_t uid_set[4]; + ngx_str_t cookie; } ngx_http_userid_ctx_t; -static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, +static void ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); @@ -61,6 +65,9 @@ static char *ngx_http_userid_path(ngx_co static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data); +static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + static uint32_t sequencer_v1 = 1; @@ -84,7 +91,6 @@ static ngx_conf_enum_t ngx_http_userid_ static ngx_conf_post_handler_pt ngx_http_userid_domain_p = ngx_http_userid_domain; - static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path; static ngx_conf_post_handler_pt ngx_http_userid_p3p_p = ngx_http_userid_p3p; @@ -99,28 +105,28 @@ static ngx_command_t ngx_http_userid_co ngx_http_userid_state }, { ngx_string("userid_service"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_num_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_userid_conf_t, service), NULL }, { ngx_string("userid_name"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_userid_conf_t, name), NULL }, { ngx_string("userid_domain"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_userid_conf_t, domain), &ngx_http_userid_domain_p }, { ngx_string("userid_path"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, ngx_conf_set_str_slot, NGX_HTTP_LOC_CONF_OFFSET, offsetof(ngx_http_userid_conf_t, path), @@ -140,6 +146,13 @@ static ngx_command_t ngx_http_userid_co offsetof(ngx_http_userid_conf_t, p3p), &ngx_http_userid_p3p_p }, + { ngx_string("userid_mark"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_userid_mark, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + ngx_null_command }; @@ -205,15 +218,24 @@ ngx_http_userid_filter(ngx_http_request_ ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module); - - rc = ngx_http_userid_get_uid(r, ctx, conf); + ngx_http_userid_get_uid(r, ctx, conf); - if (rc != NGX_OK) { - return rc; + if (conf->enable == NGX_HTTP_USERID_LOG) { + return ngx_http_next_header_filter(r); } - if (conf->enable == NGX_HTTP_USERID_LOG || ctx->uid_got[3] != 0) { - return ngx_http_next_header_filter(r); + if (ctx->uid_got[3] != 0) { + if (conf->mark == '\0') { + return ngx_http_next_header_filter(r); + + } else { + if (ctx->cookie.len > 23 + && ctx->cookie.data[22] == conf->mark + && ctx->cookie.data[23] == '=') + { + return ngx_http_next_header_filter(r); + } + } } rc = ngx_http_userid_set_uid(r, ctx, conf); @@ -226,7 +248,7 @@ ngx_http_userid_filter(ngx_http_request_ } -static ngx_int_t +static void ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf) { @@ -235,23 +257,29 @@ ngx_http_userid_get_uid(ngx_http_request ngx_table_elt_t **cookies; n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name, - &src); + &ctx->cookie); if (n == NGX_DECLINED) { - return NGX_OK; + return; } - if (src.len < 22) { + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "uid cookie: \"%V\"", &ctx->cookie); + + if (ctx->cookie.len < 22) { cookies = r->headers_in.cookies.elts; ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent too short userid cookie \"%V\"", &cookies[n]->value); - return NGX_OK; + return; } + src = ctx->cookie; + /* - * we have to limit encoded string to 22 characters - * because there are already the millions cookies with a garbage - * instead of the correct base64 trail "==" + * we have to limit the encoded string to 22 characters because + * 1) cookie may be marked by "userid_mark", + * 2) and there are already the millions cookies with a garbage + * instead of the correct base64 trail "==" */ src.len = 22; @@ -263,15 +291,13 @@ ngx_http_userid_get_uid(ngx_http_request ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "client sent invalid userid cookie \"%V\"", &cookies[n]->value); - return NGX_OK; + return; } ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "uid: %08XD%08XD%08XD%08XD", ctx->uid_got[0], ctx->uid_got[1], ctx->uid_got[2], ctx->uid_got[3]); - - return NGX_OK; } @@ -286,47 +312,58 @@ ngx_http_userid_set_uid(ngx_http_request ngx_str_t src, dst; ngx_table_elt_t *set_cookie, *p3p; - /* TODO: mutex for sequencers */ + /* + * TODO: in the threaded mode the sequencers should be in TLS and their + * ranges should be divided between threads + */ + + if (ctx->uid_got[3] == 0) { - if (conf->enable == NGX_HTTP_USERID_V1) { - if (conf->service == NGX_CONF_UNSET) { - ctx->uid_set[0] = 0; + if (conf->enable == NGX_HTTP_USERID_V1) { + if (conf->service == NGX_CONF_UNSET) { + ctx->uid_set[0] = 0; + } else { + ctx->uid_set[0] = conf->service; + } + ctx->uid_set[1] = ngx_time(); + ctx->uid_set[2] = ngx_pid; + ctx->uid_set[3] = sequencer_v1; + sequencer_v1 += 0x100; + } else { - ctx->uid_set[0] = htonl(conf->service); - } + if (conf->service == NGX_CONF_UNSET) { + if (r->in_addr == 0) { + slen = sizeof(struct sockaddr_in); + if (getsockname(r->connection->fd, + (struct sockaddr *) &sin, &slen) == -1) + { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, + ngx_socket_errno, "getsockname() failed"); + } + + r->in_addr = sin.sin_addr.s_addr; + } - ctx->uid_set[1] = ngx_time(); - ctx->uid_set[2] = ngx_pid; - ctx->uid_set[3] = sequencer_v1; - sequencer_v1 += 0x100; + ctx->uid_set[0] = htonl(r->in_addr); + + } else { + ctx->uid_set[0] = htonl(conf->service); + } + + ctx->uid_set[1] = htonl(ngx_time()); + ctx->uid_set[2] = htonl(ngx_pid); + ctx->uid_set[3] = htonl(sequencer_v2); + sequencer_v2 += 0x100; + if (sequencer_v2 < 0x03030302) { + sequencer_v2 = 0x03030302; + } + } } else { - if (conf->service == NGX_CONF_UNSET) { - if (r->in_addr == 0) { - slen = sizeof(struct sockaddr_in); - if (getsockname(r->connection->fd, - (struct sockaddr *) &sin, &slen) == -1) - { - ngx_log_error(NGX_LOG_CRIT, r->connection->log, - ngx_socket_errno, "getsockname() failed"); - } - - r->in_addr = sin.sin_addr.s_addr; - } - - ctx->uid_set[0] = htonl(r->in_addr); - - } else { - ctx->uid_set[0] = htonl(conf->service); - } - - ctx->uid_set[1] = htonl(ngx_time()); - ctx->uid_set[2] = htonl(ngx_pid); - ctx->uid_set[3] = htonl(sequencer_v2); - sequencer_v2 += 0x100; - if (sequencer_v2 < 0x03030302) { - sequencer_v2 = 0x03030302; - } + ctx->uid_set[0] = ctx->uid_got[0]; + ctx->uid_set[1] = ctx->uid_got[1]; + ctx->uid_set[2] = ctx->uid_got[2]; + ctx->uid_set[3] = ctx->uid_got[3]; } len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len; @@ -347,13 +384,24 @@ ngx_http_userid_set_uid(ngx_http_request p = ngx_cpymem(cookie, conf->name.data, conf->name.len); *p++ = '='; - src.len = 16; - src.data = (u_char *) ctx->uid_set; - dst.data = p; + if (ctx->uid_got[3] == 0) { + src.len = 16; + src.data = (u_char *) ctx->uid_set; + dst.data = p; + + ngx_encode_base64(&dst, &src); + + p += dst.len; - ngx_encode_base64(&dst, &src); + if (conf->mark) { + *(p - 2) = conf->mark; + } - p += dst.len; + } else { + p = ngx_cpymem(p, ctx->cookie.data, 22); + *p++ = conf->mark; + *p++ = '='; + } if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) { p = ngx_cpymem(p, expires, sizeof(expires) - 1); @@ -545,6 +593,7 @@ ngx_http_userid_create_conf(ngx_conf_t * conf->enable = NGX_CONF_UNSET_UINT; conf->service = NGX_CONF_UNSET; conf->expires = NGX_CONF_UNSET; + conf->mark = (u_char) '\xFF'; return conf; } @@ -567,6 +616,14 @@ ngx_http_userid_merge_conf(ngx_conf_t *c ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET); ngx_conf_merge_sec_value(conf->expires, prev->expires, 0); + if (conf->mark == (u_char) '\xFF') { + if (prev->mark == (u_char) '\xFF') { + conf->mark = '\0'; + } else { + conf->mark = prev->mark; + } + } + return NGX_CONF_OK; } @@ -627,7 +684,7 @@ ngx_http_userid_expires(ngx_conf_t *cf, { ngx_http_userid_conf_t *ucf = conf; - ngx_str_t *value; + ngx_str_t *value; if (ucf->expires != NGX_CONF_UNSET) { return "is duplicate"; @@ -670,3 +727,36 @@ ngx_http_userid_p3p(ngx_conf_t *cf, void return NGX_CONF_OK; } + + +static char * +ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_userid_conf_t *ucf = conf; + + ngx_str_t *value; + + if (ucf->mark != (u_char) '\xFF') { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "off") == 0) { + ucf->mark = '\0'; + return NGX_CONF_OK; + } + + if (value[1].len != 1 + || !((value[1].data[0] >= '0' && value[1].data[0] <= '9') + || (value[1].data[0] >= 'A' && value[1].data[0] <= 'Z') + || (value[1].data[0] >= 'a' && value[1].data[0] <= 'z') + || value[1].data[0] == '=')) + { + return "value must be \"off\" or a single letter, digit or \"=\""; + } + + ucf->mark = value[1].data[0]; + + return NGX_CONF_OK; +} diff --git a/src/http/ngx_http_core_module.c b/src/http/ngx_http_core_module.c --- a/src/http/ngx_http_core_module.c +++ b/src/http/ngx_http_core_module.c @@ -931,6 +931,76 @@ ngx_http_set_exten(ngx_http_request_t *r ngx_int_t +ngx_http_auth_basic_user(ngx_http_request_t *r) +{ + ngx_str_t auth, encoded; + ngx_uint_t len; + + if (r->headers_in.user.len == 0 && r->headers_in.user.data != NULL) { + return NGX_DECLINED; + } + + if (r->headers_in.authorization == NULL) { + r->headers_in.user.data = (u_char *) ""; + return NGX_DECLINED; + } + + encoded = r->headers_in.authorization->value; + + if (encoded.len < sizeof("Basic ") - 1 + || ngx_strncasecmp(encoded.data, "Basic ", sizeof("Basic ") - 1) != 0) + { + r->headers_in.user.data = (u_char *) ""; + return NGX_DECLINED; + } + + encoded.len -= sizeof("Basic ") - 1; + encoded.data += sizeof("Basic ") - 1; + + while (encoded.len && encoded.data[0] == ' ') { + encoded.len--; + encoded.data++; + } + + if (encoded.len == 0) { + r->headers_in.user.data = (u_char *) ""; + return NGX_DECLINED; + } + + auth.len = ngx_base64_decoded_length(encoded.len); + auth.data = ngx_palloc(r->pool, auth.len + 1); + if (auth.data == NULL) { + return NGX_ERROR; + } + + if (ngx_decode_base64(&auth, &encoded) != NGX_OK) { + r->headers_in.user.data = (u_char *) ""; + return NGX_DECLINED; + } + + auth.data[auth.len] = '\0'; + + for (len = 0; len < auth.len; len++) { + if (auth.data[len] == ':') { + break; + } + } + + if (len == auth.len) { + r->headers_in.user.data = (u_char *) ""; + return NGX_DECLINED; + } + + r->headers_in.user.len = len; + r->headers_in.user.data = auth.data; + r->headers_in.passwd.len = auth.len - len - 1; + r->headers_in.passwd.data = &auth.data[len + 1]; + + return NGX_OK; +} + + +ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args) { diff --git a/src/http/ngx_http_core_module.h b/src/http/ngx_http_core_module.h --- a/src/http/ngx_http_core_module.h +++ b/src/http/ngx_http_core_module.h @@ -252,6 +252,7 @@ ngx_int_t ngx_http_find_location_config( ngx_int_t ngx_http_set_content_type(ngx_http_request_t *r); ngx_int_t ngx_http_set_exten(ngx_http_request_t *r); +ngx_int_t ngx_http_auth_basic_user(ngx_http_request_t *r); ngx_int_t ngx_http_subrequest(ngx_http_request_t *r, ngx_str_t *uri, ngx_str_t *args); 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 @@ -11,9 +11,6 @@ static void ngx_http_init_request(ngx_event_t *ev); -#if (NGX_HTTP_SSL) -static void ngx_http_ssl_handshake(ngx_event_t *rev); -#endif static void ngx_http_process_request_line(ngx_event_t *rev); static void ngx_http_process_request_headers(ngx_event_t *rev); static ssize_t ngx_http_read_request_header(ngx_http_request_t *r); @@ -50,6 +47,11 @@ static u_char *ngx_http_log_error(ngx_lo static u_char *ngx_http_log_error_handler(ngx_http_request_t *r, u_char *buf, size_t len); +#if (NGX_HTTP_SSL) +static void ngx_http_ssl_handshake(ngx_event_t *rev); +static void ngx_http_ssl_close_handler(ngx_event_t *ev); +#endif + static char *ngx_http_client_errors[] = { @@ -490,6 +492,7 @@ ngx_http_ssl_handshake(ngx_event_t *rev) "https ssl handshake: 0x%02Xd", buf[0]); c->recv = ngx_ssl_recv; + c->send = ngx_ssl_write; c->send_chain = ngx_ssl_send_chain; rc = ngx_ssl_handshake(c); @@ -2412,27 +2415,6 @@ ngx_http_close_request(ngx_http_request_ } -#if (NGX_HTTP_SSL) - -static void -ngx_http_ssl_close_handler(ngx_event_t *ev) -{ - ngx_connection_t *c; - - c = ev->data; - - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http ssl close handler"); - - if (ngx_ssl_shutdown(c) == NGX_AGAIN) { - return; - } - - ngx_http_close_connection(c); -} - -#endif - - static void ngx_http_close_connection(ngx_connection_t *c) { @@ -2441,7 +2423,7 @@ ngx_http_close_connection(ngx_connection ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "close http connection: %d", c->fd); -#if (NGX_OPENSSL) +#if (NGX_HTTP_SSL) if (c->ssl) { if (ngx_ssl_shutdown(c) == NGX_AGAIN) { @@ -2465,6 +2447,27 @@ ngx_http_close_connection(ngx_connection } +#if (NGX_HTTP_SSL) + +static void +ngx_http_ssl_close_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + c = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, ev->log, 0, "http ssl close handler"); + + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + return; + } + + ngx_http_close_connection(c); +} + +#endif + + static u_char * ngx_http_log_error(ngx_log_t *log, u_char *buf, size_t len) { diff --git a/src/http/ngx_http_special_response.c b/src/http/ngx_http_special_response.c --- a/src/http/ngx_http_special_response.c +++ b/src/http/ngx_http_special_response.c @@ -292,6 +292,8 @@ ngx_http_special_response_handler(ngx_ht r->err_ctx = r->ctx; + r->method = NGX_HTTP_GET; + return ngx_http_internal_redirect(r, &err_page[i].uri, NULL); } } diff --git a/src/http/ngx_http_variables.c b/src/http/ngx_http_variables.c --- a/src/http/ngx_http_variables.c +++ b/src/http/ngx_http_variables.c @@ -32,6 +32,8 @@ static ngx_http_variable_value_t * ngx_http_variable_document_root(ngx_http_request_t *r, uintptr_t data); static ngx_http_variable_value_t * ngx_http_variable_request_filename(ngx_http_request_t *r, uintptr_t data); +static ngx_http_variable_value_t * + ngx_http_variable_remote_user(ngx_http_request_t *r, uintptr_t data); /* @@ -108,8 +110,7 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("request_method"), ngx_http_variable_request, offsetof(ngx_http_request_t, method_name), 0, 0 }, - { ngx_string("remote_user"), ngx_http_variable_request, - offsetof(ngx_http_request_t, headers_in.user), 0, 0 }, + { ngx_string("remote_user"), ngx_http_variable_remote_user, 0, 0, 0 }, { ngx_null_string, NULL, 0, 0, 0 } }; @@ -657,6 +658,34 @@ ngx_http_variable_request_filename(ngx_h } +static ngx_http_variable_value_t * +ngx_http_variable_remote_user(ngx_http_request_t *r, uintptr_t data) +{ + ngx_int_t rc; + ngx_http_variable_value_t *vv; + + rc = ngx_http_auth_basic_user(r); + + if (rc == NGX_DECLINED) { + return NGX_HTTP_VAR_NOT_FOUND; + } + + if (rc == NGX_ERROR) { + return NULL; + } + + vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t)); + if (vv == NULL) { + return NULL; + } + + vv->value = 0; + vv->text = r->headers_in.user; + + return vv; +} + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf) { diff --git a/src/imap/ngx_imap.h b/src/imap/ngx_imap.h --- a/src/imap/ngx_imap.h +++ b/src/imap/ngx_imap.h @@ -13,6 +13,11 @@ #include #include +#if (NGX_IMAP_SSL) +#include +#endif + + typedef struct { void **main_conf; @@ -32,7 +37,6 @@ typedef struct { ngx_msec_t timeout; size_t imap_client_buffer_size; - size_t proxy_buffer_size; ngx_uint_t protocol; @@ -82,8 +86,8 @@ typedef struct { ngx_connection_t *connection; + ngx_str_t out; ngx_buf_t *buffer; - ngx_str_t out; void **ctx; void **main_conf; @@ -93,6 +97,8 @@ typedef struct { ngx_uint_t imap_state; + unsigned blocked:1; + unsigned quit:1; unsigned protocol:1; unsigned quoted:1; @@ -100,6 +106,7 @@ typedef struct { ngx_str_t passwd; ngx_str_t tag; + ngx_str_t tagged_line; ngx_uint_t command; ngx_array_t args; @@ -167,6 +174,7 @@ typedef struct { void ngx_imap_init_connection(ngx_connection_t *c); +void ngx_imap_send(ngx_event_t *wev); void ngx_imap_auth_state(ngx_event_t *rev); void ngx_pop3_auth_state(ngx_event_t *rev); void ngx_imap_close_connection(ngx_connection_t *c); diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c --- a/src/imap/ngx_imap_auth_http_module.c +++ b/src/imap/ngx_imap_auth_http_module.c @@ -516,13 +516,14 @@ ngx_imap_auth_http_process_headers(ngx_i ngx_close_connection(ctx->peer.connection); if (ctx->err.len) { - (void) ngx_send(s->connection, ctx->err.data, ctx->err.len); + s->out = ctx->err; if (ctx->sleep == 0) { - ngx_imap_close_connection(s->connection); - return; + s->quit = 1; } + ngx_imap_send(s->connection->write); + ngx_add_timer(s->connection->read, ctx->sleep * 1000); s->connection->read->handler = ngx_imap_auth_sleep_handler; diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c --- a/src/imap/ngx_imap_core_module.c +++ b/src/imap/ngx_imap_core_module.c @@ -75,13 +75,6 @@ static ngx_command_t ngx_imap_core_comm offsetof(ngx_imap_core_srv_conf_t, imap_client_buffer_size), NULL }, - { ngx_string("proxy_buffer"), - NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_size_slot, - NGX_IMAP_SRV_CONF_OFFSET, - offsetof(ngx_imap_core_srv_conf_t, proxy_buffer_size), - NULL }, - { ngx_string("timeout"), NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, @@ -157,7 +150,6 @@ ngx_imap_core_create_srv_conf(ngx_conf_t } cscf->imap_client_buffer_size = NGX_CONF_UNSET_SIZE; - cscf->proxy_buffer_size = NGX_CONF_UNSET_SIZE; cscf->timeout = NGX_CONF_UNSET_MSEC; cscf->protocol = NGX_CONF_UNSET_UINT; @@ -191,8 +183,6 @@ ngx_imap_core_merge_srv_conf(ngx_conf_t ngx_conf_merge_size_value(conf->imap_client_buffer_size, prev->imap_client_buffer_size, (size_t) ngx_pagesize); - ngx_conf_merge_size_value(conf->proxy_buffer_size, prev->proxy_buffer_size, - (size_t) ngx_pagesize); ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); ngx_conf_merge_unsigned_value(conf->protocol, prev->protocol, NGX_IMAP_IMAP_PROTOCOL); diff --git a/src/imap/ngx_imap_handler.c b/src/imap/ngx_imap_handler.c --- a/src/imap/ngx_imap_handler.c +++ b/src/imap/ngx_imap_handler.c @@ -13,6 +13,10 @@ static void ngx_imap_init_session(ngx_event_t *rev); static ngx_int_t ngx_imap_read_command(ngx_imap_session_t *s); +#if (NGX_IMAP_SSL) +static void ngx_imap_ssl_close_handler(ngx_event_t *ev); +#endif + static ngx_str_t greetings[] = { ngx_string("+OK POP3 ready" CRLF), @@ -36,8 +40,12 @@ static u_char imap_invalid_command[] = void ngx_imap_init_connection(ngx_connection_t *c) { - ssize_t size; + ngx_imap_session_t *s; ngx_imap_conf_ctx_t *ctx; +#if (NGX_IMAP_SSL) + ngx_int_t rc; + ngx_imap_ssl_conf_t *sslcf; +#endif ngx_imap_core_srv_conf_t *cscf; ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection"); @@ -45,26 +53,123 @@ ngx_imap_init_connection(ngx_connection_ c->log_error = NGX_ERROR_INFO; ctx = c->ctx; - cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); + +#if (NGX_IMAP_SSL) + + sslcf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_ssl_module); + + if (sslcf->enable) { - size = greetings[cscf->protocol].len; + if (ngx_ssl_create_session(sslcf->ssl_ctx, c, NGX_SSL_BUFFER) + == NGX_ERROR) + { + ngx_imap_close_connection(c); + return; + } - if (ngx_send(c, greetings[cscf->protocol].data, size) < size) { - /* - * we treat the incomplete sending as NGX_ERROR - * because it is very strange here - */ + rc = ngx_ssl_handshake(c); + + if (rc == NGX_ERROR) { + ngx_imap_close_connection(c); + return; + } + + c->recv = ngx_ssl_recv; + c->send = ngx_ssl_write; + c->send_chain = ngx_ssl_send_chain; + } + +#endif + + s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t)); + if (s == NULL) { ngx_imap_close_connection(c); return; } + c->data = s; + s->connection = c; + + cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); + s->protocol = cscf->protocol; + + s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module); + if (s->ctx == NULL) { + ngx_imap_session_internal_server_error(s); + return; + } + + s->main_conf = ctx->main_conf; + s->srv_conf = ctx->srv_conf; + + s->out = greetings[s->protocol]; + c->read->handler = ngx_imap_init_session; + c->write->handler = ngx_imap_send; + ngx_add_timer(c->write, cscf->timeout); ngx_add_timer(c->read, cscf->timeout); if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { ngx_imap_close_connection(c); } + + ngx_imap_send(c->write); +} + + +void +ngx_imap_send(ngx_event_t *wev) +{ + ngx_int_t n; + ngx_connection_t *c; + ngx_imap_session_t *s; + + c = wev->data; + s = c->data; + + if (wev->timedout) { + ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out"); + ngx_imap_close_connection(c); + return; + } + + if (s->out.len == 0) { + if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { + ngx_imap_close_connection(c); + } + + return; + } + + n = c->send(c, s->out.data, s->out.len); + + if (n > 0) { + s->out.len -= n; + + if (s->quit) { + ngx_imap_close_connection(c); + return; + } + + if (s->blocked) { + c->read->handler(c->read); + } + + return; + } + + if (n == NGX_ERROR) { + ngx_imap_close_connection(c); + return; + } + + /* n == NGX_AGAIN */ + + if (ngx_handle_write_event(c->write, 0) == NGX_ERROR) { + ngx_imap_close_connection(c); + return; + } } @@ -74,7 +179,6 @@ ngx_imap_init_session(ngx_event_t *rev) size_t size; ngx_connection_t *c; ngx_imap_session_t *s; - ngx_imap_conf_ctx_t *ctx; ngx_imap_core_srv_conf_t *cscf; c = rev->data; @@ -85,40 +189,20 @@ ngx_imap_init_session(ngx_event_t *rev) return; } - s = ngx_pcalloc(c->pool, sizeof(ngx_imap_session_t)); - if (s == NULL) { - ngx_imap_session_internal_server_error(s); - return; - } - - c->data = s; - s->connection = c; - - s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module); - if (s->ctx == NULL) { - ngx_imap_session_internal_server_error(s); - return; - } - - ctx = c->ctx; - s->main_conf = ctx->main_conf; - s->srv_conf = ctx->srv_conf; + s = c->data; if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { ngx_imap_session_internal_server_error(s); return; } - cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); - - s->protocol = cscf->protocol; - - if (cscf->protocol == NGX_IMAP_POP3_PROTOCOL) { + if (s->protocol == NGX_IMAP_POP3_PROTOCOL) { size = 128; s->imap_state = ngx_pop3_start; c->read->handler = ngx_pop3_auth_state; } else { + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); size = cscf->imap_client_buffer_size; s->imap_state = ngx_imap_start; c->read->handler = ngx_imap_auth_state; @@ -137,11 +221,11 @@ ngx_imap_init_session(ngx_event_t *rev) void ngx_imap_auth_state(ngx_event_t *rev) { - u_char *text, *last, *out, *p; - ssize_t size, text_len, last_len; + u_char *text, *last, *p; + ssize_t text_len, last_len; ngx_str_t *arg; ngx_int_t rc; - ngx_uint_t quit, tag; + ngx_uint_t tag; ngx_connection_t *c; ngx_imap_session_t *s; ngx_imap_core_srv_conf_t *cscf; @@ -157,6 +241,14 @@ ngx_imap_auth_state(ngx_event_t *rev) return; } + if (s->out.len) { + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap send handler busy"); + s->blocked = 1; + return; + } + + s->blocked = 0; + rc = ngx_imap_read_command(s); ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap auth: %i", rc); @@ -165,7 +257,6 @@ ngx_imap_auth_state(ngx_event_t *rev) return; } - quit = 0; tag = 1; text = NULL; @@ -235,9 +326,9 @@ ngx_imap_auth_state(ngx_event_t *rev) break; case NGX_IMAP_LOGOUT: + s->quit = 1; text = imap_bye; text_len = sizeof(imap_bye) - 1; - quit = 1; break; case NGX_IMAP_NOOP: @@ -260,18 +351,19 @@ ngx_imap_auth_state(ngx_event_t *rev) } if (tag) { - if (s->out.len < text_len + s->tag.len + last_len) { - - s->out.len = text_len + s->tag.len + last_len; - s->out.data = ngx_palloc(c->pool, s->out.len); - if (s->out.data == NULL) { + if (s->tagged_line.len < s->tag.len + text_len + last_len) { + s->tagged_line.len = s->tag.len + text_len + last_len; + s->tagged_line.data = ngx_palloc(c->pool, s->tagged_line.len); + if (s->tagged_line.data == NULL) { ngx_imap_close_connection(c); return; } } - out = s->out.data; - p = out; + s->out.data = s->tagged_line.data; + s->out.len = s->tag.len + text_len + last_len; + + p = s->out.data; if (text) { p = ngx_cpymem(p, text, text_len); @@ -279,35 +371,20 @@ ngx_imap_auth_state(ngx_event_t *rev) p = ngx_cpymem(p, s->tag.data, s->tag.len); ngx_memcpy(p, last, last_len); - size = text_len + s->tag.len + last_len; } else { - out = last; - size = last_len; + s->out.data = last; + s->out.len = last_len; } - if (ngx_send(c, out, size) < size) { - /* - * we treat the incomplete sending as NGX_ERROR - * because it is very strange here - */ - ngx_imap_close_connection(c); - return; + if (rc != NGX_IMAP_NEXT) { + s->args.nelts = 0; + s->buffer->pos = s->buffer->start; + s->buffer->last = s->buffer->start; + s->tag.len = 0; } - if (rc == NGX_IMAP_NEXT) { - return; - } - - if (quit) { - ngx_imap_close_connection(c); - return; - } - - s->args.nelts = 0; - s->buffer->pos = s->buffer->start; - s->buffer->last = s->buffer->start; - s->tag.len = 0; + ngx_imap_send(c->write); } @@ -317,7 +394,6 @@ ngx_pop3_auth_state(ngx_event_t *rev) u_char *text; ssize_t size; ngx_int_t rc; - ngx_uint_t quit; ngx_str_t *arg; ngx_connection_t *c; ngx_imap_session_t *s; @@ -334,13 +410,20 @@ ngx_pop3_auth_state(ngx_event_t *rev) return; } + if (s->out.len) { + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap send handler busy"); + s->blocked = 1; + return; + } + + s->blocked = 0; + rc = ngx_imap_read_command(s); if (rc == NGX_AGAIN || rc == NGX_ERROR) { return; } - quit = 0; text = pop3_ok; size = sizeof(pop3_ok) - 1; @@ -381,7 +464,7 @@ ngx_pop3_auth_state(ngx_event_t *rev) break; case NGX_POP3_QUIT: - quit = 1; + s->quit = 1; break; case NGX_POP3_NOOP: @@ -441,7 +524,7 @@ ngx_pop3_auth_state(ngx_event_t *rev) break; case NGX_POP3_QUIT: - quit = 1; + s->quit = 1; break; case NGX_POP3_NOOP: @@ -466,23 +549,14 @@ ngx_pop3_auth_state(ngx_event_t *rev) size = sizeof(pop3_invalid_command) - 1; } - if (ngx_send(c, text, size) < size) { - /* - * we treat the incomplete sending as NGX_ERROR - * because it is very strange here - */ - ngx_imap_close_connection(c); - return; - } - - if (quit) { - ngx_imap_close_connection(c); - return; - } - s->args.nelts = 0; s->buffer->pos = s->buffer->start; s->buffer->last = s->buffer->start; + + s->out.data = text; + s->out.len = size; + + ngx_imap_send(c->write); } @@ -492,8 +566,8 @@ ngx_imap_read_command(ngx_imap_session_t ssize_t n; ngx_int_t rc; - n = ngx_recv(s->connection, s->buffer->last, - s->buffer->end - s->buffer->last); + n = s->connection->recv(s->connection, s->buffer->last, + s->buffer->end - s->buffer->last); if (n == NGX_ERROR || n == 0) { ngx_imap_close_connection(s->connection); @@ -538,10 +612,10 @@ ngx_imap_read_command(ngx_imap_session_t void ngx_imap_session_internal_server_error(ngx_imap_session_t *s) { - (void) ngx_send(s->connection, internal_server_errors[s->protocol].data, - internal_server_errors[s->protocol].len); + s->out = internal_server_errors[s->protocol]; + s->quit = 1; - ngx_imap_close_connection(s->connection); + ngx_imap_send(s->connection->write); } @@ -553,9 +627,42 @@ ngx_imap_close_connection(ngx_connection ngx_log_debug1(NGX_LOG_DEBUG_IMAP, c->log, 0, "close imap connection: %d", c->fd); +#if (NGX_IMAP_SSL) + + if (c->ssl) { + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + c->read->handler = ngx_imap_ssl_close_handler; + c->write->handler = ngx_imap_ssl_close_handler; + return; + } + } + +#endif + pool = c->pool; ngx_close_connection(c); ngx_destroy_pool(pool); } + + +#if (NGX_IMAP_SSL) + +static void +ngx_imap_ssl_close_handler(ngx_event_t *ev) +{ + ngx_connection_t *c; + + c = ev->data; + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "http ssl close handler"); + + if (ngx_ssl_shutdown(c) == NGX_AGAIN) { + return; + } + + ngx_imap_close_connection(c); +} + +#endif diff --git a/src/imap/ngx_imap_proxy_module.c b/src/imap/ngx_imap_proxy_module.c --- a/src/imap/ngx_imap_proxy_module.c +++ b/src/imap/ngx_imap_proxy_module.c @@ -13,6 +13,8 @@ typedef struct { ngx_flag_t enable; + size_t buffer_size; + ngx_msec_t timeout; } ngx_imap_proxy_conf_t; @@ -35,6 +37,7 @@ static char *ngx_imap_proxy_merge_conf(n static ngx_command_t ngx_imap_proxy_commands[] = { + { ngx_string("proxy"), NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -42,6 +45,20 @@ static ngx_command_t ngx_imap_proxy_com offsetof(ngx_imap_proxy_conf_t, enable), NULL }, + { ngx_string("proxy_buffer"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_size_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_proxy_conf_t, buffer_size), + NULL }, + + { ngx_string("proxy_timeout"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_proxy_conf_t, timeout), + NULL }, + ngx_null_command }; @@ -131,12 +148,12 @@ ngx_imap_proxy_block_read(ngx_event_t *r static void ngx_imap_proxy_imap_handler(ngx_event_t *rev) { - u_char *p; - ngx_int_t rc; - ngx_str_t line; - ngx_connection_t *c; - ngx_imap_session_t *s; - ngx_imap_core_srv_conf_t *cscf; + u_char *p; + ngx_int_t rc; + ngx_str_t line; + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_proxy_conf_t *pcf; ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy imap auth handler"); @@ -152,10 +169,9 @@ ngx_imap_proxy_imap_handler(ngx_event_t } if (s->proxy->buffer == NULL) { - cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); + pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); - s->proxy->buffer = ngx_create_temp_buf(c->pool, - cscf->proxy_buffer_size); + s->proxy->buffer = ngx_create_temp_buf(c->pool, pcf->buffer_size); if (s->proxy->buffer == NULL) { ngx_imap_proxy_internal_server_error(s); return; @@ -247,7 +263,7 @@ ngx_imap_proxy_imap_handler(ngx_event_t break; } - if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) { + if (c->send(c, line.data, line.len) < (ssize_t) line.len) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here @@ -265,6 +281,8 @@ ngx_imap_proxy_imap_handler(ngx_event_t rev->handler = ngx_imap_proxy_handler; c->write->handler = ngx_imap_proxy_handler; + pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); + ngx_add_timer(s->connection->read, pcf->timeout); ngx_del_timer(c->read); } } @@ -273,12 +291,12 @@ ngx_imap_proxy_imap_handler(ngx_event_t static void ngx_imap_proxy_pop3_handler(ngx_event_t *rev) { - u_char *p; - ngx_int_t rc; - ngx_str_t line; - ngx_connection_t *c; - ngx_imap_session_t *s; - ngx_imap_core_srv_conf_t *cscf; + u_char *p; + ngx_int_t rc; + ngx_str_t line; + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_proxy_conf_t *pcf; ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, "imap proxy pop3 auth handler"); @@ -294,10 +312,9 @@ ngx_imap_proxy_pop3_handler(ngx_event_t } if (s->proxy->buffer == NULL) { - cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); + pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); - s->proxy->buffer = ngx_create_temp_buf(c->pool, - cscf->proxy_buffer_size); + s->proxy->buffer = ngx_create_temp_buf(c->pool, pcf->buffer_size); if (s->proxy->buffer == NULL) { ngx_imap_proxy_internal_server_error(s); return; @@ -369,7 +386,7 @@ ngx_imap_proxy_pop3_handler(ngx_event_t break; } - if (ngx_send(c, line.data, line.len) < (ssize_t) line.len) { + if (c->send(c, line.data, line.len) < (ssize_t) line.len) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here @@ -387,6 +404,8 @@ ngx_imap_proxy_pop3_handler(ngx_event_t rev->handler = ngx_imap_proxy_handler; c->write->handler = ngx_imap_proxy_handler; + pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); + ngx_add_timer(s->connection->read, pcf->timeout); ngx_del_timer(c->read); } } @@ -408,7 +427,8 @@ ngx_imap_proxy_read_response(ngx_imap_se b = s->proxy->buffer; - n = ngx_recv(s->proxy->upstream.connection, b->last, b->end - b->last); + n = s->proxy->upstream.connection->recv(s->proxy->upstream.connection, + b->last, b->end - b->last); if (n == NGX_ERROR || n == 0) { return NGX_ERROR; @@ -475,12 +495,13 @@ ngx_imap_proxy_read_response(ngx_imap_se static void ngx_imap_proxy_handler(ngx_event_t *ev) { - size_t size; - ssize_t n; - ngx_buf_t *b; - ngx_uint_t again, do_write; - ngx_connection_t *c, *src, *dst; - ngx_imap_session_t *s; + size_t size; + ssize_t n; + ngx_buf_t *b; + ngx_uint_t again, do_write; + ngx_connection_t *c, *src, *dst; + ngx_imap_session_t *s; + ngx_imap_proxy_conf_t *pcf; c = ev->data; s = c->data; @@ -537,7 +558,7 @@ ngx_imap_proxy_handler(ngx_event_t *ev) size = b->last - b->pos; if (size && dst->write->ready) { - n = ngx_send(dst, b->pos, size); + n = dst->send(dst, b->pos, size); if (n == NGX_ERROR) { ngx_imap_proxy_close_session(s); @@ -568,7 +589,7 @@ ngx_imap_proxy_handler(ngx_event_t *ev) size = b->end - b->last; if (size && src->read->ready) { - n = ngx_recv(src, b->last, size); + n = src->recv(src, b->last, size); if (n == NGX_ERROR || n == 0) { ngx_imap_proxy_close_session(s); @@ -587,6 +608,11 @@ ngx_imap_proxy_handler(ngx_event_t *ev) return; } } + + if (c == s->connection) { + pcf = ngx_imap_get_module_srv_conf(s, ngx_imap_proxy_module); + ngx_add_timer(c->read, pcf->timeout); + } } } while (again); @@ -634,6 +660,8 @@ ngx_imap_proxy_create_conf(ngx_conf_t *c } pcf->enable = NGX_CONF_UNSET; + pcf->buffer_size = NGX_CONF_UNSET_SIZE; + pcf->timeout = NGX_CONF_UNSET_MSEC; return pcf; } @@ -645,7 +673,10 @@ ngx_imap_proxy_merge_conf(ngx_conf_t *cf ngx_imap_proxy_conf_t *prev = parent; ngx_imap_proxy_conf_t *conf = child; - ngx_conf_merge_msec_value(conf->enable, prev->enable, 0); + ngx_conf_merge_value(conf->enable, prev->enable, 0); + ngx_conf_merge_size_value(conf->buffer_size, prev->buffer_size, + (size_t) ngx_pagesize); + ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 24 * 60 * 60000); return NGX_CONF_OK; } diff --git a/src/imap/ngx_imap_ssl_module.c b/src/imap/ngx_imap_ssl_module.c new file mode 100644 --- /dev/null +++ b/src/imap/ngx_imap_ssl_module.c @@ -0,0 +1,174 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +#define NGX_DEFLAUT_CERTIFICATE "cert.pem" +#define NGX_DEFLAUT_CERTIFICATE_KEY "cert.pem" + + +static void *ngx_imap_ssl_create_conf(ngx_conf_t *cf); +static char *ngx_imap_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); + + +static ngx_command_t ngx_imap_ssl_commands[] = { + + { ngx_string("ssl"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_ssl_conf_t, enable), + NULL }, + + { ngx_string("ssl_certificate"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_ssl_conf_t, certificate), + NULL }, + + { ngx_string("ssl_certificate_key"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_ssl_conf_t, certificate_key), + NULL }, + + { ngx_string("ssl_ciphers"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_ssl_conf_t, ciphers), + NULL }, + + ngx_null_command +}; + + +static ngx_imap_module_t ngx_imap_ssl_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_ssl_create_conf, /* create server configuration */ + ngx_imap_ssl_merge_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_imap_ssl_module = { + NGX_MODULE_V1, + &ngx_imap_ssl_module_ctx, /* module context */ + ngx_imap_ssl_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static void * +ngx_imap_ssl_create_conf(ngx_conf_t *cf) +{ + ngx_imap_ssl_conf_t *scf; + + scf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_ssl_conf_t)); + if (scf == NULL) { + return NGX_CONF_ERROR; + } + + /* + * set by ngx_pcalloc(): + * + * scf->certificate.len = 0; + * scf->certificate.data = NULL; + * scf->certificate_key.len = 0; + * scf->certificate_key.data = NULL; + * scf->ciphers.len = 0; + * scf->ciphers.data = NULL; + */ + + scf->enable = NGX_CONF_UNSET; + + return scf; +} + + +static char * +ngx_imap_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_imap_ssl_conf_t *prev = parent; + ngx_imap_ssl_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + if (conf->enable == 0) { + return NGX_CONF_OK; + } + + ngx_conf_merge_str_value(conf->certificate, prev->certificate, + NGX_DEFLAUT_CERTIFICATE); + + ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, + NGX_DEFLAUT_CERTIFICATE_KEY); + + ngx_conf_merge_str_value(conf->ciphers, prev->ciphers, ""); + + + /* TODO: configure methods */ + + conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method()); + + if (conf->ssl_ctx == NULL) { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "SSL_CTX_new() failed"); + return NGX_CONF_ERROR; + } + + if (ngx_pool_cleanup_add(cf->pool, ngx_ssl_cleanup_ctx, conf->ssl_ctx) + == NULL) + { + return NGX_CONF_ERROR; + } + + +#if 0 + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_ALL); + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_NO_SSLv3); + SSL_CTX_set_options(conf->ssl_ctx, SSL_OP_SINGLE_DH_USE); +#endif + + if (conf->ciphers.len) { + if (SSL_CTX_set_cipher_list(conf->ssl_ctx, + (const char *) conf->ciphers.data) == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_set_cipher_list(\"%V\") failed", + &conf->ciphers); + } + } + + if (SSL_CTX_use_certificate_chain_file(conf->ssl_ctx, + (char *) conf->certificate.data) == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_use_certificate_chain_file(\"%s\") failed", + conf->certificate.data); + return NGX_CONF_ERROR; + } + + + if (SSL_CTX_use_PrivateKey_file(conf->ssl_ctx, + (char *) conf->certificate_key.data, + SSL_FILETYPE_PEM) == 0) + { + ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, + "SSL_CTX_use_PrivateKey_file(\"%s\") failed", + conf->certificate_key.data); + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} diff --git a/src/imap/ngx_imap_ssl_module.h b/src/imap/ngx_imap_ssl_module.h new file mode 100644 --- /dev/null +++ b/src/imap/ngx_imap_ssl_module.h @@ -0,0 +1,30 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#ifndef _NGX_IMAP_SSL_H_INCLUDED_ +#define _NGX_IMAP_SSL_H_INCLUDED_ + + +#include +#include +#include + + +typedef struct { + ngx_flag_t enable; + ngx_str_t certificate; + ngx_str_t certificate_key; + + ngx_str_t ciphers; + + ngx_ssl_ctx_t *ssl_ctx; +} ngx_imap_ssl_conf_t; + + +extern ngx_module_t ngx_imap_ssl_module; + + +#endif /* _NGX_IMAP_SSL_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -99,5 +99,7 @@ pid_t rfork_thread(int flags, void *stac extern char *malloc_options; +#define NGX_HAVE_OS_SPECIFIC_INIT 1 + #endif /* _NGX_FREEBSD_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_freebsd_init.c b/src/os/unix/ngx_freebsd_init.c --- a/src/os/unix/ngx_freebsd_init.c +++ b/src/os/unix/ngx_freebsd_init.c @@ -27,7 +27,7 @@ ngx_uint_t ngx_freebsd_sendfile_nbytes_b ngx_uint_t ngx_freebsd_use_tcp_nopush; -ngx_os_io_t ngx_os_io = { +static ngx_os_io_t ngx_freebsd_io = { ngx_unix_recv, ngx_readv_chain, ngx_unix_send, @@ -74,7 +74,8 @@ sysctl_t sysctls[] = { }; -void ngx_debug_init() +void +ngx_debug_init() { #if (NGX_DEBUG && !NGX_NO_DEBUG_MALLOC) @@ -88,7 +89,8 @@ void ngx_debug_init() } -ngx_int_t ngx_os_init(ngx_log_t *log) +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) { int version, somaxconn; size_t size; @@ -223,12 +225,14 @@ ngx_int_t ngx_os_init(ngx_log_t *log) ngx_tcp_nodelay_and_tcp_nopush = 1; + ngx_os_io = ngx_freebsd_io; - return ngx_posix_init(log); + return NGX_OK; } -void ngx_os_status(ngx_log_t *log) +void +ngx_os_specific_status(ngx_log_t *log) { ngx_uint_t i; @@ -251,7 +255,4 @@ void ngx_os_status(ngx_log_t *log) sysctls[i].name, *sysctls[i].value); } } - - - ngx_posix_status(log); } diff --git a/src/os/unix/ngx_freebsd_sendfile_chain.c b/src/os/unix/ngx_freebsd_sendfile_chain.c --- a/src/os/unix/ngx_freebsd_sendfile_chain.c +++ b/src/os/unix/ngx_freebsd_sendfile_chain.c @@ -56,7 +56,11 @@ ngx_freebsd_sendfile_chain(ngx_connectio #if (NGX_HAVE_KQUEUE) - if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) && wev->pending_eof) { + if ((ngx_event_flags & NGX_USE_KQUEUE_EVENT) + && wev->pending_eof + /* FreeBSD 6.0 may erroneously report ETIMEDOUT */ + && wev->kq_errno != NGX_ETIMEDOUT) + { (void) ngx_connection_error(c, wev->kq_errno, "kevent() reported about an closed connection"); wev->error = 1; diff --git a/src/os/unix/ngx_linux_config.h b/src/os/unix/ngx_linux_config.h --- a/src/os/unix/ngx_linux_config.h +++ b/src/os/unix/ngx_linux_config.h @@ -103,4 +103,7 @@ extern ssize_t sendfile(int s, int fd, i #endif +#define NGX_HAVE_OS_SPECIFIC_INIT 1 + + #endif /* _NGX_LINUX_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_linux_init.c b/src/os/unix/ngx_linux_init.c --- a/src/os/unix/ngx_linux_init.c +++ b/src/os/unix/ngx_linux_init.c @@ -14,7 +14,7 @@ char ngx_linux_kern_osrelease[20]; int ngx_linux_rtsig_max; -ngx_os_io_t ngx_os_io = { +static ngx_os_io_t ngx_linux_io = { ngx_unix_recv, ngx_readv_chain, ngx_unix_send, @@ -29,7 +29,7 @@ ngx_os_io_t ngx_os_io = { ngx_int_t -ngx_os_init(ngx_log_t *log) +ngx_os_specific_init(ngx_log_t *log) { int name[2]; size_t len; @@ -74,19 +74,18 @@ ngx_os_init(ngx_log_t *log) } - return ngx_posix_init(log); + ngx_os_io = ngx_linux_io; + + return NGX_OK; } void -ngx_os_status(ngx_log_t *log) +ngx_os_specific_status(ngx_log_t *log) { ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", ngx_linux_kern_ostype, ngx_linux_kern_osrelease); ngx_log_error(NGX_LOG_NOTICE, log, 0, "sysctl(KERN_RTSIGMAX): %d", ngx_linux_rtsig_max); - - - ngx_posix_status(log); } diff --git a/src/os/unix/ngx_os.h b/src/os/unix/ngx_os.h --- a/src/os/unix/ngx_os.h +++ b/src/os/unix/ngx_os.h @@ -34,10 +34,9 @@ typedef struct { void ngx_debug_init(void); ngx_int_t ngx_os_init(ngx_log_t *log); void ngx_os_status(ngx_log_t *log); +ngx_int_t ngx_os_specific_init(ngx_log_t *log); +void ngx_os_specific_status(ngx_log_t *log); ngx_int_t ngx_daemon(ngx_log_t *log); -ngx_int_t ngx_posix_init(ngx_log_t *log); -void ngx_posix_status(ngx_log_t *log); -ngx_int_t ngx_posix_post_conf_init(ngx_log_t *log); ssize_t ngx_unix_recv(ngx_connection_t *c, u_char *buf, size_t size); diff --git a/src/os/unix/ngx_posix_config.h b/src/os/unix/ngx_posix_config.h --- a/src/os/unix/ngx_posix_config.h +++ b/src/os/unix/ngx_posix_config.h @@ -102,7 +102,4 @@ #endif -#define NGX_POSIX_IO 1 - - #endif /* _NGX_POSIX_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_posix_init.c b/src/os/unix/ngx_posix_init.c --- a/src/os/unix/ngx_posix_init.c +++ b/src/os/unix/ngx_posix_init.c @@ -6,6 +6,7 @@ #include #include +#include ngx_int_t ngx_ncpu; @@ -17,8 +18,6 @@ ngx_uint_t ngx_tcp_nodelay_and_tcp_nopu struct rlimit rlmt; -#if (NGX_POSIX_IO) - ngx_os_io_t ngx_os_io = { ngx_unix_recv, ngx_readv_chain, @@ -28,74 +27,16 @@ ngx_os_io_t ngx_os_io = { }; -ngx_int_t ngx_os_init(ngx_log_t *log) -{ - return ngx_posix_init(log); -} - - -void ngx_os_status(ngx_log_t *log) +ngx_int_t +ngx_os_init(ngx_log_t *log) { - ngx_posix_status(log); -} - - -#endif - - -void ngx_signal_handler(int signo); - - -typedef struct { - int signo; - char *signame; - void (*handler)(int signo); -} ngx_signal_t; - - -ngx_signal_t signals[] = { - { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), - "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), - ngx_signal_handler }, - - { ngx_signal_value(NGX_REOPEN_SIGNAL), - "SIG" ngx_value(NGX_REOPEN_SIGNAL), - ngx_signal_handler }, + ngx_log_error(NGX_LOG_NOTICE, log, 0, NGINX_VER); - { ngx_signal_value(NGX_NOACCEPT_SIGNAL), - "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), - ngx_signal_handler }, - - { ngx_signal_value(NGX_TERMINATE_SIGNAL), - "SIG" ngx_value(NGX_TERMINATE_SIGNAL), - ngx_signal_handler }, - - { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), - "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), - ngx_signal_handler }, - - { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), - "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), - ngx_signal_handler }, - - { SIGALRM, "SIGALRM", ngx_signal_handler }, - - { SIGINT, "SIGINT", ngx_signal_handler }, - - { SIGIO, "SIGIO", ngx_signal_handler }, - - { SIGCHLD, "SIGCHLD", ngx_signal_handler }, - - { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN }, - - { 0, NULL, NULL } -}; - - -ngx_int_t ngx_posix_init(ngx_log_t *log) -{ - ngx_signal_t *sig; - struct sigaction sa; +#if (NGX_HAVE_OS_SPECIFIC_INIT) + if (ngx_os_specific_init(log) != NGX_OK) { + return NGX_ERROR; + } +#endif ngx_init_setproctitle(log); @@ -105,23 +46,12 @@ ngx_int_t ngx_posix_init(ngx_log_t *log) ngx_ncpu = 1; } - for (sig = signals; sig->signo != 0; sig++) { - ngx_memzero(&sa, sizeof(struct sigaction)); - sa.sa_handler = sig->handler; - sigemptyset(&sa.sa_mask); - if (sigaction(sig->signo, &sa, NULL) == -1) { - ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, - "sigaction(%s) failed", sig->signame); - return NGX_ERROR; - } - } - if (getrlimit(RLIMIT_NOFILE, &rlmt) == -1) { ngx_log_error(NGX_LOG_ALERT, log, errno, "getrlimit(RLIMIT_NOFILE) failed)"); return NGX_ERROR; } - + ngx_max_sockets = rlmt.rlim_cur; #if (NGX_HAVE_INHERITED_NONBLOCK) @@ -134,157 +64,21 @@ ngx_int_t ngx_posix_init(ngx_log_t *log) } -void ngx_posix_status(ngx_log_t *log) +void +ngx_os_status(ngx_log_t *log) { +#if (NGX_HAVE_OS_SPECIFIC_INIT) + ngx_os_specific_status(log); +#endif + ngx_log_error(NGX_LOG_NOTICE, log, 0, "getrlimit(RLIMIT_NOFILE): %r:%r", rlmt.rlim_cur, rlmt.rlim_max); } -void ngx_signal_handler(int signo) -{ - char *action; - struct timeval tv; - ngx_int_t ignore; - ngx_err_t err; - ngx_signal_t *sig; - - ignore = 0; - - err = ngx_errno; - - for (sig = signals; sig->signo != 0; sig++) { - if (sig->signo == signo) { - break; - } - } - - ngx_gettimeofday(&tv); - ngx_time_update(tv.tv_sec); - - action = ""; - - switch (ngx_process) { - - case NGX_PROCESS_MASTER: - case NGX_PROCESS_SINGLE: - switch (signo) { - - case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): - ngx_quit = 1; - action = ", shutting down"; - break; - - case ngx_signal_value(NGX_TERMINATE_SIGNAL): - case SIGINT: - ngx_terminate = 1; - action = ", exiting"; - break; - - case ngx_signal_value(NGX_NOACCEPT_SIGNAL): - ngx_noaccept = 1; - action = ", stop accepting connections"; - break; - - case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): - ngx_reconfigure = 1; - action = ", reconfiguring"; - break; - - case ngx_signal_value(NGX_REOPEN_SIGNAL): - ngx_reopen = 1; - action = ", reopening logs"; - break; - - case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): - if (getppid() > 1 || ngx_new_binary > 0) { - - /* - * Ignore the signal in the new binary if its parent is - * not the init process, i.e. the old binary's process - * is still running. Or ingore the signal in the old binary's - * process if the new binary's process is already running. - */ - - action = ", ignoring"; - ignore = 1; - break; - } - - ngx_change_binary = 1; - action = ", changing binary"; - break; - - case SIGALRM: - if (!ngx_terminate) { - ngx_timer = 1; - action = ", shutting down old worker processes"; - } - - break; - - case SIGIO: - ngx_sigio = 1; - break; - - case SIGCHLD: - ngx_reap = 1; - break; - } - - break; - - case NGX_PROCESS_WORKER: - switch (signo) { - - case ngx_signal_value(NGX_NOACCEPT_SIGNAL): - ngx_debug_quit = 1; - case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): - ngx_quit = 1; - action = ", shutting down"; - break; - - case ngx_signal_value(NGX_TERMINATE_SIGNAL): - case SIGINT: - ngx_terminate = 1; - action = ", exiting"; - break; - - case ngx_signal_value(NGX_REOPEN_SIGNAL): - ngx_reopen = 1; - action = ", reopening logs"; - break; - - case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): - case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): - case SIGIO: - action = ", ignoring"; - break; - } - - break; - } - - ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, - "signal %d (%s) received%s", signo, sig->signame, action); - - if (ignore) { - ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, - "the changing binary signal is ignored: " - "you should shutdown or terminate " - "before either old or new binary's process"); - } - - if (signo == SIGCHLD) { - ngx_process_get_status(); - } - - ngx_set_errno(err); -} - - -ngx_int_t ngx_posix_post_conf_init(ngx_log_t *log) +ngx_int_t +ngx_posix_post_conf_init(ngx_log_t *log) { ngx_fd_t pp[2]; diff --git a/src/os/unix/ngx_process.c b/src/os/unix/ngx_process.c --- a/src/os/unix/ngx_process.c +++ b/src/os/unix/ngx_process.c @@ -10,7 +10,17 @@ #include +typedef struct { + int signo; + char *signame; + void (*handler)(int signo); +} ngx_signal_t; + + + static void ngx_execute_proc(ngx_cycle_t *cycle, void *data); +static void ngx_signal_handler(int signo); +static void ngx_process_get_status(void); int ngx_argc; @@ -23,6 +33,45 @@ ngx_int_t ngx_last_process; ngx_process_t ngx_processes[NGX_MAX_PROCESSES]; +ngx_signal_t signals[] = { + { ngx_signal_value(NGX_RECONFIGURE_SIGNAL), + "SIG" ngx_value(NGX_RECONFIGURE_SIGNAL), + ngx_signal_handler }, + + { ngx_signal_value(NGX_REOPEN_SIGNAL), + "SIG" ngx_value(NGX_REOPEN_SIGNAL), + ngx_signal_handler }, + + { ngx_signal_value(NGX_NOACCEPT_SIGNAL), + "SIG" ngx_value(NGX_NOACCEPT_SIGNAL), + ngx_signal_handler }, + + { ngx_signal_value(NGX_TERMINATE_SIGNAL), + "SIG" ngx_value(NGX_TERMINATE_SIGNAL), + ngx_signal_handler }, + + { ngx_signal_value(NGX_SHUTDOWN_SIGNAL), + "SIG" ngx_value(NGX_SHUTDOWN_SIGNAL), + ngx_signal_handler }, + + { ngx_signal_value(NGX_CHANGEBIN_SIGNAL), + "SIG" ngx_value(NGX_CHANGEBIN_SIGNAL), + ngx_signal_handler }, + + { SIGALRM, "SIGALRM", ngx_signal_handler }, + + { SIGINT, "SIGINT", ngx_signal_handler }, + + { SIGIO, "SIGIO", ngx_signal_handler }, + + { SIGCHLD, "SIGCHLD", ngx_signal_handler }, + + { SIGPIPE, "SIGPIPE, SIG_IGN", SIG_IGN }, + + { 0, NULL, NULL } +}; + + ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn) @@ -208,7 +257,171 @@ ngx_execute_proc(ngx_cycle_t *cycle, voi } +ngx_int_t +ngx_init_signals(ngx_log_t *log) +{ + ngx_signal_t *sig; + struct sigaction sa; + + for (sig = signals; sig->signo != 0; sig++) { + ngx_memzero(&sa, sizeof(struct sigaction)); + sa.sa_handler = sig->handler; + sigemptyset(&sa.sa_mask); + if (sigaction(sig->signo, &sa, NULL) == -1) { + ngx_log_error(NGX_LOG_EMERG, log, ngx_errno, + "sigaction(%s) failed", sig->signame); + return NGX_ERROR; + } + } + + return NGX_OK; +} + + void +ngx_signal_handler(int signo) +{ + char *action; + struct timeval tv; + ngx_int_t ignore; + ngx_err_t err; + ngx_signal_t *sig; + + ignore = 0; + + err = ngx_errno; + + for (sig = signals; sig->signo != 0; sig++) { + if (sig->signo == signo) { + break; + } + } + + ngx_gettimeofday(&tv); + ngx_time_update(tv.tv_sec); + + action = ""; + + switch (ngx_process) { + + case NGX_PROCESS_MASTER: + case NGX_PROCESS_SINGLE: + switch (signo) { + + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + action = ", shutting down"; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + case SIGINT: + ngx_terminate = 1; + action = ", exiting"; + break; + + case ngx_signal_value(NGX_NOACCEPT_SIGNAL): + ngx_noaccept = 1; + action = ", stop accepting connections"; + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + ngx_reconfigure = 1; + action = ", reconfiguring"; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + action = ", reopening logs"; + break; + + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + if (getppid() > 1 || ngx_new_binary > 0) { + + /* + * Ignore the signal in the new binary if its parent is + * not the init process, i.e. the old binary's process + * is still running. Or ingore the signal in the old binary's + * process if the new binary's process is already running. + */ + + action = ", ignoring"; + ignore = 1; + break; + } + + ngx_change_binary = 1; + action = ", changing binary"; + break; + + case SIGALRM: + if (!ngx_terminate) { + ngx_timer = 1; + action = ", shutting down old worker processes"; + } + + break; + + case SIGIO: + ngx_sigio = 1; + break; + + case SIGCHLD: + ngx_reap = 1; + break; + } + + break; + + case NGX_PROCESS_WORKER: + switch (signo) { + + case ngx_signal_value(NGX_NOACCEPT_SIGNAL): + ngx_debug_quit = 1; + case ngx_signal_value(NGX_SHUTDOWN_SIGNAL): + ngx_quit = 1; + action = ", shutting down"; + break; + + case ngx_signal_value(NGX_TERMINATE_SIGNAL): + case SIGINT: + ngx_terminate = 1; + action = ", exiting"; + break; + + case ngx_signal_value(NGX_REOPEN_SIGNAL): + ngx_reopen = 1; + action = ", reopening logs"; + break; + + case ngx_signal_value(NGX_RECONFIGURE_SIGNAL): + case ngx_signal_value(NGX_CHANGEBIN_SIGNAL): + case SIGIO: + action = ", ignoring"; + break; + } + + break; + } + + ngx_log_error(NGX_LOG_NOTICE, ngx_cycle->log, 0, + "signal %d (%s) received%s", signo, sig->signame, action); + + if (ignore) { + ngx_log_error(NGX_LOG_CRIT, ngx_cycle->log, 0, + "the changing binary signal is ignored: " + "you should shutdown or terminate " + "before either old or new binary's process"); + } + + if (signo == SIGCHLD) { + ngx_process_get_status(); + } + + ngx_set_errno(err); +} + + +static void ngx_process_get_status(void) { int status; diff --git a/src/os/unix/ngx_process.h b/src/os/unix/ngx_process.h --- a/src/os/unix/ngx_process.h +++ b/src/os/unix/ngx_process.h @@ -54,7 +54,7 @@ typedef struct { ngx_pid_t ngx_spawn_process(ngx_cycle_t *cycle, ngx_spawn_proc_pt proc, void *data, char *name, ngx_int_t respawn); ngx_pid_t ngx_execute(ngx_cycle_t *cycle, ngx_exec_ctx_t *ctx); -void ngx_process_get_status(void); +ngx_int_t ngx_init_signals(ngx_log_t *log); void ngx_debug_point(void); diff --git a/src/os/unix/ngx_solaris_config.h b/src/os/unix/ngx_solaris_config.h --- a/src/os/unix/ngx_solaris_config.h +++ b/src/os/unix/ngx_solaris_config.h @@ -83,4 +83,7 @@ #endif +#define NGX_HAVE_OS_SPECIFIC_INIT 1 + + #endif /* _NGX_SOLARIS_CONFIG_H_INCLUDED_ */ diff --git a/src/os/unix/ngx_solaris_init.c b/src/os/unix/ngx_solaris_init.c --- a/src/os/unix/ngx_solaris_init.c +++ b/src/os/unix/ngx_solaris_init.c @@ -13,7 +13,7 @@ char ngx_solaris_release[10]; char ngx_solaris_version[50]; -ngx_os_io_t ngx_os_io = { +static ngx_os_io_t ngx_solaris_io = { ngx_unix_recv, ngx_readv_chain, ngx_unix_send, @@ -27,10 +27,11 @@ ngx_os_io_t ngx_os_io = { }; -ngx_int_t ngx_os_init(ngx_log_t *log) +ngx_int_t +ngx_os_specific_init(ngx_log_t *log) { if (sysinfo(SI_SYSNAME, ngx_solaris_sysname, sizeof(ngx_solaris_sysname)) - == -1) + == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sysinfo(SI_SYSNAME) failed"); @@ -38,7 +39,7 @@ ngx_int_t ngx_os_init(ngx_log_t *log) } if (sysinfo(SI_RELEASE, ngx_solaris_release, sizeof(ngx_solaris_release)) - == -1) + == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sysinfo(SI_RELEASE) failed"); @@ -46,7 +47,7 @@ ngx_int_t ngx_os_init(ngx_log_t *log) } if (sysinfo(SI_VERSION, ngx_solaris_version, sizeof(ngx_solaris_version)) - == -1) + == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, "sysinfo(SI_SYSNAME) failed"); @@ -54,11 +55,14 @@ ngx_int_t ngx_os_init(ngx_log_t *log) } - return ngx_posix_init(log); + ngx_os_io = ngx_solaris_io; + + return NGX_OK;; } -void ngx_os_status(ngx_log_t *log) +void +ngx_os_specific_status(ngx_log_t *log) { ngx_log_error(NGX_LOG_NOTICE, log, 0, "OS: %s %s", @@ -66,6 +70,4 @@ void ngx_os_status(ngx_log_t *log) ngx_log_error(NGX_LOG_NOTICE, log, 0, "version: %s", ngx_solaris_version); - - ngx_posix_status(log); }