# HG changeset patch # User Igor Sysoev # Date 1118159791 0 # Node ID 6f00349b98e5f706b82115c6e4dc84456fc0d770 # Parent 1fecc7e0d717aed8917ac3aca3740fee5e9268c5 nginx-0.1.35-RELEASE import *) Feature: the "working_directory" directive. *) Feature: the "port_in_redirect" directive. *) Bugfix: the segmentation fault was occurred if the backend response header was in several packets; the bug had appeared in 0.1.29. *) Bugfix: if more than 10 servers were configured or some server did not use the "listen" directive, then the segmentation fault was occurred on the start. *) Bugfix: the segmentation fault might occur if the response was bigger than the temporary file. *) Bugfix: nginx returned the 400 response on requests like "GET http://www.domain.com/uri HTTP/1.0"; the bug had appeared in 0.1.28. diff --git a/auto/cc/gcc b/auto/cc/gcc --- a/auto/cc/gcc +++ b/auto/cc/gcc @@ -4,7 +4,7 @@ # gcc 2.7.2.3, 2.8.1, 2.95.4, egcs-1.1.2 # 3.0.4, 3.1.1, 3.2.3, 3.3.2, 3.3.3, 3.3.4, 3.4.0, 3.4.2 -# 4.0.0 +# 4.0.0, 4.0.1, 4.1.0 NGX_GCC_VER=`$CC -v 2>&1 | grep 'gcc version' 2>&1 \ @@ -57,6 +57,11 @@ case $CPU in CPU_OPT="-march=pentium4" ;; + athlon) + # optimize for Athlon, gcc 3.x + CPU_OPT="-march=athlon" + ;; + opteron) # optimize for Opteron, gcc 3.x CPU_OPT="-march=opteron" diff --git a/auto/cc/icc b/auto/cc/icc --- a/auto/cc/icc +++ b/auto/cc/icc @@ -4,6 +4,12 @@ # Intel C++ compiler 7.1, 8.0, 8.1 +NGX_ICC_VER=`$CC -V 2>&1 | grep 'Version' 2>&1 \ + | sed -e 's/^.* Version \(.*\) Build.*$/\1/'` + +echo " + icc version: $NGX_ICC_VER" + + # optimizations CFLAGS="$CFLAGS -O" @@ -72,8 +78,6 @@ CFLAGS="$CFLAGS -wd269" CFLAGS="$CFLAGS -wd810" # parameter was never referenced CFLAGS="$CFLAGS -wd869" -# "cc" clobber ignored, warnings for Liunx's htons() -CFLAGS="$CFLAGS -wd1469" # STUB # enumerated type mixed with another type @@ -86,8 +90,20 @@ CFLAGS="$CFLAGS -wd981" CFLAGS="$CFLAGS -wd1418" # external declaration in primary source file CFLAGS="$CFLAGS -wd1419" -# non-POD class type passed through ellipsis -CFLAGS="$CFLAGS -wd1595" + +case "$NGX_ICC_VER" in + 8.*) + # "cc" clobber ignored, warnings for Liunx's htons() + CFLAGS="$CFLAGS -wd1469" + + # STUB + # non-POD class type passed through ellipsis + CFLAGS="$CFLAGS -wd1595" + ;; + + *) + ;; +esac # stop on warning CFLAGS="$CFLAGS -Werror" diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -51,6 +51,12 @@ if [ $NGX_TEST_BUILD_SOLARIS_SENDFILEV = fi +if [ $HTTP != YES ]; then + have=NGX_CRYPT . auto/nohave + CRYPT_LIB= +fi + + if [ $HTTP_SSI = YES ]; then HTTP_POSTPONE=YES fi @@ -219,10 +225,14 @@ if [ $HTTP = YES ]; then fi -IMAP_MODULES=$IMAP_MODULE - if [ $IMAP = YES ]; then modules="$modules $IMAP_MODULES" + + modules="$modules $IMAP_AUTH_HTTP_MODULE" + IMAP_SRCS="$IMAP_SRCS $IMAP_AUTH_HTTP_SRCS" + + modules="$modules $IMAP_PROXY_MODULE" + IMAP_SRCS="$IMAP_SRCS $IMAP_PROXY_SRCS" fi diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -339,8 +339,15 @@ IMAP_INCS="src/imap" IMAP_DEPS="src/imap/ngx_imap.h" -IMAP_MODULE=ngx_imap_module +IMAP_MODULES="ngx_imap_module ngx_imap_core_module" + IMAP_SRCS="src/imap/ngx_imap.c \ + src/imap/ngx_imap_core_module.c \ src/imap/ngx_imap_handler.c \ - src/imap/ngx_imap_parse.c \ - src/imap/ngx_imap_proxy.c" + src/imap/ngx_imap_parse.c" + +IMAP_AUTH_HTTP_MODULE="ngx_imap_auth_http_module" +IMAP_AUTH_HTTP_SRCS="src/imap/ngx_imap_auth_http_module.c" + +IMAP_PROXY_MODULE="ngx_imap_proxy_module" +IMAP_PROXY_SRCS="src/imap/ngx_imap_proxy_module.c" diff --git a/docs/xml/nginx/changes.xml b/docs/xml/nginx/changes.xml --- a/docs/xml/nginx/changes.xml +++ b/docs/xml/nginx/changes.xml @@ -9,6 +9,78 @@ nginx changelog + + + + +директива working_directory. + + +the "working_directory" directive. + + + + + +директива port_in_redirect. + + +the "port_in_redirect" directive. + + + + + +если заголовок ответа бэкенда не помещался в один пакет, то +происходил segmentation fault; +ошибка появилась в 0.1.29. + + +the segmentation fault was occurred if the backend response header was in +several packets; +bug appeared in 0.1.29. + + + + + +если было сконфигурировано более 10 серверов или в сервере не описана +директива "listen", +то при запуске мог произойти segmentation fault. + + +if more than 10 servers were configured or some server did not use the +"listen" directive, then the segmentation fault was occurred on the start. + + + + + +если ответ не помещался во временный файл, +то мог произойти segmentation fault. + + +the segmentation fault might occur if the response was bigger than +the temporary file. + + + + + +nginx возвращал ошибку 400 на запросы вида +"GET http://www.domain.com/uri HTTP/1.0"; +ошибка появилась в 0.1.28. + + +nginx returned the 400 response on requests like +"GET http://www.domain.com/uri HTTP/1.0"; +bug appeared in 0.1.28. + + + + + + diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -95,6 +95,13 @@ static ngx_command_t ngx_core_commands[ offsetof(ngx_core_conf_t, pid), NULL }, + { ngx_string("working_directory"), + NGX_MAIN_CONF|NGX_DIRECT_CONF|NGX_CONF_TAKE1, + ngx_conf_set_str_slot, + 0, + offsetof(ngx_core_conf_t, working_directory), + NULL }, + ngx_null_command }; 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.34" +#define NGINX_VER "nginx/0.1.35" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -12,9 +12,8 @@ ngx_os_io_t ngx_io; -ngx_listening_t *ngx_listening_inet_stream_socket(ngx_conf_t *cf, - in_addr_t addr, - in_port_t port) +ngx_listening_t * +ngx_listening_inet_stream_socket(ngx_conf_t *cf, in_addr_t addr, in_port_t port) { size_t len; ngx_listening_t *ls; @@ -60,7 +59,8 @@ ngx_listening_t *ngx_listening_inet_stre } -ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) +ngx_int_t +ngx_set_inherited_sockets(ngx_cycle_t *cycle) { size_t len; ngx_uint_t i; @@ -121,7 +121,8 @@ ngx_int_t ngx_set_inherited_sockets(ngx_ } -ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle) +ngx_int_t +ngx_open_listening_sockets(ngx_cycle_t *cycle) { ngx_uint_t tries, failed, reuseaddr, i; ngx_err_t err; @@ -261,7 +262,8 @@ ngx_int_t ngx_open_listening_sockets(ngx } -void ngx_close_listening_sockets(ngx_cycle_t *cycle) +void +ngx_close_listening_sockets(ngx_cycle_t *cycle) { ngx_uint_t i; ngx_socket_t fd; @@ -309,7 +311,8 @@ void ngx_close_listening_sockets(ngx_cyc } -void ngx_close_connection(ngx_connection_t *c) +void +ngx_close_connection(ngx_connection_t *c) { ngx_socket_t fd; @@ -398,7 +401,8 @@ void ngx_close_connection(ngx_connection } -ngx_int_t ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) +ngx_int_t +ngx_connection_error(ngx_connection_t *c, ngx_err_t err, char *text) { ngx_uint_t level; 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 @@ -144,8 +144,7 @@ struct ngx_connection_s { ngx_listening_t *ngx_listening_inet_stream_socket(ngx_conf_t *cf, - in_addr_t addr, - in_port_t port); + in_addr_t addr, in_port_t port); ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle); ngx_int_t ngx_open_listening_sockets(ngx_cycle_t *cycle); void ngx_close_listening_sockets(ngx_cycle_t *cycle); diff --git a/src/core/ngx_cycle.h b/src/core/ngx_cycle.h --- a/src/core/ngx_cycle.h +++ b/src/core/ngx_cycle.h @@ -57,6 +57,8 @@ typedef struct { ngx_uid_t user; ngx_gid_t group; + ngx_str_t working_directory; + ngx_str_t pid; ngx_str_t newpid; diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -792,8 +792,30 @@ ngx_escape_uri(u_char *dst, u_char *src, 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; + /* " ", """, "%", "'", %00-%1F, %7F-%FF */ + + static uint32_t utf[] = + { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x800000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ + + /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + + /* ~}| {zyx wvut srqp onml kjih gfed cba` */ + 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ + + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ + 0x00000000 /* 0000 0000 0000 0000 0000 0000 0000 0000 */ }; + switch (type) { + case NGX_ESCAPE_UTF: + escape = utf; + break; case NGX_ESCAPE_HTML: escape = html; break; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -100,6 +100,7 @@ ngx_int_t ngx_decode_base64(ngx_str_t *d #define NGX_ESCAPE_URI 0 #define NGX_ESCAPE_ARGS 1 #define NGX_ESCAPE_HTML 2 +#define NGX_ESCAPE_UTF 3 uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type); diff --git a/src/event/ngx_event_pipe.c b/src/event/ngx_event_pipe.c --- a/src/event/ngx_event_pipe.c +++ b/src/event/ngx_event_pipe.c @@ -210,6 +210,10 @@ static ngx_int_t ngx_event_pipe_read_ups ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "pipe temp offset: %O", p->temp_file->offset); + if (rc == NGX_BUSY) { + break; + } + if (rc == NGX_AGAIN) { if (ngx_event_flags & NGX_USE_LEVEL_EVENT && p->upstream->read->active @@ -617,6 +621,10 @@ static ngx_int_t ngx_event_pipe_write_ch ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, "size: %z", size); + if (ll == NULL) { + return NGX_BUSY; + } + if (cl) { p->in = cl; *ll = NULL; 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 @@ -1013,6 +1013,10 @@ ngx_http_proxy_process_header(ngx_http_r return NGX_OK; } + if (rc == NGX_AGAIN) { + return NGX_AGAIN; + } + /* there was error while a header line parsing */ ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, diff --git a/src/http/ngx_http.c b/src/http/ngx_http.c --- a/src/http/ngx_http.c +++ b/src/http/ngx_http.c @@ -360,7 +360,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * to quickly find the server core module configuration at run-time */ - if (ngx_array_init(&in_ports, cf->pool, 10, sizeof(ngx_http_in_port_t)) + if (ngx_array_init(&in_ports, cf->pool, 2, sizeof(ngx_http_in_port_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -434,6 +434,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (inaddr == NULL) { return NGX_CONF_ERROR; } + in_addr = in_port[p].addrs.elts; /* * the INADDR_ANY must be the last resort @@ -578,7 +579,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } for (n = 0; n < cmcf->server_names_hash; n++) { - if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 5, + if (ngx_array_init(&in_addr[a].hash[n], cf->pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_CONF_ERROR; @@ -595,6 +596,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma if (s_name == NULL) { return NGX_CONF_ERROR; } + name = in_addr[a].names.elts; *s_name = name[s]; } @@ -748,7 +750,7 @@ ngx_http_add_address(ngx_conf_t *cf, ngx ngx_http_in_addr_t *in_addr; if (in_port->addrs.elts == NULL) { - if (ngx_array_init(&in_port->addrs, cf->pool, 10, + if (ngx_array_init(&in_port->addrs, cf->pool, 4, sizeof(ngx_http_in_addr_t)) != NGX_OK) { return NGX_ERROR; @@ -794,7 +796,7 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h ngx_http_server_name_t *server_names, *name; if (in_addr->names.elts == NULL) { - if (ngx_array_init(&in_addr->names, cf->pool, 10, + if (ngx_array_init(&in_addr->names, cf->pool, 4, sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_ERROR; @@ -802,7 +804,7 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h } if (in_addr->wildcards.elts == NULL) { - if (ngx_array_init(&in_addr->wildcards, cf->pool, 10, + if (ngx_array_init(&in_addr->wildcards, cf->pool, 1, sizeof(ngx_http_server_name_t)) != NGX_OK) { return NGX_ERROR; @@ -834,6 +836,7 @@ ngx_http_add_names(ngx_conf_t *cf, ngx_h if (name == NULL) { return NGX_ERROR; } + server_names = cscf->server_names.elts; *name = server_names[i]; } diff --git a/src/http/ngx_http_config.h b/src/http/ngx_http_config.h --- a/src/http/ngx_http_config.h +++ b/src/http/ngx_http_config.h @@ -8,7 +8,8 @@ #define _NGX_HTTP_CONFIG_H_INCLUDED_ -#include +#include +#include #include 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 @@ -319,6 +319,13 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_loc_conf_t, reset_timedout_connection), NULL }, + { ngx_string("port_in_redirect"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_core_loc_conf_t, port_in_redirect), + NULL }, + { ngx_string("msie_padding"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, ngx_conf_set_flag_slot, @@ -1113,10 +1120,10 @@ ngx_http_delay_handler(ngx_http_request_ static char * ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy) { - int m; char *rv; void *mconf; - ngx_conf_t save; + ngx_uint_t m; + ngx_conf_t pcf; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx, *http_ctx; ngx_http_core_srv_conf_t *cscf, **cscfp; @@ -1189,13 +1196,13 @@ ngx_http_core_server(ngx_conf_t *cf, ngx /* parse inside server{} */ - save = *cf; + pcf = *cf; cf->ctx = ctx; cf->cmd_type = NGX_HTTP_SRV_CONF; rv = ngx_conf_parse(cf, NULL); - *cf = save; + *cf = pcf; if (rv != NGX_CONF_OK) { return rv; @@ -1622,6 +1629,7 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ls->port = (getuid() == 0) ? 80 : 8000; #endif ls->family = AF_INET; + ls->default_server = 0; } if (conf->server_names.nelts == 0) { @@ -1726,6 +1734,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->lingering_time = NGX_CONF_UNSET_MSEC; lcf->lingering_timeout = NGX_CONF_UNSET_MSEC; lcf->reset_timedout_connection = NGX_CONF_UNSET; + lcf->port_in_redirect = NGX_CONF_UNSET; lcf->msie_padding = NGX_CONF_UNSET; return lcf; @@ -1839,6 +1848,7 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_value(conf->reset_timedout_connection, prev->reset_timedout_connection, 0); + ngx_conf_merge_value(conf->port_in_redirect, prev->port_in_redirect, 1); ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1); if (conf->open_files == NULL) { @@ -1857,8 +1867,8 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx u_char *addr; ngx_int_t port; ngx_uint_t p; + ngx_str_t *args; struct hostent *h; - ngx_str_t *args; ngx_http_listen_t *ls; /* @@ -1874,9 +1884,9 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx /* AF_INET only */ ls->family = AF_INET; - ls->default_server = 0; ls->file_name = cf->conf_file->file.name; ls->line = cf->conf_file->line; + ls->default_server = 0; args = cf->args->elts; addr = args[1].data; 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 @@ -20,7 +20,7 @@ typedef struct { ngx_str_t file_name; ngx_int_t line; - unsigned default_server:1; + ngx_uint_t default_server; /* unsigned default_server:1; */ } ngx_http_listen_t; @@ -206,6 +206,7 @@ struct ngx_http_core_loc_conf_s { ngx_flag_t tcp_nopush; /* tcp_nopush */ ngx_flag_t tcp_nodelay; /* tcp_nodelay */ ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */ + ngx_flag_t port_in_redirect; /* port_in_redirect */ ngx_flag_t msie_padding; /* msie_padding */ ngx_array_t *error_pages; /* error_page */ diff --git a/src/http/ngx_http_header_filter_module.c b/src/http/ngx_http_header_filter_module.c --- a/src/http/ngx_http_header_filter_module.c +++ b/src/http/ngx_http_header_filter_module.c @@ -258,6 +258,8 @@ ngx_http_header_filter(ngx_http_request_ len += sizeof("Last-Modified: Mon, 28 Sep 1970 06:00:00 GMT" CRLF) - 1; } + clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (r->headers_out.location && r->headers_out.location->value.len && r->headers_out.location->value.data[0] == '/') @@ -270,7 +272,7 @@ ngx_http_header_filter(ngx_http_request_ + r->server_name.len + r->headers_out.location->value.len + 2; - if (r->port != 443) { + if (clcf->port_in_redirect && r->port != 443) { len += r->port_text->len; } @@ -281,7 +283,7 @@ ngx_http_header_filter(ngx_http_request_ + r->server_name.len + r->headers_out.location->value.len + 2; - if (r->port != 80) { + if (clcf->port_in_redirect && r->port != 80) { len += r->port_text->len; } } @@ -291,8 +293,6 @@ ngx_http_header_filter(ngx_http_request_ len += sizeof("Transfer-Encoding: chunked" CRLF) - 1; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); - if (r->keepalive) { len += sizeof("Connection: keep-alive" CRLF) - 1; @@ -425,18 +425,20 @@ ngx_http_header_filter(ngx_http_request_ b->last = ngx_cpymem(b->last, r->server_name.data, r->server_name.len); + if (clcf->port_in_redirect) { #if (NGX_HTTP_SSL) - if (r->connection->ssl) { - if (r->port != 443) { - b->last = ngx_cpymem(b->last, r->port_text->data, - r->port_text->len); - } - } else + if (r->connection->ssl) { + if (r->port != 443) { + b->last = ngx_cpymem(b->last, r->port_text->data, + r->port_text->len); + } + } else #endif - { - if (r->port != 80) { - b->last = ngx_cpymem(b->last, r->port_text->data, - r->port_text->len); + { + if (r->port != 80) { + b->last = ngx_cpymem(b->last, r->port_text->data, + r->port_text->len); + } } } diff --git a/src/http/ngx_http_parse.c b/src/http/ngx_http_parse.c --- a/src/http/ngx_http_parse.c +++ b/src/http/ngx_http_parse.c @@ -112,7 +112,7 @@ ngx_http_parse_request_line(ngx_http_req case sw_spaces_before_uri: c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { + if (c >= 'a' && c <= 'z') { r->schema_start = p; state = sw_schema; break; @@ -133,7 +133,7 @@ ngx_http_parse_request_line(ngx_http_req case sw_schema: c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { + if (c >= 'a' && c <= 'z') { break; } @@ -171,7 +171,7 @@ ngx_http_parse_request_line(ngx_http_req case sw_host: c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { + if (c >= 'a' && c <= 'z') { break; } @@ -215,7 +215,7 @@ ngx_http_parse_request_line(ngx_http_req case sw_after_slash_in_uri: c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { + if (c >= 'a' && c <= 'z') { state = sw_check_uri; break; } @@ -277,7 +277,7 @@ ngx_http_parse_request_line(ngx_http_req case sw_check_uri: c = (u_char) (ch | 0x20); - if (c >= 'a' && c <= 'f') { + if (c >= 'a' && c <= 'z') { break; } 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 @@ -1722,6 +1722,10 @@ ngx_http_discard_body(ngx_http_request_t ssize_t size; ngx_event_t *rev; + if (r->main) { + return NGX_OK; + } + rev = r->connection->read; ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body"); diff --git a/src/imap/ngx_imap.c b/src/imap/ngx_imap.c --- a/src/imap/ngx_imap.c +++ b/src/imap/ngx_imap.c @@ -13,6 +13,9 @@ static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +ngx_uint_t ngx_imap_max_module; + + static ngx_command_t ngx_imap_commands[] = { { ngx_string("imap"), @@ -43,25 +46,144 @@ ngx_module_t ngx_imap_module = { }; -static char *ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +static char * +ngx_imap_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { - ngx_listening_t *ls; + char *rv; + ngx_uint_t m, mi, s; + ngx_conf_t pcf; + ngx_imap_module_t *module; + ngx_imap_conf_ctx_t *ctx; + ngx_imap_core_srv_conf_t **cscfp; + ngx_imap_core_main_conf_t *cmcf; + + /* the main imap context */ + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_imap_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + *(ngx_imap_conf_ctx_t **) conf = ctx; + + /* count the number of the http modules and set up their indices */ - /* STUB */ + ngx_imap_max_module = 0; + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + ngx_modules[m]->ctx_index = ngx_imap_max_module++; + } + + + /* the imap main_conf context, it is the same in the all imap contexts */ - ls = ngx_listening_inet_stream_socket(cf, 0, 8110); - if (ls == NULL) { + ctx->main_conf = ngx_pcalloc(cf->pool, + sizeof(void *) * ngx_imap_max_module); + if (ctx->main_conf == NULL) { + return NGX_CONF_ERROR; + } + + + /* + * the imap null srv_conf context, it is used to merge + * the server{}s' srv_conf's + */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_imap_max_module); + if (ctx->srv_conf == NULL) { return NGX_CONF_ERROR; } - ls->backlog = -1; - ls->addr_ntop = 1; - ls->handler = ngx_imap_init_connection; - ls->pool_size = 16384; - /* ls->post_accept_timeout = 0; */ - ls->log = cf->cycle->new_log; + + /* + * create the main_conf's, the null srv_conf's, and the null loc_conf's + * of the all imap modules + */ + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + if (module->create_main_conf) { + ctx->main_conf[mi] = module->create_main_conf(cf); + if (ctx->main_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + + if (module->create_srv_conf) { + ctx->srv_conf[mi] = module->create_srv_conf(cf); + if (ctx->srv_conf[mi] == NULL) { + return NGX_CONF_ERROR; + } + } + } + + + /* parse inside the imap{} block */ + + pcf = *cf; + cf->ctx = ctx; + + cf->module_type = NGX_IMAP_MODULE; + cf->cmd_type = NGX_IMAP_MAIN_CONF; + rv = ngx_conf_parse(cf, NULL); + + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } - /* */ + + /* init imap{} main_conf's, merge the server{}s' srv_conf's */ + + cmcf = ctx->main_conf[ngx_imap_core_module.ctx_index]; + cscfp = cmcf->servers.elts; + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + mi = ngx_modules[m]->ctx_index; + + /* init imap{} main_conf's */ + + if (module->init_main_conf) { + rv = module->init_main_conf(cf, ctx->main_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + + for (s = 0; s < cmcf->servers.nelts; s++) { + + /* merge the server{}s' srv_conf's */ + + if (module->merge_srv_conf) { + rv = module->merge_srv_conf(cf, + ctx->srv_conf[mi], + cscfp[s]->ctx->srv_conf[mi]); + if (rv != NGX_CONF_OK) { + *cf = pcf; + return rv; + } + } + } + } + + /* imap{}'s cf->ctx was needed while the configuration merging */ + + *cf = pcf; return NGX_CONF_OK; } 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 @@ -15,10 +15,39 @@ typedef struct { - ngx_peer_connection_t upstream; + void **main_conf; + void **srv_conf; +} ngx_imap_conf_ctx_t; + + +typedef struct { + ngx_array_t servers; /* ngx_imap_core_srv_conf_t */ +} ngx_imap_core_main_conf_t; + + +#define NGX_IMAP_POP3_PROTOCOL 0 +#define NGX_IMAP_IMAP_PROTOCOL 1 + +typedef struct { + ngx_msec_t timeout; - ngx_buf_t *buffer; -} ngx_imap_proxy_ctx_t; + size_t imap_client_buffer_size; + size_t proxy_buffer_size; + + ngx_uint_t protocol; + + /* server ctx */ + ngx_imap_conf_ctx_t *ctx; +} ngx_imap_core_srv_conf_t; + + +typedef struct { + void *(*create_main_conf)(ngx_conf_t *cf); + char *(*init_main_conf)(ngx_conf_t *cf, void *conf); + + void *(*create_srv_conf)(ngx_conf_t *cf); + char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf); +} ngx_imap_module_t; typedef enum { @@ -28,14 +57,27 @@ typedef enum { typedef struct { + ngx_peer_connection_t upstream; + ngx_buf_t *buffer; +} ngx_imap_proxy_ctx_t; + + +typedef struct { uint32_t signature; /* "IMAP" */ ngx_connection_t *connection; + ngx_buf_t *buffer; + void **ctx; + void **main_conf; + void **srv_conf; + + ngx_imap_proxy_ctx_t *proxy; + ngx_imap_state_e imap_state; - ngx_imap_proxy_ctx_t *proxy; + unsigned protocol:1; ngx_str_t login; ngx_str_t passwd; @@ -74,17 +116,38 @@ typedef struct { #define NGX_IMAP_MODULE 0x50414D49 /* "IMAP" */ -#define NGX_IMAP_SRV_CONF 0x02000000 -#define NGX_IMAP_IMAP_CONF 0x04000000 -#define NGX_IMAP_POP3_CONF 0x08000000 +#define NGX_IMAP_MAIN_CONF 0x02000000 +#define NGX_IMAP_SRV_CONF 0x04000000 + + +#define NGX_IMAP_MAIN_CONF_OFFSET offsetof(ngx_imap_conf_ctx_t, main_conf) +#define NGX_IMAP_SRV_CONF_OFFSET offsetof(ngx_imap_conf_ctx_t, srv_conf) + + +#define ngx_imap_get_module_ctx(s, module) (s)->ctx[module.ctx_index] +#define ngx_imap_set_ctx(s, c, module) s->ctx[module.ctx_index] = c; +#define ngx_imap_delete_ctx(s, module) s->ctx[module.ctx_index] = NULL; + + +#define ngx_imap_get_module_main_conf(s, module) \ + (s)->main_conf[module.ctx_index] +#define ngx_imap_get_module_srv_conf(s, module) (s)->srv_conf[module.ctx_index] void ngx_imap_init_connection(ngx_connection_t *c); void ngx_imap_close_connection(ngx_connection_t *c); -void ngx_imap_proxy_init(ngx_imap_session_t *s); - ngx_int_t ngx_pop3_parse_command(ngx_imap_session_t *s); +/* STUB */ +void ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers); +void ngx_imap_auth_http_init(ngx_imap_session_t *s); +/**/ + + +extern ngx_uint_t ngx_imap_max_module; +extern ngx_module_t ngx_imap_core_module; + + #endif /* _NGX_IMAP_H_INCLUDED_ */ diff --git a/src/imap/ngx_imap_auth_http_module.c b/src/imap/ngx_imap_auth_http_module.c new file mode 100644 --- /dev/null +++ b/src/imap/ngx_imap_auth_http_module.c @@ -0,0 +1,421 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include +#include + + +typedef struct { + ngx_peers_t *peers; + + ngx_msec_t timeout; + + ngx_str_t host_header; + ngx_str_t uri; +} ngx_imap_auth_http_conf_t; + + +typedef struct { + ngx_buf_t *request; + ngx_peer_connection_t peer; +} ngx_imap_auth_http_ctx_t; + + +static void ngx_imap_auth_http_write_handler(ngx_event_t *wev); +static void ngx_imap_auth_http_read_handler(ngx_event_t *rev); +static void ngx_imap_auth_http_block_read(ngx_event_t *rev); +static void ngx_imap_auth_http_dummy_handler(ngx_event_t *ev); +static ngx_buf_t *ngx_imap_auth_http_create_request(ngx_imap_session_t *s, + ngx_imap_auth_http_conf_t *ahcf); + +static void *ngx_imap_auth_http_create_conf(ngx_conf_t *cf); +static char *ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); + + +static ngx_command_t ngx_imap_auth_http_commands[] = { + + { ngx_string("auth_http"), + NGX_IMAP_MAIN_CONF|NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_imap_auth_http, + NGX_IMAP_SRV_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("auth_http_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_auth_http_conf_t, timeout), + NULL }, + + ngx_null_command +}; + + +static ngx_imap_module_t ngx_imap_auth_http_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_auth_http_create_conf, /* create server configuration */ + ngx_imap_auth_http_merge_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_imap_auth_http_module = { + NGX_MODULE_V1, + &ngx_imap_auth_http_module_ctx, /* module context */ + ngx_imap_auth_http_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static char *ngx_imap_auth_http_protocol[] = { "pop3", "imap" }; + + +void +ngx_imap_auth_http_init(ngx_imap_session_t *s) +{ + ngx_int_t rc; + ngx_imap_auth_http_ctx_t *ctx; + ngx_imap_auth_http_conf_t *ahcf; + + ctx = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_auth_http_ctx_t)); + if (ctx == NULL) { + ngx_imap_close_connection(s->connection); + return; + } + + ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module); + + ctx->request = ngx_imap_auth_http_create_request(s, ahcf); + if (ctx->request == NULL) { + ngx_imap_close_connection(s->connection); + return; + } + + ngx_imap_set_ctx(s, ctx, ngx_imap_auth_http_module); + + ctx->peer.peers = ahcf->peers; + ctx->peer.log = s->connection->log; + ctx->peer.log_error = NGX_ERROR_ERR; + + rc = ngx_event_connect_peer(&ctx->peer); + + if (rc == NGX_ERROR) { + ngx_imap_close_connection(s->connection); + return; + } + + ctx->peer.connection->data = s; + ctx->peer.connection->pool = s->connection->pool; + + s->connection->read->handler = ngx_imap_auth_http_block_read; + ctx->peer.connection->read->handler = ngx_imap_auth_http_read_handler; + ctx->peer.connection->write->handler = ngx_imap_auth_http_write_handler; + + if (rc == NGX_OK) { + ngx_imap_auth_http_write_handler(ctx->peer.connection->write); + return; + } + + ngx_add_timer(ctx->peer.connection->read, ahcf->timeout); + ngx_add_timer(ctx->peer.connection->write, ahcf->timeout); +} + + +static void +ngx_imap_auth_http_write_handler(ngx_event_t *wev) +{ + ssize_t n, size; + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_auth_http_ctx_t *ctx; + ngx_imap_auth_http_conf_t *ahcf; + + c = wev->data; + s = c->data; + + ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module); + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, wev->log, 0, + "imap auth http write handler"); + + if (wev->timedout) { + ngx_log_error(NGX_LOG_ERR, wev->log, NGX_ETIMEDOUT, + "auth http server timed out"); + ngx_imap_close_connection(ctx->peer.connection); + ngx_imap_close_connection(s->connection); + return; + } + + size = ctx->request->last - ctx->request->pos; + + n = ngx_send(c, ctx->request->pos, size); + + if (n == NGX_ERROR) { + ngx_imap_close_connection(ctx->peer.connection); + ngx_imap_close_connection(s->connection); + return; + } + + if (n > 0) { + ctx->request->pos += n; + + if (n == size) { + wev->handler = ngx_imap_auth_http_dummy_handler; + + if (wev->timer_set) { + ngx_del_timer(wev); + } + + return; + } + } + + if (!wev->timer_set) { + ahcf = ngx_imap_get_module_srv_conf(s, ngx_imap_auth_http_module); + ngx_add_timer(wev, ahcf->timeout); + } +} + + +static void +ngx_imap_auth_http_read_handler(ngx_event_t *rev) +{ + ngx_peers_t *peers; + ngx_connection_t *c; + ngx_imap_session_t *s; +#if 0 + ngx_imap_auth_http_ctx_t *ctx; +#endif + + c = rev->data; + s = c->data; + +#if 0 + ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module); +#endif + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, + "imap auth http read handler"); + + peers = NULL; + + ngx_imap_proxy_init(s, peers); +} + + +static void +ngx_imap_auth_http_block_read(ngx_event_t *rev) +{ + ngx_connection_t *c; + ngx_imap_session_t *s; + ngx_imap_auth_http_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, rev->log, 0, + "imap auth http block read"); + + if (ngx_handle_read_event(rev, 0) == NGX_ERROR) { + c = rev->data; + s = c->data; + + ctx = ngx_imap_get_module_ctx(s, ngx_imap_auth_http_module); + + ngx_imap_close_connection(ctx->peer.connection); + ngx_imap_close_connection(s->connection); + } +} + + +static void +ngx_imap_auth_http_dummy_handler(ngx_event_t *ev) +{ + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, + "imap auth http dummy handler"); +} + + +static ngx_buf_t * +ngx_imap_auth_http_create_request(ngx_imap_session_t *s, + ngx_imap_auth_http_conf_t *ahcf) +{ + size_t len; + ngx_buf_t *b; + + len = sizeof("GET ") - 1 + ahcf->uri.len + sizeof(" HTTP/1.0" CRLF) - 1 + + sizeof("Host: ") - 1 + ahcf->host_header.len + sizeof(CRLF) - 1 + + sizeof("Auth-Method: plain" CRLF) - 1 + + sizeof("Auth-User: ") - 1 + s->login.len + sizeof(CRLF) - 1 + + sizeof("Auth-Pass: ") - 1 + s->passwd.len + sizeof(CRLF) - 1 + + sizeof("Auth-Protocol: imap" CRLF) - 1 + + sizeof("Client-IP: ") - 1 + s->connection->addr_text.len + + sizeof(CRLF) - 1 + + sizeof(CRLF) - 1; + + b = ngx_create_temp_buf(s->connection->pool, len); + if (b == NULL) { + return NULL; + } + + b->last = ngx_cpymem(b->last, "GET ", sizeof("GET ") - 1); + b->last = ngx_cpymem(b->last, ahcf->uri.data, ahcf->uri.len); + b->last = ngx_cpymem(b->last, " HTTP/1.0" CRLF, + sizeof(" HTTP/1.0" CRLF) - 1); + + b->last = ngx_cpymem(b->last, "Host: ", sizeof("Host: ") - 1); + b->last = ngx_cpymem(b->last, ahcf->host_header.data, + ahcf->host_header.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Auth-Method: plain" CRLF, + sizeof("Auth-Method: plain" CRLF) - 1); + + b->last = ngx_cpymem(b->last, "Auth-User: ", sizeof("Auth-User: ") - 1); + b->last = ngx_cpymem(b->last, s->login.data, s->login.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Auth-Pass: ", sizeof("Auth-Pass: ") - 1); + b->last = ngx_cpymem(b->last, s->passwd.data, s->passwd.len); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Auth-Protocol: ", + sizeof("Auth-Protocol: ") - 1); + b->last = ngx_cpymem(b->last, ngx_imap_auth_http_protocol[s->protocol], + sizeof("imap") - 1); + *b->last++ = CR; *b->last++ = LF; + + b->last = ngx_cpymem(b->last, "Client-IP: ", sizeof("Client-IP: ") - 1); + b->last = ngx_cpymem(b->last, s->connection->addr_text.data, + s->connection->addr_text.len); + *b->last++ = CR; *b->last++ = LF; + + /* add "\r\n" at the header end */ + *b->last++ = CR; *b->last++ = LF; + +#if (NGX_DEBUG) + { + ngx_str_t l; + + l.len = b->last - b->pos; + l.data = b->pos; + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, s->connection->log, 0, + "imap auth http header:\n\"%V\"", &l); + } +#endif + + return b; +} + + +static void * +ngx_imap_auth_http_create_conf(ngx_conf_t *cf) +{ + ngx_imap_auth_http_conf_t *ahcf; + + ahcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_auth_http_conf_t)); + if (ahcf == NULL) { + return NGX_CONF_ERROR; + } + + ahcf->timeout = NGX_CONF_UNSET_MSEC; + + return ahcf; +} + + +static char * +ngx_imap_auth_http_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_imap_auth_http_conf_t *prev = parent; + ngx_imap_auth_http_conf_t *conf = child; + + if (conf->peers == NULL) { + conf->peers = prev->peers; + conf->host_header = prev->host_header; + conf->uri = prev->uri; + } + + ngx_conf_merge_msec_value(conf->timeout, prev->timeout, 60000); + + return NGX_CONF_OK; +} + + +static char * +ngx_imap_auth_http(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_imap_auth_http_conf_t *ahcf = conf; + + ngx_uint_t i; + ngx_str_t *value, *url; + ngx_inet_upstream_t inet_upstream; +#if (NGX_HAVE_UNIX_DOMAIN) + ngx_unix_domain_upstream_t unix_upstream; +#endif + + value = cf->args->elts; + + url = &value[1]; + + if (ngx_strncasecmp(url->data, "unix:", 5) == 0) { + +#if (NGX_HAVE_UNIX_DOMAIN) + + ngx_memzero(&unix_upstream, sizeof(ngx_unix_domain_upstream_t)); + + unix_upstream.name = *url; + unix_upstream.url = *url; + unix_upstream.uri_part = 1; + + ahcf->peers = ngx_unix_upstream_parse(cf, &unix_upstream); + if (ahcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + ahcf->peers->peer[0].uri_separator = ":"; + + ahcf->host_header.len = sizeof("localhost") - 1; + ahcf->host_header.data = (u_char *) "localhost"; + ahcf->uri = unix_upstream.uri; + +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the unix domain sockets are not supported " + "on this platform"); + return NGX_CONF_ERROR; + +#endif + + } else { + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.name = *url; + inet_upstream.url = *url; + inet_upstream.default_port_value = 80; + inet_upstream.uri_part = 1; + + ahcf->peers = ngx_inet_upstream_parse(cf, &inet_upstream); + if (ahcf->peers == NULL) { + return NGX_CONF_ERROR; + } + + for (i = 0; i < ahcf->peers->number; i++) { + ahcf->peers->peer[i].uri_separator = ":"; + } + + ahcf->host_header = inet_upstream.host_header; + ahcf->uri = inet_upstream.uri; + } + + return NGX_CONF_OK; +} diff --git a/src/imap/ngx_imap_core_module.c b/src/imap/ngx_imap_core_module.c new file mode 100644 --- /dev/null +++ b/src/imap/ngx_imap_core_module.c @@ -0,0 +1,297 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include +#include + + +static void *ngx_imap_core_create_main_conf(ngx_conf_t *cf); +static void *ngx_imap_core_create_srv_conf(ngx_conf_t *cf); +static char *ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent, + void *child); +static char *ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); + + +static ngx_conf_enum_t ngx_imap_core_procotol[] = { + { ngx_string("pop3"), NGX_IMAP_POP3_PROTOCOL }, + { ngx_string("imap"), NGX_IMAP_IMAP_PROTOCOL }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_imap_core_commands[] = { + + { ngx_string("server"), + NGX_IMAP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, + ngx_imap_core_server, + 0, + 0, + NULL }, + + { ngx_string("listen"), + NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_imap_core_listen, + 0, + 0, + NULL }, + + { ngx_string("protocol"), + NGX_IMAP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_enum_slot, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_core_srv_conf_t, protocol), + &ngx_imap_core_procotol }, + + { ngx_string("imap_client_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, 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, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_core_srv_conf_t, timeout), + NULL }, + + ngx_null_command +}; + + +static ngx_imap_module_t ngx_imap_core_module_ctx = { + ngx_imap_core_create_main_conf, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_core_create_srv_conf, /* create server configuration */ + ngx_imap_core_merge_srv_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_imap_core_module = { + NGX_MODULE_V1, + &ngx_imap_core_module_ctx, /* module context */ + ngx_imap_core_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +static void * +ngx_imap_core_create_main_conf(ngx_conf_t *cf) +{ + ngx_imap_core_main_conf_t *cmcf; + + cmcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_main_conf_t)); + if (cmcf == NULL) { + return NGX_CONF_ERROR; + } + + if (ngx_array_init(&cmcf->servers, cf->pool, 4, + sizeof(ngx_imap_core_srv_conf_t *)) == NGX_ERROR) + { + return NGX_CONF_ERROR; + } + + return cmcf; +} + + +static void * +ngx_imap_core_create_srv_conf(ngx_conf_t *cf) +{ + ngx_imap_core_srv_conf_t *cscf; + + cscf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_core_srv_conf_t)); + if (cscf == NULL) { + return NGX_CONF_ERROR; + } + + 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; + + return cscf; +} + + +static char * +ngx_imap_core_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_imap_core_srv_conf_t *prev = parent; + ngx_imap_core_srv_conf_t *conf = child; + + 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); + + return NGX_CONF_OK; +} + + +static char * +ngx_imap_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *rv; + void *mconf; + ngx_uint_t m; + ngx_conf_t pcf; + ngx_imap_module_t *module; + ngx_imap_conf_ctx_t *ctx, *imap_ctx; + ngx_imap_core_srv_conf_t *cscf, **cscfp; + ngx_imap_core_main_conf_t *cmcf; + + + ctx = ngx_pcalloc(cf->pool, sizeof(ngx_imap_conf_ctx_t)); + if (ctx == NULL) { + return NGX_CONF_ERROR; + } + + imap_ctx = cf->ctx; + ctx->main_conf = imap_ctx->main_conf; + + /* the server{}'s srv_conf */ + + ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_imap_max_module); + if (ctx->srv_conf == NULL) { + return NGX_CONF_ERROR; + } + + for (m = 0; ngx_modules[m]; m++) { + if (ngx_modules[m]->type != NGX_IMAP_MODULE) { + continue; + } + + module = ngx_modules[m]->ctx; + + if (module->create_srv_conf) { + mconf = module->create_srv_conf(cf); + if (mconf == NULL) { + return NGX_CONF_ERROR; + } + + ctx->srv_conf[ngx_modules[m]->ctx_index] = mconf; + } + } + + /* the server configuration context */ + + cscf = ctx->srv_conf[ngx_imap_core_module.ctx_index]; + cscf->ctx = ctx; + + cmcf = ctx->main_conf[ngx_imap_core_module.ctx_index]; + + cscfp = ngx_array_push(&cmcf->servers); + if (cscfp == NULL) { + return NGX_CONF_ERROR; + } + + *cscfp = cscf; + + + /* parse inside server{} */ + + pcf = *cf; + cf->ctx = ctx; + cf->cmd_type = NGX_IMAP_SRV_CONF; + + rv = ngx_conf_parse(cf, NULL); + + *cf = pcf; + + return rv; +} + + +/* AF_INET only */ + +static char * +ngx_imap_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + char *err; + ngx_str_t *value; + in_addr_t in_addr; + struct hostent *h; + ngx_listening_t *ls; + ngx_inet_upstream_t inet_upstream; + + value = cf->args->elts; + + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.url = value[1]; + inet_upstream.port_only = 1; + + err = ngx_inet_parse_host_port(&inet_upstream); + + if (err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"listen\" directive", err); + return NGX_CONF_ERROR; + } + + if (inet_upstream.host.len) { + inet_upstream.host.data[inet_upstream.host.len] = '\0'; + + in_addr = inet_addr((const char *) inet_upstream.host.data); + + if (in_addr == INADDR_NONE) { + h = gethostbyname((const char *) inet_upstream.host.data); + + if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "can not resolve host \"%s\" " + "in the \"listen\" directive", + inet_upstream.host.data); + return NGX_CONF_ERROR; + } + + in_addr = *(in_addr_t *)(h->h_addr_list[0]); + } + + } else { + in_addr = INADDR_ANY; + } + + + ls = ngx_listening_inet_stream_socket(cf, in_addr, inet_upstream.port); + if (ls == NULL) { + return NGX_CONF_ERROR; + } + + ls->backlog = -1; + ls->addr_ntop = 1; + ls->handler = ngx_imap_init_connection; + ls->pool_size = 256; + + ls->ctx = cf->ctx; + + /* STUB */ + ls->log = cf->cycle->new_log; + /**/ + + return NGX_CONF_OK; +} 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 @@ -12,33 +12,39 @@ static void ngx_imap_init_session(ngx_event_t *rev); + static void ngx_pop3_auth_state(ngx_event_t *rev); static ngx_int_t ngx_pop3_read_command(ngx_imap_session_t *s); - -static u_char pop3_greeting[] = "+OK " NGINX_VER " ready" CRLF; -#if 0 -static u_char imap_greeting[] = "* OK " NGINX_VER " ready" CRLF; -#endif - -static u_char pop3_ok[] = "+OK" CRLF; -static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; +static void ngx_imap_auth_state(ngx_event_t *rev); -void ngx_imap_init_connection(ngx_connection_t *c) +static ngx_str_t greetings[] = { + ngx_string("+OK " NGINX_VER " ready" CRLF), + ngx_string("* OK " NGINX_VER " ready" CRLF) +}; + +static u_char pop3_ok[] = "+OK" CRLF; +static u_char pop3_invalid_command[] = "-ERR invalid command" CRLF; + + +void +ngx_imap_init_connection(ngx_connection_t *c) { - u_char *greeting; - ssize_t size; + ssize_t size; + ngx_imap_conf_ctx_t *ctx; + ngx_imap_core_srv_conf_t *cscf; - ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, - "imap init connection"); + ngx_log_debug0(NGX_LOG_DEBUG_IMAP, c->log, 0, "imap init connection"); c->log_error = NGX_ERROR_INFO; - greeting = pop3_greeting; - size = sizeof(pop3_greeting) - 1; + ctx = c->ctx; + cscf = ngx_imap_get_module_srv_conf(ctx, ngx_imap_core_module); - if (ngx_send(c, greeting, size) < size) { + size = greetings[cscf->protocol].len; + + if (ngx_send(c, greetings[cscf->protocol].data, size) < size) { /* * we treat the incomplete sending as NGX_ERROR * because it is very strange here @@ -49,7 +55,7 @@ void ngx_imap_init_connection(ngx_connec c->read->handler = ngx_imap_init_session; - ngx_add_timer(c->read, /* STUB */ 60000); + ngx_add_timer(c->read, cscf->timeout); if (ngx_handle_read_event(c->read, 0) == NGX_ERROR) { ngx_imap_close_connection(c); @@ -57,11 +63,14 @@ void ngx_imap_init_connection(ngx_connec } -static void ngx_imap_init_session(ngx_event_t *rev) +static void +ngx_imap_init_session(ngx_event_t *rev) { - size_t size; - ngx_connection_t *c; - ngx_imap_session_t *s; + 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; @@ -80,12 +89,33 @@ static void ngx_imap_init_session(ngx_ev c->data = s; s->connection = c; + s->ctx = ngx_pcalloc(c->pool, sizeof(void *) * ngx_imap_max_module); + if (s->ctx == NULL) { + ngx_imap_close_connection(c); + return; + } + + ctx = c->ctx; + s->main_conf = ctx->main_conf; + s->srv_conf = ctx->srv_conf; + if (ngx_array_init(&s->args, c->pool, 2, sizeof(ngx_str_t)) == NGX_ERROR) { ngx_imap_close_connection(c); return; } - size = /* STUB: pop3: 128, imap: configurable 4K default */ 128; + cscf = ngx_imap_get_module_srv_conf(s, ngx_imap_core_module); + + s->protocol = cscf->protocol; + + if (cscf->protocol == NGX_IMAP_POP3_PROTOCOL) { + size = 128; + c->read->handler = ngx_pop3_auth_state; + + } else { + size = cscf->imap_client_buffer_size; + c->read->handler = ngx_imap_auth_state; + } s->buffer = ngx_create_temp_buf(c->pool, size); if (s->buffer == NULL) { @@ -93,13 +123,23 @@ static void ngx_imap_init_session(ngx_ev return; } - c->read->handler = ngx_pop3_auth_state; - - ngx_pop3_auth_state(rev); + c->read->handler(rev); } -static void ngx_pop3_auth_state(ngx_event_t *rev) +static void +ngx_imap_auth_state(ngx_event_t *rev) +{ + ngx_connection_t *c; + + c = rev->data; + + ngx_imap_close_connection(c); +} + + +static void +ngx_pop3_auth_state(ngx_event_t *rev) { u_char *text; ssize_t size; @@ -196,7 +236,7 @@ static void ngx_pop3_auth_state(ngx_even s->buffer->pos = s->buffer->start; s->buffer->last = s->buffer->start; - ngx_imap_proxy_init(s); + ngx_imap_auth_http_init(s); return; @@ -245,7 +285,8 @@ static void ngx_pop3_auth_state(ngx_even } -static ngx_int_t ngx_pop3_read_command(ngx_imap_session_t *s) +static ngx_int_t +ngx_pop3_read_command(ngx_imap_session_t *s) { ssize_t n; ngx_int_t rc; @@ -288,7 +329,8 @@ static ngx_int_t ngx_pop3_read_command(n #if 0 -void ngx_imap_close_session(ngx_imap_session_t *s) +void +ngx_imap_close_session(ngx_imap_session_t *s) { ngx_log_debug0(NGX_LOG_DEBUG_IMAP, s->connection->log, 0, "close imap session"); @@ -299,7 +341,8 @@ void ngx_imap_close_session(ngx_imap_ses #endif -void ngx_imap_close_connection(ngx_connection_t *c) +void +ngx_imap_close_connection(ngx_connection_t *c) { ngx_pool_t *pool; diff --git a/src/imap/ngx_imap_proxy.c b/src/imap/ngx_imap_proxy_module.c rename from src/imap/ngx_imap_proxy.c rename to src/imap/ngx_imap_proxy_module.c --- a/src/imap/ngx_imap_proxy.c +++ b/src/imap/ngx_imap_proxy_module.c @@ -11,19 +11,57 @@ #include +typedef struct { + ngx_flag_t enable; +} ngx_imap_proxy_conf_t; + + static void ngx_imap_proxy_block_read(ngx_event_t *rev); static void ngx_imap_proxy_auth_handler(ngx_event_t *rev); static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev); static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s); static void ngx_imap_proxy_handler(ngx_event_t *ev); static void ngx_imap_proxy_close_session(ngx_imap_session_t *s); +static void *ngx_imap_proxy_create_conf(ngx_conf_t *cf); +static char *ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent, + void *child); + + +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, + NGX_IMAP_SRV_CONF_OFFSET, + offsetof(ngx_imap_proxy_conf_t, enable), + NULL }, + + ngx_null_command +}; -void ngx_imap_proxy_init(ngx_imap_session_t *s) +static ngx_imap_module_t ngx_imap_proxy_module_ctx = { + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + ngx_imap_proxy_create_conf, /* create server configuration */ + ngx_imap_proxy_merge_conf /* merge server configuration */ +}; + + +ngx_module_t ngx_imap_proxy_module = { + NGX_MODULE_V1, + &ngx_imap_proxy_module_ctx, /* module context */ + ngx_imap_proxy_commands, /* module directives */ + NGX_IMAP_MODULE, /* module type */ + NULL, /* init module */ + NULL /* init process */ +}; + + +void +ngx_imap_proxy_init(ngx_imap_session_t *s, ngx_peers_t *peers) { ngx_int_t rc; - ngx_peers_t *peers; - struct sockaddr_in *sin; ngx_imap_proxy_ctx_t *p; p = ngx_pcalloc(s->connection->pool, sizeof(ngx_imap_proxy_ctx_t)); @@ -34,44 +72,10 @@ void ngx_imap_proxy_init(ngx_imap_sessio s->proxy = p; - /**/ - - peers = ngx_pcalloc(s->connection->pool, sizeof(ngx_peers_t)); - if (peers == NULL) { - ngx_imap_close_connection(s->connection); - return; - } - p->upstream.peers = peers; p->upstream.log = s->connection->log; p->upstream.log_error = NGX_ERROR_ERR; - sin = ngx_pcalloc(s->connection->pool, sizeof(struct sockaddr_in)); - if (sin == NULL) { - ngx_imap_close_connection(s->connection); - return; - } - - peers->peer[0].sockaddr = (struct sockaddr *) sin; - peers->peer[0].socklen = sizeof(struct sockaddr_in); - - sin->sin_port = htons(110); -#if 1 - sin->sin_addr.s_addr = inet_addr("81.19.64.101"); - peers->peer[0].name.len = sizeof("81.19.64.101:110") - 1; - peers->peer[0].name.data = (u_char *) "81.19.64.101:110"; -#else - sin->sin_addr.s_addr = inet_addr("81.19.69.70"); - peers->peer[0].name.len = sizeof("81.19.69.70:110") - 1; - peers->peer[0].name.data = (u_char *) "81.19.69.70:110"; -#endif - - peers->number = 1; - - peers->peer[0].max_fails = 1; - peers->peer[0].fail_timeout = 60; - peers->peer[0].weight = 1; - rc = ngx_event_connect_peer(&p->upstream); if (rc == NGX_ERROR) { @@ -88,7 +92,8 @@ void ngx_imap_proxy_init(ngx_imap_sessio } -static void ngx_imap_proxy_block_read(ngx_event_t *rev) +static void +ngx_imap_proxy_block_read(ngx_event_t *rev) { ngx_connection_t *c; ngx_imap_session_t *s; @@ -104,7 +109,8 @@ static void ngx_imap_proxy_block_read(ng } -static void ngx_imap_proxy_auth_handler(ngx_event_t *rev) +static void +ngx_imap_proxy_auth_handler(ngx_event_t *rev) { u_char *p; ngx_int_t rc; @@ -207,13 +213,15 @@ static void ngx_imap_proxy_auth_handler( } -static void ngx_imap_proxy_dummy_handler(ngx_event_t *ev) +static void +ngx_imap_proxy_dummy_handler(ngx_event_t *ev) { ngx_log_debug0(NGX_LOG_DEBUG_IMAP, ev->log, 0, "imap proxy dummy handler"); } -static ngx_int_t ngx_imap_proxy_read_response(ngx_imap_session_t *s) +static ngx_int_t +ngx_imap_proxy_read_response(ngx_imap_session_t *s) { u_char *p; ssize_t n; @@ -267,7 +275,8 @@ static ngx_int_t ngx_imap_proxy_read_res } -static void ngx_imap_proxy_handler(ngx_event_t *ev) +static void +ngx_imap_proxy_handler(ngx_event_t *ev) { size_t size; ssize_t n; @@ -387,12 +396,44 @@ static void ngx_imap_proxy_handler(ngx_e } -static void ngx_imap_proxy_close_session(ngx_imap_session_t *s) +static void +ngx_imap_proxy_close_session(ngx_imap_session_t *s) { - if (ngx_close_socket(s->proxy->upstream.connection->fd) == -1) { - ngx_log_error(NGX_LOG_ALERT, s->connection->log, ngx_socket_errno, - ngx_close_socket_n " failed"); + if (s->proxy->upstream.connection) { + ngx_log_debug1(NGX_LOG_DEBUG_IMAP, s->connection->log, 0, + "close imap proxy connection: %d", + s->proxy->upstream.connection->fd); + + ngx_close_connection(s->proxy->upstream.connection); } ngx_imap_close_connection(s->connection); } + + +static void * +ngx_imap_proxy_create_conf(ngx_conf_t *cf) +{ + ngx_imap_proxy_conf_t *pcf; + + pcf = ngx_pcalloc(cf->pool, sizeof(ngx_imap_proxy_conf_t)); + if (pcf == NULL) { + return NGX_CONF_ERROR; + } + + pcf->enable = NGX_CONF_UNSET; + + return pcf; +} + + +static char * +ngx_imap_proxy_merge_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_imap_proxy_conf_t *prev = parent; + ngx_imap_proxy_conf_t *conf = child; + + ngx_conf_merge_msec_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -838,6 +838,15 @@ ngx_worker_process_init(ngx_cycle_t *cyc #endif + if (ccf->working_directory.len) { + if (chdir(ccf->working_directory.data) == -1) { + ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, + "chdir(\"%s\") failed", ccf->working_directory.data); + /* fatal */ + exit(2); + } + } + sigemptyset(&set); if (sigprocmask(SIG_SETMASK, &set, NULL) == -1) {