# HG changeset patch # User Maxim Dounin # Date 1221739148 -14400 # Node ID c65888a079bfd96a2eedb308c9d5c7b4f7de6296 # Parent 2f3f9dbf84d0cf6aa471072bc52411c63bc614e4# Parent b453a4324c60689e0def20c4fcd1311726726640 Merge with current. diff --git a/.hgtags b/.hgtags --- a/.hgtags +++ b/.hgtags @@ -198,3 +198,9 @@ 34fb3a5735483bd22e77f90f305103307a813fc4 05981f639d211e316c98ff3074a0f268fbde8bed NGINX_0_7_9 349057ecf4d5d2886b08e6c61656548577243141 NGINX_0_7_10 9d81578d04bbc73636567e84ed5a48e86826eb1b NGINX_0_7_11 +6ebbca3d5ed73b82e1e0aa14adff133b50bbb4ea NGINX_0_7_12 +df7b79c859c361542f840721db02f2183471c834 NGINX_0_7_13 +a094317ba3074c6d71215c39b02a0e027ae1bd79 NGINX_0_7_14 +79c5df00501e08b14b9457873e691c74059e7519 NGINX_0_7_15 +a2a3905c04abe7ff22d33176682cdba5eb6cf186 NGINX_0_7_16 +a8e3f1441eec1b608b77f39110e16f0b82b983d5 NGINX_0_7_17 diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,87 @@ +Changes with nginx 0.7.17 15 Sep 2008 + + *) Feature: now the "directio" directive works on Linux. + + *) Feature: the $pid variable. + + *) Bugfix: the "directio" optimization that had appeared in 0.7.15 did + not work with open_file_cache. + + *) Bugfix: the "access_log" with variables did not work on Linux; the + bug had appeared in 0.7.7. + + *) Bugfix: the ngx_http_charset_module did not understand quoted + charset name received from backend. + + +Changes with nginx 0.7.16 08 Sep 2008 + + *) Bugfix: nginx could not be built on 64-bit platforms; the bug had + appeared in 0.7.15. + + +Changes with nginx 0.7.15 08 Sep 2008 + + *) Feature: the ngx_http_random_index_module. + + *) Feature: the "directio" directive has been optimized for file + requests starting from arbitrary position. + + *) Feature: the "directio" directive turns off sendfile if it is + necessary. + + *) Feature: now nginx allows underscores in a client request header + line names. + + +Changes with nginx 0.7.14 01 Sep 2008 + + *) Change: now the ssl_certificate and ssl_certificate_key directives + have not default values. + + *) Feature: the "listen" directive supports the "ssl" parameter. + + *) Feature: now nginx takes into account a time zone change while + reconfiguration on FreeBSD and Linux. + + *) Bugfix: the "listen" directive parameters such as "backlog", + "rcvbuf", etc. were not set, if a default server was not the first + one. + + *) Bugfix: if URI part captured by a "rewrite" directive was used as a + query string, then the query string was not escaped. + + *) Bugfix: configuration file validity test improvements. + + +Changes with nginx 0.7.13 26 Aug 2008 + + *) Bugfix: nginx could not be built on Linux and Solaris; the bug had + appeared in 0.7.12. + + +Changes with nginx 0.7.12 26 Aug 2008 + + *) Feature: the "server_name" directive supports empty name "". + + *) Feature: the "gzip_disable" directive supports special "msie6" mask. + + *) Bugfix: if the "max_fails=0" parameter was used in upstream with + several servers, then a worker process exited on a SIGFPE signal. + Thanks to Maxim Dounin. + + *) Bugfix: a request body was dropped while redirection via an + "error_page" directive. + + *) Bugfix: a full response was returned for request method HEAD while + redirection via an "error_page" directive. + + *) Bugfix: the $r->header_in() method did not return value of the + "Host", "User-Agent", and "Connection" request header lines; the bug + had appeared in 0.7.0. + + Changes with nginx 0.7.11 18 Aug 2008 *) Change: now ngx_http_charset_module does not work by default with diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,90 @@ +Изменения в nginx 0.7.17 15.09.2008 + + *) Добавление: директива directio теперь работает на Linux. + + *) Добавление: переменная $pid. + + *) Исправление: оптимизация directio, появившаяся в 0.7.15, не работала + при использовании open_file_cache. + + *) Исправление: access_log с переменными не работал на Linux; ошибка + появилась в 0.7.7. + + *) Исправление: модуль ngx_http_charset_module не понимал название + кодировки в кавычках, полученное от бэкенда. + + +Изменения в nginx 0.7.16 08.09.2008 + + *) Исправление: nginx не собирался на 64-битных платформах; ошибка + появилась в 0.7.15. + + +Изменения в nginx 0.7.15 08.09.2008 + + *) Добавление: модуль ngx_http_random_index_module. + + *) Добавление: директива directio оптимизирована для запросов файлов, + начинающихся с произвольной позиции. + + *) Добавление: директива directio при необходимости запрещает + использование sendfile. + + *) Добавление: теперь nginx разрешает подчёркивания в именах строк в + заголовке запроса клиента. + + +Изменения в nginx 0.7.14 01.09.2008 + + *) Изменение: теперь директивы ssl_certificate и ssl_certificate_key не + имеют значений по умолчанию. + + *) Добавление: директива listen поддерживает параметр ssl. + + *) Добавление: теперь при переконфигурации nginx учитывает изменение + временной зоны на FreeBSD и Linux. + + *) Исправление: параметры директивы listen, такие как backlog, rcvbuf и + прочие, не устанавливались, если сервером по умолчанию был не первый + сервер. + + *) Исправление: при использовании в качестве аргументов части URI, + выделенного с помощью директивы rewrite, эти аргументы не + экранировались. + + *) Исправление: улучшения тестирования правильности конфигурационного + файла. + + +Изменения в nginx 0.7.13 26.08.2008 + + *) Исправление: nginx не собирался на Linux и Solaris; ошибка появилась + в 0.7.12. + + +Изменения в nginx 0.7.12 26.08.2008 + + *) Добавление: директива server_name поддерживает пустое имя "". + + *) Добавление: директива gzip_disable поддерживает специальную маску + msie6. + + *) Исправление: при использовании параметра max_fails=0 в upstream'е с + несколькими серверами рабочий процесс выходил по сигналу SIGFPE. + Спасибо Максиму Дунину. + + *) Исправление: при перенаправлении запроса с помощью директивы + error_page терялось тело запроса. + + *) Исправление: при перенаправлении запроса с методом HEAD с помощью + директивы error_page возвращался полный ответ. + + *) Исправление: метод $r->header_in() не возвращал значения строк + "Host", "User-Agent", и "Connection" из заголовка запроса; ошибка + появилась в 0.7.0. + + Изменения в nginx 0.7.11 18.08.2008 *) Изменение: теперь ngx_http_charset_module по умолчанию не работает diff --git a/auto/modules b/auto/modules --- a/auto/modules +++ b/auto/modules @@ -81,6 +81,7 @@ fi # ngx_http_dav_module # ngx_http_autoindex_module # ngx_http_index_module +# ngx_http_random_index_module # # ngx_http_access_module # ngx_http_realip_module @@ -179,6 +180,12 @@ fi HTTP_MODULES="$HTTP_MODULES $HTTP_INDEX_MODULE" +if [ $HTTP_RANDOM_INDEX = YES ]; then + have=NGX_HTTP_RANDOM_INDEX . auto/have + HTTP_MODULES="$HTTP_MODULES $HTTP_RANDOM_INDEX_MODULE" + HTTP_SRCS="$HTTP_SRCS $HTTP_RANDOM_INDEX_SRCS" +fi + if [ $HTTP_AUTH_BASIC = YES ]; then have=NGX_HTTP_AUTH_BASIC . auto/have have=NGX_CRYPT . auto/have diff --git a/auto/options b/auto/options --- a/auto/options +++ b/auto/options @@ -64,6 +64,7 @@ HTTP_ACCESS=YES HTTP_AUTH_BASIC=YES HTTP_USERID=YES HTTP_AUTOINDEX=YES +HTTP_RANDOM_INDEX=NO HTTP_STATUS=NO HTTP_GEO=YES HTTP_MAP=YES @@ -171,6 +172,7 @@ do --with-http_dav_module) HTTP_DAV=YES ;; --with-http_flv_module) HTTP_FLV=YES ;; --with-http_gzip_static_module) HTTP_GZIP_STATIC=YES ;; + --with-http_random_index_module) HTTP_RANDOM_INDEX=YES ;; --without-http_charset_module) HTTP_CHARSET=NO ;; --without-http_gzip_module) HTTP_GZIP=NO ;; @@ -287,6 +289,7 @@ cat << END --with-http_dav_module enable ngx_http_dav_module --with-http_flv_module enable ngx_http_flv_module --with-http_gzip_static_module enable ngx_http_gzip_static_module + --with-http_random_index_module enable ngx_http_random_index_module --with-http_stub_status_module enable ngx_http_stub_status_module --without-http_charset_module disable ngx_http_charset_module diff --git a/auto/os/features b/auto/os/features --- a/auto/os/features +++ b/auto/os/features @@ -182,6 +182,10 @@ ngx_feature_test="fcntl(0, F_SETFL, O_DI . auto/feature +if [ $ngx_found = yes -a "$NGX_SYSTEM" = "Linux" ]; then + have=NGX_HAVE_ALIGNED_DIRECTIO . auto/have +fi + ngx_feature="F_NOCACHE" ngx_feature_name="NGX_HAVE_F_NOCACHE" ngx_feature_run=no diff --git a/auto/sources b/auto/sources --- a/auto/sources +++ b/auto/sources @@ -131,7 +131,6 @@ UNIX_INCS="$CORE_INCS $EVENT_INCS src/os UNIX_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/unix/ngx_time.h \ - src/os/unix/ngx_types.h \ src/os/unix/ngx_errno.h \ src/os/unix/ngx_alloc.h \ src/os/unix/ngx_files.h \ @@ -208,7 +207,6 @@ WIN32_INCS="$CORE_INCS $EVENT_INCS src/o WIN32_DEPS="$CORE_DEPS $EVENT_DEPS \ src/os/win32/ngx_win32_config.h \ src/os/win32/ngx_time.h \ - src/os/win32/ngx_types.h \ src/os/win32/ngx_errno.h \ src/os/win32/ngx_alloc.h \ src/os/win32/ngx_files.h \ @@ -369,6 +367,10 @@ HTTP_AUTOINDEX_MODULE=ngx_http_autoindex HTTP_AUTOINDEX_SRCS=src/http/modules/ngx_http_autoindex_module.c +HTTP_RANDOM_INDEX_MODULE=ngx_http_random_index_module +HTTP_RANDOM_INDEX_SRCS=src/http/modules/ngx_http_random_index_module.c + + HTTP_STATUS_MODULE=ngx_http_status_module HTTP_STATUS_SRCS=src/http/modules/ngx_http_status_module.c diff --git a/auto/unix b/auto/unix --- a/auto/unix +++ b/auto/unix @@ -229,3 +229,23 @@ ngx_feature_path= ngx_feature_libs= ngx_feature_test="struct tm tm; tm.tm_gmtoff = 0" . auto/feature + + +ngx_feature="struct dirent.d_namlen" +ngx_feature_name="NGX_HAVE_D_NAMLEN" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct dirent dir; dir.d_namlen = 0" +. auto/feature + + +ngx_feature="struct dirent.d_type" +ngx_feature_name="NGX_HAVE_D_TYPE" +ngx_feature_run=no +ngx_feature_incs="#include " +ngx_feature_path= +ngx_feature_libs= +ngx_feature_test="struct dirent dir; dir.d_type = DT_REG" +. auto/feature diff --git a/conf/mime.types b/conf/mime.types --- a/conf/mime.types +++ b/conf/mime.types @@ -33,6 +33,8 @@ types { application/vnd.ms-powerpoint ppt; application/vnd.wap.wmlc wmlc; application/vnd.wap.xhtml+xml xhtml; + application/vnd.google-earth.kml+xml kml; + application/vnd.google-earth.kmz kmz; application/x-cocoa cco; application/x-java-archive-diff jardiff; application/x-java-jnlp-file jnlp; diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.7.11" +#define NGINX_VERSION "0.7.17" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_buf.h b/src/core/ngx_buf.h --- a/src/core/ngx_buf.h +++ b/src/core/ngx_buf.h @@ -78,6 +78,10 @@ typedef struct { ngx_chain_t *busy; unsigned sendfile; + unsigned directio; +#if (NGX_HAVE_ALIGNED_DIRECTIO) + unsigned unaligned; +#endif unsigned need_in_memory; unsigned need_in_temp; diff --git a/src/core/ngx_conf_file.c b/src/core/ngx_conf_file.c --- a/src/core/ngx_conf_file.c +++ b/src/core/ngx_conf_file.c @@ -7,6 +7,7 @@ #include #include +#define NGX_CONF_BUFFER 4096 static ngx_int_t ngx_conf_handler(ngx_conf_t *cf, ngx_int_t last); static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf); @@ -43,9 +44,9 @@ ngx_module_t ngx_conf_module = { }; -/* The ten fixed arguments */ +/* The eight fixed arguments */ -static int argument_number[] = { +static ngx_uint_t argument_number[] = { NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_TAKE2, @@ -141,14 +142,14 @@ ngx_conf_parse(ngx_conf_t *cf, ngx_str_t cf->conf_file->buffer = b; - b->start = ngx_alloc(ngx_pagesize, cf->log); + b->start = ngx_alloc(NGX_CONF_BUFFER, cf->log); if (b->start == NULL) { return NGX_CONF_ERROR; } b->pos = b->start; b->last = b->start; - b->end = b->last + ngx_pagesize; + b->end = b->last + NGX_CONF_BUFFER; b->temporary = 1; cf->conf_file->file.fd = fd; @@ -433,10 +434,11 @@ static ngx_int_t ngx_conf_read_token(ngx_conf_t *cf) { u_char *start, ch, *src, *dst; - int len; - int found, need_space, last_space, sharp_comment, variable; - int quoted, s_quoted, d_quoted; - ssize_t n; + off_t file_size; + size_t len; + ssize_t n, size; + ngx_uint_t found, need_space, last_space, sharp_comment, variable; + ngx_uint_t quoted, s_quoted, d_quoted, start_line; ngx_str_t *word; ngx_buf_t *b; @@ -450,14 +452,16 @@ ngx_conf_read_token(ngx_conf_t *cf) cf->args->nelts = 0; b = cf->conf_file->buffer; start = b->pos; + start_line = cf->conf_file->line; + + file_size = ngx_file_size(&cf->conf_file->file.info); for ( ;; ) { if (b->pos >= b->last) { - if (cf->conf_file->file.offset - >= ngx_file_size(&cf->conf_file->file.info)) - { + if (cf->conf_file->file.offset >= file_size) { + if (cf->args->nelts > 0) { if (cf->conf_file->file.fd == NGX_INVALID_FILE) { @@ -476,22 +480,58 @@ ngx_conf_read_token(ngx_conf_t *cf) return NGX_CONF_FILE_DONE; } - if (b->pos - start) { - ngx_memcpy(b->start, start, b->pos - start); + len = b->pos - start; + + if (len == NGX_CONF_BUFFER) { + cf->conf_file->line = start_line; + + if (d_quoted) { + ch = '"'; + + } else if (s_quoted) { + ch = '\''; + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long parameter \"%*s...\" started", + 10, start); + return NGX_ERROR; + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "too long parameter, probably " + "missing terminating \"%c\" character", ch); + return NGX_ERROR; } - n = ngx_read_file(&cf->conf_file->file, - b->start + (b->pos - start), - b->end - (b->start + (b->pos - start)), + if (len) { + ngx_memcpy(b->start, start, len); + } + + size = (ssize_t) (file_size - cf->conf_file->file.offset); + + if (size > b->end - (b->start + len)) { + size = b->end - (b->start + len); + } + + n = ngx_read_file(&cf->conf_file->file, b->start + len, size, cf->conf_file->file.offset); if (n == NGX_ERROR) { return NGX_ERROR; } - b->pos = b->start + (b->pos - start); + if (n != size) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + ngx_read_file_n " returned " + "only %z bytes instead of %z", + n, size); + return NGX_ERROR; + } + + b->pos = b->start + len; + b->last = b->pos + n; start = b->start; - b->last = b->pos + n; } ch = *b->pos++; @@ -545,6 +585,7 @@ ngx_conf_read_token(ngx_conf_t *cf) } start = b->pos - 1; + start_line = cf->conf_file->line; switch (ch) { diff --git a/src/core/ngx_conf_file.h b/src/core/ngx_conf_file.h --- a/src/core/ngx_conf_file.h +++ b/src/core/ngx_conf_file.h @@ -314,9 +314,6 @@ char *ngx_conf_check_num_bounds(ngx_conf } -#define addressof(addr) ((int) &addr) - - char *ngx_conf_param(ngx_conf_t *cf); char *ngx_conf_parse(ngx_conf_t *cf, ngx_str_t *filename); diff --git a/src/core/ngx_config.h b/src/core/ngx_config.h --- a/src/core/ngx_config.h +++ b/src/core/ngx_config.h @@ -116,10 +116,6 @@ typedef intptr_t ngx_flag_t; #define INADDR_NONE ((unsigned int) -1) #endif -#ifndef INET_ADDRSTRLEN /* Win32 */ -#define INET_ADDRSTRLEN 16 -#endif - #ifdef MAXHOSTNAMELEN #define NGX_MAXHOSTNAMELEN MAXHOSTNAMELEN #else 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 @@ -37,23 +37,23 @@ ngx_listening_inet_stream_socket(ngx_con ls->addr_text.data = ngx_pnalloc(cf->pool, - INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); + NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1); if (ls->addr_text.data == NULL) { return NULL; } - len = ngx_inet_ntop(AF_INET, &addr, ls->addr_text.data, INET_ADDRSTRLEN); + len = ngx_inet_ntop(AF_INET, &addr, ls->addr_text.data, + NGX_INET_ADDRSTRLEN); ls->addr_text.len = ngx_sprintf(ls->addr_text.data + len, ":%d", port) - ls->addr_text.data; ls->fd = (ngx_socket_t) -1; - ls->family = AF_INET; ls->type = SOCK_STREAM; ls->sockaddr = (struct sockaddr *) sin; ls->socklen = sizeof(struct sockaddr_in); ls->addr = offsetof(struct sockaddr_in, sin_addr); - ls->addr_text_max_len = INET_ADDRSTRLEN; + ls->addr_text_max_len = NGX_INET_ADDRSTRLEN; return ls; } @@ -104,17 +104,16 @@ ngx_set_inherited_sockets(ngx_cycle_t *c continue; } - ls[i].addr_text_max_len = INET_ADDRSTRLEN; + ls[i].addr_text_max_len = NGX_INET_ADDRSTRLEN; ls[i].addr_text.data = ngx_pnalloc(cycle->pool, - INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); + NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1); if (ls[i].addr_text.data == NULL) { return NGX_ERROR; } - ls[i].family = sin->sin_family; - len = ngx_sock_ntop(ls[i].family, ls[i].sockaddr, - ls[i].addr_text.data, INET_ADDRSTRLEN); + len = ngx_sock_ntop(ls[i].sockaddr, ls[i].addr_text.data, + NGX_INET_ADDRSTRLEN); if (len == 0) { return NGX_ERROR; } @@ -254,7 +253,7 @@ ngx_open_listening_sockets(ngx_cycle_t * continue; } - s = ngx_socket(ls[i].family, ls[i].type, 0); + s = ngx_socket(ls[i].sockaddr->sa_family, ls[i].type, 0); if (s == -1) { ngx_log_error(NGX_LOG_EMERG, log, ngx_socket_errno, 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 @@ -23,7 +23,6 @@ struct ngx_listening_s { size_t addr_text_max_len; ngx_str_t addr_text; - int family; int type; int backlog; diff --git a/src/core/ngx_core.h b/src/core/ngx_core.h --- a/src/core/ngx_core.h +++ b/src/core/ngx_core.h @@ -40,11 +40,11 @@ typedef void (*ngx_connection_handler_pt #include #include #include -#include +#include +#include #include #include #include -#include #include #include #include @@ -55,7 +55,6 @@ typedef void (*ngx_connection_handler_pt #include #include #include -#include #include #include #if (NGX_PCRE) diff --git a/src/core/ngx_cycle.c b/src/core/ngx_cycle.c --- a/src/core/ngx_cycle.c +++ b/src/core/ngx_cycle.c @@ -47,6 +47,7 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) u_char *lock_file; ngx_uint_t i, n; ngx_log_t *log; + ngx_time_t *tp; ngx_conf_t conf; ngx_pool_t *pool; ngx_cycle_t *cycle, **old; @@ -59,6 +60,16 @@ ngx_init_cycle(ngx_cycle_t *old_cycle) ngx_core_module_t *module; char hostname[NGX_MAXHOSTNAMELEN]; + ngx_timezone_update(); + + /* force localtime update with a new timezone */ + + tp = ngx_timeofday(); + tp->sec = 0; + + ngx_time_update(0, 0); + + log = old_cycle->log; pool = ngx_create_pool(NGX_CYCLE_POOL_SIZE, log); diff --git a/src/core/ngx_file.h b/src/core/ngx_file.h --- a/src/core/ngx_file.h +++ b/src/core/ngx_file.h @@ -26,7 +26,8 @@ struct ngx_file_s { ngx_log_t *log; - ngx_uint_t valid_info; /* unsigned valid_info:1; */ + unsigned valid_info:1; + unsigned directio:1; }; #define NGX_MAX_PATH_LEVEL 3 diff --git a/src/core/ngx_hash.c b/src/core/ngx_hash.c --- a/src/core/ngx_hash.c +++ b/src/core/ngx_hash.c @@ -220,6 +220,10 @@ ngx_hash_find_combined(ngx_hash_combined } } + if (len == 0) { + return NULL; + } + if (hash->wc_head && hash->wc_head->hash.buckets) { value = ngx_hash_find_wc_head(hash->wc_head, name, len); diff --git a/src/core/ngx_inet.c b/src/core/ngx_inet.c --- a/src/core/ngx_inet.c +++ b/src/core/ngx_inet.c @@ -8,7 +8,8 @@ #include -static size_t ngx_sprint_uchar(u_char *text, u_char c, size_t len); +static ngx_int_t ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u); +static ngx_int_t ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u); /* AF_INET only */ @@ -56,166 +57,43 @@ ngx_inet_addr(u_char *text, size_t len) } -/* - * ngx_sock_ntop() and ngx_inet_ntop() may be implemented as - * "ngx_sprintf(text, "%ud.%ud.%ud.%ud", p[0], p[1], p[2], p[3])", however, - * they had been implemented long before the ngx_sprintf() had appeared - * and they are faster by 1.5-2.5 times, so it is worth to keep them. - * - * By the way, the implementation using ngx_sprintf() is faster by 2.5-3 times - * than using FreeBSD libc's snprintf(). - */ - /* AF_INET only */ size_t -ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len) +ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len) { u_char *p; - size_t n; - ngx_uint_t i; struct sockaddr_in *sin; - if (len == 0) { - return 0; - } + if (sa->sa_family == AF_INET) { - if (family != AF_INET) { - return 0; - } + sin = (struct sockaddr_in *) sa; + p = (u_char *) &sin->sin_addr; - sin = (struct sockaddr_in *) sa; - p = (u_char *) &sin->sin_addr; - - if (len > INET_ADDRSTRLEN) { - len = INET_ADDRSTRLEN; + return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", + p[0], p[1], p[2], p[3]) + - text; } - n = ngx_sprint_uchar(text, p[0], len); - - i = 1; - - do { - if (len == n) { - text[n - 1] = '\0'; - return n; - } - - text[n++] = '.'; - - if (len == n) { - text[n - 1] = '\0'; - return n; - } - - n += ngx_sprint_uchar(&text[n], p[i++], len - n); - - } while (i < 4); - - if (len == n) { - text[n] = '\0'; - return n; - } - - text[n] = '\0'; - - return n; + return 0; } size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len) { - u_char *p; - size_t n; - ngx_uint_t i; - - if (len == 0) { - return 0; - } + u_char *p; - if (family != AF_INET) { - return 0; - } - - p = (u_char *) addr; - - if (len > INET_ADDRSTRLEN) { - len = INET_ADDRSTRLEN; - } - - n = ngx_sprint_uchar(text, p[0], len); + if (family == AF_INET) { - i = 1; - - do { - if (len == n) { - text[n - 1] = '\0'; - return n; - } - - text[n++] = '.'; + p = (u_char *) addr; - if (len == n) { - text[n - 1] = '\0'; - return n; - } - - n += ngx_sprint_uchar(&text[n], p[i++], len - n); - - } while (i < 4); - - if (len == n) { - text[n] = '\0'; - return n; + return ngx_snprintf(text, len, "%ud.%ud.%ud.%ud", + p[0], p[1], p[2], p[3]) + - text; } - text[n] = '\0'; - - return n; -} - - -static size_t -ngx_sprint_uchar(u_char *text, u_char c, size_t len) -{ - size_t n; - ngx_uint_t c1, c2; - - n = 0; - - if (len == n) { - return n; - } - - c1 = c / 100; - - if (c1) { - *text++ = (u_char) (c1 + '0'); - n++; - - if (len == n) { - return n; - } - } - - c2 = (c % 100) / 10; - - if (c1 || c2) { - *text++ = (u_char) (c2 + '0'); - n++; - - if (len == n) { - return n; - } - } - - c2 = c % 10; - - *text = (u_char) (c2 + '0'); - n++; - - return n; + return 0; } @@ -224,43 +102,48 @@ ngx_sprint_uchar(u_char *text, u_char c, ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr) { - ngx_int_t m; - ngx_uint_t i; + u_char *addr, *mask, *last; + ngx_int_t shift; ngx_inet_cidr_t *in_cidr; in_cidr = cidr; - - for (i = 0; i < text->len; i++) { - if (text->data[i] == '/') { - break; - } - } + addr = text->data; + last = addr + text->len; - if (i == text->len) { - return NGX_ERROR; - } + mask = ngx_strlchr(addr, last, '/'); - text->data[i] = '\0'; - in_cidr->addr = inet_addr((char *) text->data); - text->data[i] = '/'; + in_cidr->addr = ngx_inet_addr(addr, (mask ? mask : last) - addr); + if (in_cidr->addr == INADDR_NONE) { return NGX_ERROR; } - m = ngx_atoi(&text->data[i + 1], text->len - (i + 1)); - if (m == NGX_ERROR) { + if (mask == NULL) { + in_cidr->mask = 0xffffffff; + return NGX_OK; + } + + mask++; + + shift = ngx_atoi(mask, last - mask); + if (shift == NGX_ERROR) { return NGX_ERROR; } - if (m == 0) { + if (shift == 0) { /* the x86 compilers use the shl instruction that shifts by modulo 32 */ in_cidr->mask = 0; - return NGX_OK; + + if (in_cidr->addr == 0) { + return NGX_OK; + } + + return NGX_DONE; } - in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - m)))); + in_cidr->mask = htonl((ngx_uint_t) (0 - (1 << (32 - shift)))); if (in_cidr->addr == (in_cidr->addr & in_cidr->mask)) { return NGX_OK; @@ -275,85 +158,12 @@ ngx_ptocidr(ngx_str_t *text, void *cidr) ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u) { - u_char *p, *host, *port_start; - size_t len, port_len; - ngx_int_t port; - ngx_uint_t i; - struct hostent *h; -#if (NGX_HAVE_UNIX_DOMAIN) - struct sockaddr_un *saun; -#endif + u_char *p; - len = u->url.len; p = u->url.data; if (ngx_strncasecmp(p, (u_char *) "unix:", 5) == 0) { - -#if (NGX_HAVE_UNIX_DOMAIN) - - p += 5; - len -= 5; - - u->uri.len = len; - u->uri.data = p; - - if (u->uri_part) { - for (i = 0; i < len; i++) { - - if (p[i] == ':') { - len = i; - - u->uri.len -= len + 1; - u->uri.data += len + 1; - - break; - } - } - } - - if (len == 0) { - u->err = "no path in the unix domain socket"; - return NGX_ERROR; - } - - if (len + 1 > sizeof(saun->sun_path)) { - u->err = "too long path in the unix domain socket"; - return NGX_ERROR; - } - - u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); - if (u->addrs == NULL) { - return NGX_ERROR; - } - - saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un)); - if (saun == NULL) { - return NGX_ERROR; - } - - u->naddrs = 1; - - saun->sun_family = AF_UNIX; - (void) ngx_cpystrn((u_char *) saun->sun_path, p, len + 1); - - u->addrs[0].sockaddr = (struct sockaddr *) saun; - u->addrs[0].socklen = sizeof(struct sockaddr_un); - u->addrs[0].name.len = len + 5; - u->addrs[0].name.data = u->url.data; - - u->host.len = len; - u->host.data = p; - - u->unix_socket = 1; - - return NGX_OK; - -#else - u->err = "the unix domain sockets are not supported on this platform"; - - return NGX_ERROR; - -#endif + return ngx_parse_unix_domain_url(pool, u); } if ((p[0] == ':' || p[0] == '/') && !u->listen) { @@ -361,150 +171,219 @@ ngx_parse_url(ngx_pool_t *pool, ngx_url_ return NGX_ERROR; } - u->host.data = p; + return ngx_parse_inet_url(pool, u); +} - port_start = NULL; - port_len = 0; - - for (i = 0; i < len; i++) { - if (p[i] == ':') { - port_start = &p[i + 1]; - u->host.len = i; - - if (!u->uri_part) { - port_len = len - (i + 1); - break; - } - } +static ngx_int_t +ngx_parse_unix_domain_url(ngx_pool_t *pool, ngx_url_t *u) +{ +#if (NGX_HAVE_UNIX_DOMAIN) + u_char *path, *uri, *last; + size_t len; + struct sockaddr_un *saun; - if (p[i] == '/') { - u->uri.len = len - i; - u->uri.data = &p[i]; + len = u->url.len; + path = u->url.data; - if (u->host.len == 0) { - u->host.len = i; - } + path += 5; + len -= 5; + + if (u->uri_part) { - if (port_start == NULL) { - u->no_port = 1; - goto no_port; - } - - port_len = &p[i] - port_start; + last = path + len; + uri = ngx_strlchr(path, last, ':'); - if (port_len == 0) { - u->err = "invalid port"; - return NGX_ERROR; - } - - break; + if (uri) { + len = uri - path; + uri++; + u->uri.len = last - uri; + u->uri.data = uri; } } - if (port_start) { + if (len == 0) { + u->err = "no path in the unix domain socket"; + return NGX_ERROR; + } + + u->host.len = len++; + u->host.data = path; + u->family = AF_UNIX; + + if (len > sizeof(saun->sun_path)) { + u->err = "too long path in the unix domain socket"; + return NGX_ERROR; + } - if (port_len == 0) { - port_len = &p[i] - port_start; + u->addrs = ngx_pcalloc(pool, sizeof(ngx_peer_addr_t)); + if (u->addrs == NULL) { + return NGX_ERROR; + } + + saun = ngx_pcalloc(pool, sizeof(struct sockaddr_un)); + if (saun == NULL) { + return NGX_ERROR; + } + + u->naddrs = 1; + + saun->sun_family = AF_UNIX; + (void) ngx_cpystrn((u_char *) saun->sun_path, path, len); + + u->addrs[0].sockaddr = (struct sockaddr *) saun; + u->addrs[0].socklen = sizeof(struct sockaddr_un); + u->addrs[0].name.len = len + 4; + u->addrs[0].name.data = u->url.data; - if (port_len == 0) { - u->err = "invalid port"; - return NGX_ERROR; - } + return NGX_OK; + +#else + + u->err = "the unix domain sockets are not supported on this platform"; + + return NGX_ERROR; + +#endif +} + + +static ngx_int_t +ngx_parse_inet_url(ngx_pool_t *pool, ngx_url_t *u) +{ + u_char *p, *host, *port, *last, *uri; + size_t len; + ngx_int_t n; + struct hostent *h; + + u->family = AF_INET; + + host = u->url.data; + + last = host + u->url.len; + + port = ngx_strlchr(host, last, ':'); + + uri = ngx_strlchr(port ? port : host, last, '/'); + + if (uri) { + if (u->listen || !u->uri_part) { + u->err = "invalid host"; + return NGX_ERROR; } - port = ngx_atoi(port_start, port_len); + u->uri.len = last - uri; + u->uri.data = uri; + + last = uri; + } - if (port == NGX_ERROR || port < 1 || port > 65536) { + if (port) { + port++; + + len = last - port; + + if (len == 0) { u->err = "invalid port"; return NGX_ERROR; } - u->port_text.len = port_len; - u->port_text.data = port_start; - - } else { - port = ngx_atoi(p, len); - - if (port == NGX_ERROR) { - u->host.len = len; - u->no_port = 1; - - goto no_port; - } - - u->wildcard = 1; - } + n = ngx_atoi(port, len); - u->port = (in_port_t) port; - -no_port: - - if (u->listen) { - - if (u->port == 0) { - if (u->default_port == 0) { - u->err = "no port"; - return NGX_ERROR; - } - - u->port = u->default_port; - } - - if (u->host.len == 1 && u->host.data[0] == '*') { - u->host.len = 0; + if (n < 1 || n > 65536) { + u->err = "invalid port"; + return NGX_ERROR; } - /* AF_INET only */ + u->port = (in_port_t) n; - if (u->host.len) { + u->port_text.len = len; + u->port_text.data = port; + + last = port - 1; - host = ngx_alloc(u->host.len + 1, pool->log); - if (host == NULL) { - return NGX_ERROR; - } + } else { + if (uri == NULL) { - (void) ngx_cpystrn(host, u->host.data, u->host.len + 1); + if (u->listen) { - u->addr.in_addr = inet_addr((const char *) host); + /* test value as port only */ + + n = ngx_atoi(host, last - host); - if (u->addr.in_addr == INADDR_NONE) { - h = gethostbyname((const char *) host); + if (n != NGX_ERROR) { + + if (n < 1 || n > 65536) { + u->err = "invalid port"; + return NGX_ERROR; + } - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_free(host); - u->err = "host not found"; - return NGX_ERROR; + u->port = (in_port_t) n; + + u->port_text.len = last - host; + u->port_text.data = host; + + return NGX_OK; } - - u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]); } - - ngx_free(host); - - } else { - u->addr.in_addr = INADDR_ANY; } - return NGX_OK; + u->no_port = 1; } - if (u->host.len == 0) { + len = last - host; + + if (len == 0) { u->err = "no host"; return NGX_ERROR; } + if (len == 1 && *host == '*') { + len = 0; + } + + u->host.len = len; + u->host.data = host; + if (u->no_resolve) { return NGX_OK; } + if (len++) { + + p = ngx_alloc(len, pool->log); + if (p == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn(p, host, len); + + u->addr.in_addr = inet_addr((const char *) p); + + if (u->addr.in_addr == INADDR_NONE) { + h = gethostbyname((const char *) p); + + if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_free(p); + u->err = "host not found"; + return NGX_ERROR; + } + + u->addr.in_addr = *(in_addr_t *) (h->h_addr_list[0]); + } + + ngx_free(p); + + } else { + u->addr.in_addr = INADDR_ANY; + } + if (u->no_port) { u->port = u->default_port; } - if (u->port == 0) { - u->err = "no port"; - return NGX_ERROR; + if (u->listen) { + return NGX_OK; } if (ngx_inet_resolve_host(pool, u) != NGX_OK) { @@ -576,14 +455,14 @@ ngx_inet_resolve_host(ngx_pool_t *pool, u->addrs[i].sockaddr = (struct sockaddr *) sin; u->addrs[i].socklen = sizeof(struct sockaddr_in); - len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1; + len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1; p = ngx_pnalloc(pool, len); if (p == NULL) { return NGX_ERROR; } - len = ngx_sock_ntop(AF_INET, (struct sockaddr *) sin, p, len); + len = ngx_sock_ntop((struct sockaddr *) sin, p, len); u->addrs[i].name.len = ngx_sprintf(&p[len], ":%d", u->port) - p; u->addrs[i].name.data = p; diff --git a/src/core/ngx_inet.h b/src/core/ngx_inet.h --- a/src/core/ngx_inet.h +++ b/src/core/ngx_inet.h @@ -12,6 +12,9 @@ #include +#define NGX_INET_ADDRSTRLEN (sizeof("255.255.255.255") - 1) + + typedef struct { in_addr_t addr; in_addr_t mask; @@ -31,8 +34,6 @@ typedef struct { typedef struct { - ngx_int_t type; - ngx_str_t url; ngx_str_t host; ngx_str_t port_text; @@ -40,15 +41,14 @@ typedef struct { in_port_t port; in_port_t default_port; + int family; unsigned listen:1; unsigned uri_part:1; unsigned no_resolve:1; unsigned one_addr:1; - unsigned wildcard:1; unsigned no_port:1; - unsigned unix_socket:1; ngx_url_addr_t addr; @@ -60,7 +60,7 @@ typedef struct { in_addr_t ngx_inet_addr(u_char *text, size_t len); -size_t ngx_sock_ntop(int family, struct sockaddr *sa, u_char *text, size_t len); +size_t ngx_sock_ntop(struct sockaddr *sa, u_char *text, size_t len); size_t ngx_inet_ntop(int family, void *addr, u_char *text, size_t len); ngx_int_t ngx_ptocidr(ngx_str_t *text, void *cidr); ngx_int_t ngx_parse_url(ngx_pool_t *pool, ngx_url_t *u); diff --git a/src/core/ngx_open_file_cache.c b/src/core/ngx_open_file_cache.c --- a/src/core/ngx_open_file_cache.c +++ b/src/core/ngx_open_file_cache.c @@ -205,6 +205,7 @@ ngx_open_cached_file(ngx_open_file_cache of->is_file = file->is_file; of->is_link = file->is_link; of->is_exec = file->is_exec; + of->is_directio = file->is_directio; if (!file->is_dir) { file->count++; @@ -360,6 +361,7 @@ update: file->is_file = of->is_file; file->is_link = of->is_link; file->is_exec = of->is_exec; + file->is_directio = of->is_directio; if (!of->is_dir) { file->count++; @@ -499,9 +501,12 @@ ngx_open_and_stat_file(u_char *name, ngx of->fd = fd; if (of->directio <= ngx_file_size(&fi)) { - if (ngx_directio(fd) == -1) { + if (ngx_directio_on(fd) == -1) { ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, - ngx_directio_n " \"%s\" failed", name); + ngx_directio_on_n " \"%s\" failed", name); + + } else { + of->is_directio = 1; } } } diff --git a/src/core/ngx_open_file_cache.h b/src/core/ngx_open_file_cache.h --- a/src/core/ngx_open_file_cache.h +++ b/src/core/ngx_open_file_cache.h @@ -33,6 +33,7 @@ typedef struct { unsigned is_file:1; unsigned is_link:1; unsigned is_exec:1; + unsigned is_directio:1; } ngx_open_file_info_t; @@ -62,6 +63,7 @@ struct ngx_cached_open_file_s { unsigned is_file:1; unsigned is_link:1; unsigned is_exec:1; + unsigned is_directio:1; ngx_event_t *event; }; diff --git a/src/core/ngx_output_chain.c b/src/core/ngx_output_chain.c --- a/src/core/ngx_output_chain.c +++ b/src/core/ngx_output_chain.c @@ -18,21 +18,21 @@ static ngx_inline ngx_int_t - ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); + ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf); static ngx_int_t ngx_output_chain_add_copy(ngx_pool_t *pool, ngx_chain_t **chain, ngx_chain_t *in); -static ngx_int_t ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, - ngx_uint_t sendfile); +static ngx_int_t ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, + off_t bsize); +static ngx_int_t ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, + off_t bsize); +static ngx_int_t ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx); ngx_int_t ngx_output_chain(ngx_output_chain_ctx_t *ctx, ngx_chain_t *in) { off_t bsize; - size_t size; ngx_int_t rc, last; - ngx_uint_t recycled; - ngx_buf_t *b; ngx_chain_t *cl, *out, **last_out; if (ctx->in == NULL && ctx->busy == NULL) { @@ -51,7 +51,7 @@ ngx_output_chain(ngx_output_chain_ctx_t #if (NGX_SENDFILE_LIMIT) && !(in->buf->in_file && in->buf->file_last > NGX_SENDFILE_LIMIT) #endif - && !ngx_output_chain_need_to_copy(ctx, in->buf)) + && ngx_output_chain_as_is(ctx, in->buf)) { return ctx->output_filter(ctx->filter_ctx, in); } @@ -75,7 +75,7 @@ ngx_output_chain(ngx_output_chain_ctx_t /* * cycle while there are the ctx->in bufs - * or there are the free output bufs to copy in + * and there are the free output bufs to copy in */ bsize = ngx_buf_size(ctx->in->buf); @@ -102,7 +102,7 @@ ngx_output_chain(ngx_output_chain_ctx_t continue; } - if (!ngx_output_chain_need_to_copy(ctx, ctx->in->buf)) { + if (ngx_output_chain_as_is(ctx, ctx->in->buf)) { /* move the chain link to the output chain */ @@ -118,79 +118,35 @@ ngx_output_chain(ngx_output_chain_ctx_t if (ctx->buf == NULL) { - /* get the free buf */ + rc = ngx_output_chain_align_file_buf(ctx, bsize); - if (ctx->free) { - cl = ctx->free; - ctx->buf = cl->buf; - ctx->free = cl->next; - ngx_free_chain(ctx->pool, cl); - - } else if (out || ctx->allocated == ctx->bufs.num) { + if (rc == NGX_ERROR) { + return NGX_ERROR; + } - break; - - } else { + if (rc != NGX_OK) { - size = ctx->bufs.size; - recycled = 1; + if (ctx->free) { - if (ctx->in->buf->last_in_chain) { - - if (bsize < (off_t) ctx->bufs.size) { + /* get the free buf */ - /* - * allocate small temp buf for the small last buf - * or its small last part - */ + cl = ctx->free; + ctx->buf = cl->buf; + ctx->free = cl->next; - size = (size_t) bsize; - recycled = 0; + ngx_free_chain(ctx->pool, cl); - } else if (ctx->bufs.num == 1 - && (bsize < (off_t) (ctx->bufs.size - + (ctx->bufs.size >> 2)))) - { - /* - * allocate a temp buf that equals - * to the last buf if the last buf size is lesser - * than 1.25 of bufs.size and a temp buf is single - */ + } else if (out || ctx->allocated == ctx->bufs.num) { - size = (size_t) bsize; - recycled = 0; - } - } + break; - b = ngx_calloc_buf(ctx->pool); - if (b == NULL) { + } else if (ngx_output_chain_get_buf(ctx, bsize) != NGX_OK) { return NGX_ERROR; } - - /* - * allocate block aligned to a disk sector size - * to enable O_DIRECT - */ - - b->start = ngx_pmemalign(ctx->pool, size, 512); - if (b->start == NULL) { - return NGX_ERROR; - } - - b->pos = b->start; - b->last = b->start; - b->end = b->last + size; - b->temporary = 1; - b->tag = ctx->tag; - b->recycled = recycled; - - ctx->buf = b; - ctx->allocated++; } } - rc = ngx_output_chain_copy_buf(ctx->buf, ctx->in->buf, - ctx->sendfile); + rc = ngx_output_chain_copy_buf(ctx); if (rc == NGX_ERROR) { return rc; @@ -244,11 +200,15 @@ ngx_output_chain(ngx_output_chain_ctx_t static ngx_inline ngx_int_t -ngx_output_chain_need_to_copy(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) +ngx_output_chain_as_is(ngx_output_chain_ctx_t *ctx, ngx_buf_t *buf) { ngx_uint_t sendfile; if (ngx_buf_special(buf)) { + return 1; + } + + if (buf->in_file && buf->file->directio) { return 0; } @@ -265,21 +225,21 @@ ngx_output_chain_need_to_copy(ngx_output if (!sendfile) { if (!ngx_buf_in_memory(buf)) { - return 1; + return 0; } buf->in_file = 0; } if (ctx->need_in_memory && !ngx_buf_in_memory(buf)) { - return 1; + return 0; } if (ctx->need_in_temp && (buf->memory || buf->mmap)) { - return 1; + return 0; } - return 0; + return 1; } @@ -313,6 +273,8 @@ ngx_output_chain_add_copy(ngx_pool_t *po && buf->file_pos < NGX_SENDFILE_LIMIT && buf->file_last > NGX_SENDFILE_LIMIT) { + /* split a file buf on two bufs by the sendfile limit */ + b = ngx_calloc_buf(pool); if (b == NULL) { return NGX_ERROR; @@ -352,10 +314,141 @@ ngx_output_chain_add_copy(ngx_pool_t *po static ngx_int_t -ngx_output_chain_copy_buf(ngx_buf_t *dst, ngx_buf_t *src, ngx_uint_t sendfile) +ngx_output_chain_align_file_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) +{ + size_t size; + ngx_buf_t *in; + + in = ctx->in->buf; + + if (in->file == NULL || !in->file->directio) { + return NGX_DECLINED; + } + + ctx->directio = 1; + + size = (size_t) (in->file_pos - (in->file_pos & ~511)); + + if (size == 0) { + + if (bsize >= (off_t) ctx->bufs.size) { + return NGX_DECLINED; + } + + size = (size_t) bsize; + + } else { + size = 512 - size; + + if ((off_t) size > bsize) { + size = (size_t) bsize; + } + } + + ctx->buf = ngx_create_temp_buf(ctx->pool, size); + if (ctx->buf == NULL) { + return NGX_ERROR; + } + + /* + * we do not set ctx->buf->tag, because we do not want + * to reuse the buf via ctx->free list + */ + +#if (NGX_HAVE_ALIGNED_DIRECTIO) + ctx->unaligned = 1; +#endif + + return NGX_OK; +} + + +static ngx_int_t +ngx_output_chain_get_buf(ngx_output_chain_ctx_t *ctx, off_t bsize) { - off_t size; - ssize_t n; + size_t size; + ngx_buf_t *b, *in; + ngx_uint_t recycled; + + in = ctx->in->buf; + size = ctx->bufs.size; + recycled = 1; + + if (in->last_in_chain) { + + if (bsize < (off_t) size) { + + /* + * allocate a small temp buf for a small last buf + * or its small last part + */ + + size = (size_t) bsize; + recycled = 0; + + } else if (!ctx->directio + && ctx->bufs.num == 1 + && (bsize < (off_t) (size + size / 4))) + { + /* + * allocate a temp buf that equals to a last buf, + * if there is no directio, the last buf size is lesser + * than 1.25 of bufs.size and the temp buf is single + */ + + size = (size_t) bsize; + recycled = 0; + } + } + + b = ngx_calloc_buf(ctx->pool); + if (b == NULL) { + return NGX_ERROR; + } + + if (ctx->directio) { + + /* + * allocate block aligned to a disk sector size to enable + * userland buffer direct usage conjunctly with directio + */ + + b->start = ngx_pmemalign(ctx->pool, size, 512); + if (b->start == NULL) { + return NGX_ERROR; + } + + } else { + b->start = ngx_palloc(ctx->pool, size); + if (b->start == NULL) { + return NGX_ERROR; + } + } + + b->pos = b->start; + b->last = b->start; + b->end = b->last + size; + b->temporary = 1; + b->tag = ctx->tag; + b->recycled = recycled; + + ctx->buf = b; + ctx->allocated++; + + return NGX_OK; +} + + +static ngx_int_t +ngx_output_chain_copy_buf(ngx_output_chain_ctx_t *ctx) +{ + off_t size; + ssize_t n; + ngx_buf_t *src, *dst; + ngx_uint_t sendfile; + + src = ctx->in->buf; + dst = ctx->buf; size = ngx_buf_size(src); @@ -363,6 +456,8 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst size = dst->end - dst->pos; } + sendfile = ctx->sendfile & !ctx->directio; + #if (NGX_SENDFILE_LIMIT) if (src->in_file && src->file_pos >= NGX_SENDFILE_LIMIT) { @@ -400,8 +495,41 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst } } else { + +#if (NGX_HAVE_ALIGNED_DIRECTIO) + + if (ctx->unaligned) { + if (ngx_directio_off(src->file->fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, + ngx_directio_off_n " \"%s\" failed", + src->file->name.data); + } + } + +#endif + n = ngx_read_file(src->file, dst->pos, (size_t) size, src->file_pos); +#if (NGX_HAVE_ALIGNED_DIRECTIO) + + if (ctx->unaligned) { + ngx_err_t err; + + err = ngx_errno; + + if (ngx_directio_on(src->file->fd) == -1) { + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, ngx_errno, + ngx_directio_on_n " \"%s\" failed", + src->file->name.data); + } + + ngx_set_errno(err); + + ctx->unaligned = 0; + } + +#endif + if (n == NGX_ERROR) { return (ngx_int_t) n; } @@ -413,9 +541,9 @@ ngx_output_chain_copy_buf(ngx_buf_t *dst #endif if (n != size) { - ngx_log_error(NGX_LOG_ALERT, src->file->log, 0, - ngx_read_file_n " read only %z of %O from file", - n, size); + ngx_log_error(NGX_LOG_ALERT, ctx->pool->log, 0, + ngx_read_file_n " read only %z of %O from \"%s\"", + n, size, src->file->name.data); if (n == 0) { return NGX_ERROR; } diff --git a/src/core/ngx_radix_tree.c b/src/core/ngx_radix_tree.c --- a/src/core/ngx_radix_tree.c +++ b/src/core/ngx_radix_tree.c @@ -274,7 +274,7 @@ ngx_radix_alloc(ngx_radix_tree_t *tree) } if (tree->size < sizeof(ngx_radix_node_t)) { - tree->start = ngx_palloc(tree->pool, ngx_pagesize); + tree->start = ngx_pmemalign(tree->pool, ngx_pagesize, ngx_pagesize); if (tree->start == NULL) { return NULL; } 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 @@ -54,8 +54,24 @@ void ngx_strlow(u_char *dst, u_char *src #define ngx_strstr(s1, s2) strstr((const char *) s1, (const char *) s2) +#define ngx_strlen(s) strlen((const char *) s) + #define ngx_strchr(s1, c) strchr((const char *) s1, (int) c) -#define ngx_strlen(s) strlen((const char *) s) + +static ngx_inline u_char * +ngx_strlchr(u_char *p, u_char *last, u_char c) +{ + while (p < last) { + + if (*p == c) { + return p; + } + + p++; + } + + return NULL; +} /* diff --git a/src/core/ngx_times.c b/src/core/ngx_times.c --- a/src/core/ngx_times.c +++ b/src/core/ngx_times.c @@ -50,10 +50,6 @@ ngx_time_init(void) ngx_cached_time = &cached_time[0]; -#if !(NGX_WIN32) - tzset(); -#endif - ngx_time_update(0, 0); } diff --git a/src/event/ngx_event.c b/src/event/ngx_event.c --- a/src/event/ngx_event.c +++ b/src/event/ngx_event.c @@ -1051,13 +1051,6 @@ ngx_event_debug_connection(ngx_conf_t *c return NGX_CONF_ERROR; } - dc->addr = inet_addr((char *) value[1].data); - - if (dc->addr != INADDR_NONE) { - dc->mask = 0xffffffff; - return NGX_CONF_OK; - } - rc = ngx_ptocidr(&value[1], &in_cidr); if (rc == NGX_DONE) { 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 @@ -207,8 +207,7 @@ ngx_event_accept(ngx_event_t *ev) return; } - c->addr_text.len = ngx_sock_ntop(ls->family, c->sockaddr, - c->addr_text.data, + c->addr_text.len = ngx_sock_ntop(c->sockaddr, c->addr_text.data, ls->addr_text_max_len); if (c->addr_text.len == 0) { ngx_close_accepted_connection(c); diff --git a/src/http/modules/ngx_http_access_module.c b/src/http/modules/ngx_http_access_module.c --- a/src/http/modules/ngx_http_access_module.c +++ b/src/http/modules/ngx_http_access_module.c @@ -166,14 +166,6 @@ ngx_http_access_rule(ngx_conf_t *cf, ngx return NGX_CONF_OK; } - rule->addr = inet_addr((char *) value[1].data); - - if (rule->addr != INADDR_NONE) { - rule->mask = 0xffffffff; - - return NGX_CONF_OK; - } - rc = ngx_ptocidr(&value[1], &in_cidr); if (rc == NGX_ERROR) { diff --git a/src/http/modules/ngx_http_fastcgi_module.c b/src/http/modules/ngx_http_fastcgi_module.c --- a/src/http/modules/ngx_http_fastcgi_module.c +++ b/src/http/modules/ngx_http_fastcgi_module.c @@ -7,7 +7,6 @@ #include #include #include -#include typedef struct { @@ -1170,7 +1169,7 @@ ngx_http_fastcgi_process_header(ngx_http u->headers_in.status_line.len = sizeof("302 Moved Temporarily") - 1; u->headers_in.status_line.data = - (u_char *) "302 Moved Temporarily"; + (u_char *) "302 Moved Temporarily"; } else { u->headers_in.status_n = 200; diff --git a/src/http/modules/ngx_http_flv_module.c b/src/http/modules/ngx_http_flv_module.c --- a/src/http/modules/ngx_http_flv_module.c +++ b/src/http/modules/ngx_http_flv_module.c @@ -244,6 +244,7 @@ ngx_http_flv_handler(ngx_http_request_t b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out[1].buf = b; out[1].next = NULL; diff --git a/src/http/modules/ngx_http_gzip_static_module.c b/src/http/modules/ngx_http_gzip_static_module.c --- a/src/http/modules/ngx_http_gzip_static_module.c +++ b/src/http/modules/ngx_http_gzip_static_module.c @@ -235,6 +235,7 @@ ngx_http_gzip_static_handler(ngx_http_re b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out.buf = b; out.next = NULL; diff --git a/src/http/modules/ngx_http_log_module.c b/src/http/modules/ngx_http_log_module.c --- a/src/http/modules/ngx_http_log_module.c +++ b/src/http/modules/ngx_http_log_module.c @@ -7,7 +7,6 @@ #include #include #include -#include typedef struct ngx_http_log_op_s ngx_http_log_op_t; @@ -431,6 +430,7 @@ ngx_http_log_script_write(ngx_http_reque of.log = 1; of.valid = llcf->open_file_cache_valid; of.min_uses = llcf->open_file_cache_min_uses; + of.directio = NGX_MAX_OFF_T_VALUE; if (ngx_open_cached_file(llcf->open_file_cache, &log, &of, r->pool) != NGX_OK) diff --git a/src/http/modules/ngx_http_memcached_module.c b/src/http/modules/ngx_http_memcached_module.c --- a/src/http/modules/ngx_http_memcached_module.c +++ b/src/http/modules/ngx_http_memcached_module.c @@ -6,7 +6,6 @@ #include #include -#include #include 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 @@ -6,7 +6,6 @@ #include #include -#include #include @@ -2546,7 +2545,7 @@ static ngx_int_t ngx_http_proxy_set_vars(ngx_pool_t *pool, ngx_url_t *u, ngx_http_proxy_vars_t *v) { - if (!u->unix_socket) { + if (u->family != AF_UNIX) { if (u->no_port || u->port == u->default_port) { v->host_header = u->host; diff --git a/src/http/modules/ngx_http_random_index_module.c b/src/http/modules/ngx_http_random_index_module.c new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_random_index_module.c @@ -0,0 +1,321 @@ + +/* + * Copyright (C) Igor Sysoev + */ + + +#include +#include +#include + + +typedef struct { + ngx_flag_t enable; +} ngx_http_random_index_loc_conf_t; + + +#define NGX_HTTP_RANDOM_INDEX_PREALLOCATE 50 + + +static ngx_int_t ngx_http_random_index_error(ngx_http_request_t *r, + ngx_dir_t *dir, ngx_str_t *name); +static ngx_int_t ngx_http_random_index_init(ngx_conf_t *cf); +static void *ngx_http_random_index_create_loc_conf(ngx_conf_t *cf); +static char *ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, + void *parent, void *child); + + +static ngx_command_t ngx_http_random_index_commands[] = { + + { ngx_string("random_index"), + NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_flag_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_random_index_loc_conf_t, enable), + NULL }, + + ngx_null_command +}; + + +static ngx_http_module_t ngx_http_random_index_module_ctx = { + NULL, /* preconfiguration */ + ngx_http_random_index_init, /* postconfiguration */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_random_index_create_loc_conf, /* create location configration */ + ngx_http_random_index_merge_loc_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_random_index_module = { + NGX_MODULE_V1, + &ngx_http_random_index_module_ctx, /* module context */ + ngx_http_random_index_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + NULL, /* init master */ + NULL, /* init module */ + NULL, /* init process */ + NULL, /* init thread */ + NULL, /* exit thread */ + NULL, /* exit process */ + NULL, /* exit master */ + NGX_MODULE_V1_PADDING +}; + + +static ngx_int_t +ngx_http_random_index_handler(ngx_http_request_t *r) +{ + u_char *last, *filename; + size_t len, allocated, root; + ngx_err_t err; + ngx_int_t rc; + ngx_str_t path, uri, *name; + ngx_dir_t dir; + ngx_uint_t n, level; + ngx_array_t names; + ngx_http_random_index_loc_conf_t *rlcf; + + if (r->uri.data[r->uri.len - 1] != '/') { + return NGX_DECLINED; + } + + /* TODO: Win32 */ + if (r->zero_in_uri) { + return NGX_DECLINED; + } + + if (!(r->method & (NGX_HTTP_GET|NGX_HTTP_HEAD|NGX_HTTP_POST))) { + return NGX_DECLINED; + } + + rlcf = ngx_http_get_module_loc_conf(r, ngx_http_random_index_module); + + if (!rlcf->enable) { + return NGX_DECLINED; + } + +#if (NGX_HAVE_D_TYPE) + len = NGX_DIR_MASK_LEN; +#else + len = NGX_HTTP_RANDOM_INDEX_PREALLOCATE; +#endif + + last = ngx_http_map_uri_to_path(r, &path, &root, len); + if (last == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + allocated = path.len; + + path.len = last - path.data - 1; + path.data[path.len] = '\0'; + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http random index: \"%s\"", path.data); + + if (ngx_open_dir(&path, &dir) == NGX_ERROR) { + err = ngx_errno; + + if (err == NGX_ENOENT + || err == NGX_ENOTDIR + || err == NGX_ENAMETOOLONG) + { + level = NGX_LOG_ERR; + rc = NGX_HTTP_NOT_FOUND; + + } else if (err == NGX_EACCES) { + level = NGX_LOG_ERR; + rc = NGX_HTTP_FORBIDDEN; + + } else { + level = NGX_LOG_CRIT; + rc = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + ngx_log_error(level, r->connection->log, err, + ngx_open_dir_n " \"%s\" failed", path.data); + + return rc; + } + + if (ngx_array_init(&names, r->pool, 32, sizeof(ngx_str_t)) != NGX_OK) { + return ngx_http_random_index_error(r, &dir, &path); + } + + filename = path.data; + filename[path.len] = '/'; + + for ( ;; ) { + ngx_set_errno(0); + + if (ngx_read_dir(&dir) == NGX_ERROR) { + err = ngx_errno; + + if (err != NGX_ENOMOREFILES) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_read_dir_n " \"%V\" failed", &path); + return ngx_http_random_index_error(r, &dir, &path); + } + + break; + } + + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "http random index file: \"%s\"", ngx_de_name(&dir)); + + if (ngx_de_name(&dir)[0] == '.') { + continue; + } + + len = ngx_de_namelen(&dir); + + if (!dir.valid_type) { + + /* 1 byte for '/' and 1 byte for terminating '\0' */ + + if (path.len + 1 + len + 1 > allocated) { + allocated = path.len + 1 + len + 1 + + NGX_HTTP_RANDOM_INDEX_PREALLOCATE; + + filename = ngx_pnalloc(r->pool, allocated); + if (filename == NULL) { + return ngx_http_random_index_error(r, &dir, &path); + } + + last = ngx_cpystrn(filename, path.data, path.len + 1); + *last++ = '/'; + } + + ngx_cpystrn(last, ngx_de_name(&dir), len + 1); + + if (ngx_de_info(filename, &dir) == NGX_FILE_ERROR) { + err = ngx_errno; + + if (err != NGX_ENOENT) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, err, + ngx_de_info_n " \"%s\" failed", filename); + return ngx_http_random_index_error(r, &dir, &path); + } + + if (ngx_de_link_info(filename, &dir) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_CRIT, r->connection->log, ngx_errno, + ngx_de_link_info_n " \"%s\" failed", + filename); + return ngx_http_random_index_error(r, &dir, &path); + } + } + } + + if (!ngx_de_is_file(&dir)) { + continue; + } + + name = ngx_array_push(&names); + if (name == NULL) { + return ngx_http_random_index_error(r, &dir, &path); + } + + name->len = len; + + name->data = ngx_pnalloc(r->pool, len); + if (name->data == NULL) { + return ngx_http_random_index_error(r, &dir, &path); + } + + ngx_memcpy(name->data, ngx_de_name(&dir), len); + } + + if (ngx_close_dir(&dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%s\" failed", &path); + } + + n = names.nelts; + + if (n == 0) { + return NGX_DECLINED; + } + + name = names.elts; + + n = (ngx_uint_t) (((uint64_t) ngx_random() * n) / 0x80000000); + + uri.len = r->uri.len + name[n].len; + + uri.data = ngx_pnalloc(r->pool, uri.len); + if (uri.data == NULL) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + last = ngx_copy(uri.data, r->uri.data, r->uri.len); + ngx_memcpy(last, name[n].data, name[n].len); + + return ngx_http_internal_redirect(r, &uri, &r->args); +} + + +static ngx_int_t +ngx_http_random_index_error(ngx_http_request_t *r, ngx_dir_t *dir, + ngx_str_t *name) +{ + if (ngx_close_dir(dir) == NGX_ERROR) { + ngx_log_error(NGX_LOG_ALERT, r->connection->log, ngx_errno, + ngx_close_dir_n " \"%V\" failed", name); + } + + return NGX_HTTP_INTERNAL_SERVER_ERROR; +} + + +static void * +ngx_http_random_index_create_loc_conf(ngx_conf_t *cf) +{ + ngx_http_random_index_loc_conf_t *conf; + + conf = ngx_palloc(cf->pool, sizeof(ngx_http_random_index_loc_conf_t)); + if (conf == NULL) { + return NGX_CONF_ERROR; + } + + conf->enable = NGX_CONF_UNSET; + + return conf; +} + + +static char * +ngx_http_random_index_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) +{ + ngx_http_random_index_loc_conf_t *prev = parent; + ngx_http_random_index_loc_conf_t *conf = child; + + ngx_conf_merge_value(conf->enable, prev->enable, 0); + + return NGX_CONF_OK; +} + + +static ngx_int_t +ngx_http_random_index_init(ngx_conf_t *cf) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); + + h = ngx_array_push(&cmcf->phases[NGX_HTTP_CONTENT_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_random_index_handler; + + return NGX_OK; +} diff --git a/src/http/modules/ngx_http_realip_module.c b/src/http/modules/ngx_http_realip_module.c --- a/src/http/modules/ngx_http_realip_module.c +++ b/src/http/modules/ngx_http_realip_module.c @@ -251,14 +251,6 @@ ngx_http_realip_from(ngx_conf_t *cf, ngx value = cf->args->elts; - from->addr = inet_addr((char *) value[1].data); - - if (from->addr != INADDR_NONE) { - from->mask = 0xffffffff; - - return NGX_CONF_OK; - } - rc = ngx_ptocidr(&value[1], &in_cidr); if (rc == NGX_ERROR) { diff --git a/src/http/modules/ngx_http_ssl_module.c b/src/http/modules/ngx_http_ssl_module.c --- a/src/http/modules/ngx_http_ssl_module.c +++ b/src/http/modules/ngx_http_ssl_module.c @@ -13,8 +13,6 @@ typedef ngx_int_t (*ngx_ssl_variable_han ngx_pool_t *pool, ngx_str_t *s); -#define NGX_DEFAULT_CERTIFICATE "cert.pem" -#define NGX_DEFAULT_CERTIFICATE_KEY "cert.pem" #define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" @@ -28,6 +26,8 @@ static void *ngx_http_ssl_create_srv_con static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf, void *parent, void *child); +static char *ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -61,7 +61,7 @@ static ngx_command_t ngx_http_ssl_comma { ngx_string("ssl"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_http_ssl_enable, NGX_HTTP_SRV_CONF_OFFSET, offsetof(ngx_http_ssl_srv_conf_t, enable), NULL }, @@ -339,10 +339,6 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_value(conf->enable, prev->enable, 0); - if (conf->enable == 0) { - return NGX_CONF_OK; - } - ngx_conf_merge_value(conf->session_timeout, prev->session_timeout, 300); @@ -356,11 +352,8 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * ngx_conf_merge_uint_value(conf->verify, prev->verify, 0); ngx_conf_merge_uint_value(conf->verify_depth, prev->verify_depth, 1); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFAULT_CERTIFICATE); - - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFAULT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); + ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); @@ -372,6 +365,38 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * conf->ssl.log = cf->log; + if (conf->enable) { + + if (conf->certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"ssl\" directive in %s:%ui", + conf->file, conf->line); + return NGX_CONF_ERROR; + } + + } else { + + if (conf->certificate.len == 0) { + return NGX_CONF_OK; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\"", &conf->certificate); + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_create(&conf->ssl, conf->protocols, conf) != NGX_OK) { return NGX_CONF_ERROR; } @@ -467,6 +492,26 @@ ngx_http_ssl_merge_srv_conf(ngx_conf_t * static char * +ngx_http_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_ssl_srv_conf_t *sscf = conf; + + char *rv; + + rv = ngx_conf_set_flag_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + sscf->file = cf->conf_file->file.name.data; + sscf->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +static char * ngx_http_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_ssl_srv_conf_t *sscf = conf; diff --git a/src/http/modules/ngx_http_ssl_module.h b/src/http/modules/ngx_http_ssl_module.h --- a/src/http/modules/ngx_http_ssl_module.h +++ b/src/http/modules/ngx_http_ssl_module.h @@ -37,6 +37,9 @@ typedef struct { ngx_str_t ciphers; ngx_shm_zone_t *shm_zone; + + u_char *file; + ngx_uint_t line; } ngx_http_ssl_srv_conf_t; diff --git a/src/http/modules/ngx_http_static_module.c b/src/http/modules/ngx_http_static_module.c --- a/src/http/modules/ngx_http_static_module.c +++ b/src/http/modules/ngx_http_static_module.c @@ -251,6 +251,7 @@ ngx_http_static_handler(ngx_http_request b->file->fd = of.fd; b->file->name = path; b->file->log = log; + b->file->directio = of.is_directio; out.buf = b; out.next = NULL; diff --git a/src/http/modules/ngx_http_xslt_filter_module.c b/src/http/modules/ngx_http_xslt_filter_module.c --- a/src/http/modules/ngx_http_xslt_filter_module.c +++ b/src/http/modules/ngx_http_xslt_filter_module.c @@ -136,6 +136,7 @@ static void *ngx_http_xslt_filter_create static char *ngx_http_xslt_filter_merge_conf(ngx_conf_t *cf, void *parent, void *child); static ngx_int_t ngx_http_xslt_filter_init(ngx_conf_t *cf); +static void ngx_http_xslt_filter_exit(ngx_cycle_t *cycle); ngx_str_t ngx_http_xslt_default_types[] = { @@ -196,8 +197,8 @@ ngx_module_t ngx_http_xslt_filter_modul NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ - NULL, /* exit process */ - NULL, /* exit master */ + ngx_http_xslt_filter_exit, /* exit process */ + ngx_http_xslt_filter_exit, /* exit master */ NGX_MODULE_V1_PADDING }; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.7.11'; +our $VERSION = '0.7.17'; require XSLoader; XSLoader::load('nginx', $VERSION); diff --git a/src/http/modules/perl/nginx.xs b/src/http/modules/perl/nginx.xs --- a/src/http/modules/perl/nginx.xs +++ b/src/http/modules/perl/nginx.xs @@ -681,6 +681,7 @@ sendfile(r, filename, offset = -1, bytes b->file->fd = of.fd; b->file->log = r->connection->log; + b->file->directio = of.is_directio; (void) ngx_http_perl_output(r, b); 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 @@ -6,7 +6,6 @@ #include #include -#include #include @@ -1158,6 +1157,10 @@ ngx_http_init_server_lists(ngx_conf_t *c in_addr[a].core_srv_conf = cscfp[s]; in_addr[a].default_server = 1; +#if (NGX_HTTP_SSL) + in_addr[a].ssl = listen[l].conf.ssl; +#endif + in_addr[a].listen_conf = &listen[l].conf; } goto found; @@ -1241,17 +1244,11 @@ ngx_http_add_address(ngx_conf_t *cf, ngx in_addr->core_srv_conf = cscf; in_addr->default_server = listen->conf.default_server; in_addr->bind = listen->conf.bind; +#if (NGX_HTTP_SSL) + in_addr->ssl = listen->conf.ssl; +#endif in_addr->listen_conf = &listen->conf; -#if (NGX_DEBUG) - { - u_char text[20]; - ngx_inet_ntop(AF_INET, &in_addr->addr, text, 20); - ngx_log_debug2(NGX_LOG_DEBUG_HTTP, cf->log, 0, "address: %s:%d", - text, in_port->port); - } -#endif - return ngx_http_add_names(cf, cscf, in_addr); } @@ -1656,6 +1653,10 @@ ngx_http_init_listening(ngx_conf_t *cf, hip->addrs[i].addr = in_addr[i].addr; hip->addrs[i].core_srv_conf = in_addr[i].core_srv_conf; +#if (NGX_HTTP_SSL) + hip->addrs[i].ssl = in_addr[i].ssl; +#endif + if (in_addr[i].hash.buckets == NULL && (in_addr[i].wc_head == NULL || in_addr[i].wc_head->hash.buckets == NULL) @@ -1787,11 +1788,11 @@ ngx_http_merge_types(ngx_conf_t *cf, ngx if (prev_keys == NULL) { - if (ngx_http_set_default_types(cf, &prev_keys, default_types) + if (ngx_http_set_default_types(cf, &prev_keys, default_types) != NGX_OK) { - return NGX_CONF_ERROR; - } + return NGX_CONF_ERROR; + } } hash.hash = prev_types_hash; 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 @@ -6,9 +6,7 @@ #include #include -#include #include -#include typedef struct { @@ -1625,8 +1623,8 @@ ngx_http_server_addr(ngx_http_request_t return NGX_OK; } - s->len = ngx_inet_ntop(c->listening->family, &r->in_addr, - s->data, INET_ADDRSTRLEN); + s->len = ngx_sock_ntop((struct sockaddr *) &sin, s->data, + NGX_INET_ADDRSTRLEN); return NGX_OK; } @@ -1672,6 +1670,10 @@ ngx_http_gzip_ok(ngx_http_request_t *r) clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + if (r->headers_in.msie6 && clcf->gzip_disable_msie6) { + return NGX_DECLINED; + } + if (r->http_version < clcf->gzip_http_version) { return NGX_DECLINED; } @@ -2677,6 +2679,7 @@ ngx_http_core_create_loc_conf(ngx_conf_t lcf->gzip_http_version = NGX_CONF_UNSET_UINT; #if (NGX_PCRE) lcf->gzip_disable = NGX_CONF_UNSET_PTR; + lcf->gzip_disable_msie6 = 3; #endif #endif @@ -2914,6 +2917,11 @@ ngx_http_core_merge_loc_conf(ngx_conf_t ngx_conf_merge_ptr_value(conf->gzip_disable, prev->gzip_disable, NULL); #endif + if (conf->gzip_disable_msie6 == 3) { + conf->gzip_disable_msie6 = + (prev->gzip_disable_msie6 == 3) ? 0 : prev->gzip_disable_msie6; + } + #endif return NGX_CONF_OK; @@ -2962,7 +2970,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ngx_memzero(ls, sizeof(ngx_http_listen_t)); - ls->family = AF_INET; + ls->family = u.family; ls->addr = u.addr.in_addr; ls->port = u.port; ls->file_name = cf->conf_file->file.name.data; @@ -2971,7 +2979,7 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx ls->conf.rcvbuf = -1; ls->conf.sndbuf = -1; - n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, INET_ADDRSTRLEN + 6); + n = ngx_inet_ntop(AF_INET, &ls->addr, ls->conf.addr, NGX_INET_ADDRSTRLEN); ngx_sprintf(&ls->conf.addr[n], ":%ui", ls->port); if (cf->args->nelts == 2) { @@ -3071,6 +3079,18 @@ ngx_http_core_listen(ngx_conf_t *cf, ngx continue; } + if (ngx_strcmp(value[n].data, "ssl") == 0) { +#if (NGX_HTTP_SSL) + ls->conf.ssl = 1; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl\" parameter requires " + "ngx_http_ssl_module"); + return NGX_CONF_ERROR; +#endif + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, "the invalid \"%V\" parameter", &value[n]); return NGX_CONF_ERROR; @@ -3094,17 +3114,24 @@ ngx_http_core_server_name(ngx_conf_t *cf ch = value[1].data[0]; - if (cscf->server_name.data == NULL && value[1].len) { - name = value[1]; - - if (ch == '.') { - name.len--; - name.data++; - } - - cscf->server_name.len = name.len; - cscf->server_name.data = ngx_pstrdup(cf->pool, &name); - if (cscf->server_name.data == NULL) { + if (cscf->server_name.data == NULL) { + if (value[1].len) { + name = value[1]; + + if (ch == '.') { + name.len--; + name.data++; + } + + cscf->server_name.len = name.len; + cscf->server_name.data = ngx_pstrdup(cf->pool, &name); + if (cscf->server_name.data == NULL) { + return NGX_CONF_ERROR; + } + + } else { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the first server name must not be empty"); return NGX_CONF_ERROR; } } @@ -3113,8 +3140,7 @@ ngx_http_core_server_name(ngx_conf_t *cf ch = value[i].data[0]; - if (value[i].len == 0 - || (ch == '*' && (value[i].len < 3 || value[i].data[1] != '.')) + if ((ch == '*' && (value[i].len < 3 || value[i].data[1] != '.')) || (ch == '.' && value[i].len < 2)) { ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, @@ -3747,8 +3773,9 @@ ngx_http_core_resolver(ngx_conf_t *cf, n static char * ngx_http_gzip_disable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { + ngx_http_core_loc_conf_t *clcf = conf; + #if (NGX_PCRE) - ngx_http_core_loc_conf_t *clcf = conf; ngx_str_t err, *value; ngx_uint_t i; @@ -3770,6 +3797,11 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng for (i = 1; i < cf->args->nelts; i++) { + if (ngx_strcmp(value[1].data, "msie6") == 0) { + clcf->gzip_disable_msie6 = 1; + continue; + } + re = ngx_array_push(clcf->gzip_disable); if (re == NULL) { return NGX_CONF_ERROR; @@ -3789,8 +3821,18 @@ ngx_http_gzip_disable(ngx_conf_t *cf, ng return NGX_CONF_OK; #else + ngx_str_t *value; + + value = cf->args->elts; + + if (cf->args->nelts == 2 && ngx_strcmp(value[1].data, "msie6") == 0) { + clcf->gzip_disable_msie6 = 1; + return NGX_CONF_OK; + } + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "\"gzip_disable\" requires PCRE library"); + "without PCRE library \"gzip_disable\" supports " + "builtin \"msie6\" mask only"); return NGX_CONF_ERROR; #endif 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 @@ -8,8 +8,8 @@ #define _NGX_HTTP_CORE_H_INCLUDED_ -#include -#include +#include +#include #include @@ -35,6 +35,9 @@ typedef struct ngx_http_core_loc_conf_s typedef struct { unsigned default_server:1; unsigned bind:1; +#if (NGX_HTTP_SSL) + unsigned ssl:1; +#endif int backlog; int rcvbuf; @@ -47,7 +50,7 @@ typedef struct { ngx_uint_t deferred_accept; #endif - u_char addr[INET_ADDRSTRLEN + 6]; + u_char addr[NGX_INET_ADDRSTRLEN + sizeof(":65535")]; } ngx_http_listen_conf_t; @@ -167,6 +170,10 @@ typedef struct { ngx_http_core_srv_conf_t *core_srv_conf; ngx_http_virtual_names_t *virtual_names; + +#if (NGX_HTTP_SSL) + ngx_uint_t ssl; /* unsigned ssl:1; */ +#endif } ngx_http_in_addr_t; @@ -203,6 +210,9 @@ typedef struct { unsigned default_server:1; unsigned bind:1; +#if (NGX_HTTP_SSL) + unsigned ssl:1; +#endif ngx_http_listen_conf_t *listen_conf; } ngx_http_conf_in_addr_t; @@ -242,6 +252,9 @@ struct ngx_http_core_loc_conf_s { unsigned auto_redirect:1; unsigned alias:1; +#if (NGX_HTTP_GZIP) + unsigned gzip_disable_msie6:2; +#endif ngx_http_location_tree_node_t *static_locations; ngx_http_core_loc_conf_t **regex_locations; 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 @@ -162,7 +162,7 @@ ngx_http_header_filter(ngx_http_request_ ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t *cscf; /* AF_INET only */ - u_char addr[INET_ADDRSTRLEN]; + u_char addr[NGX_INET_ADDRSTRLEN]; r->header_sent = 1; 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 @@ -720,7 +720,7 @@ ngx_http_parse_header_line(ngx_http_requ static u_char lowcase[] = "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0-\0\0" "0123456789\0\0\0\0\0\0" - "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" + "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0_" "\0abcdefghijklmnopqrstuvwxyz\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" "\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0" diff --git a/src/http/ngx_http_parse_time.c b/src/http/ngx_http_parse_time.c --- a/src/http/ngx_http_parse_time.c +++ b/src/http/ngx_http_parse_time.c @@ -6,7 +6,6 @@ #include #include -#include static int mday[] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 }; 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 @@ -6,7 +6,6 @@ #include #include -#include #include @@ -74,15 +73,18 @@ static char *ngx_http_client_errors[] = ngx_http_header_t ngx_http_headers_in[] = { - { ngx_string("Host"), 0, ngx_http_process_host }, - - { ngx_string("Connection"), 0, ngx_http_process_connection }, + { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), + ngx_http_process_host }, + + { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), + ngx_http_process_connection }, { ngx_string("If-Modified-Since"), offsetof(ngx_http_headers_in_t, if_modified_since), ngx_http_process_unique_header_line }, - { ngx_string("User-Agent"), 0, ngx_http_process_user_agent }, + { ngx_string("User-Agent"), offsetof(ngx_http_headers_in_t, user_agent), + ngx_http_process_user_agent }, { ngx_string("Referer"), offsetof(ngx_http_headers_in_t, referer), ngx_http_process_header_line }, @@ -354,9 +356,20 @@ ngx_http_init_request(ngx_event_t *rev) ngx_http_ssl_srv_conf_t *sscf; sscf = ngx_http_get_module_srv_conf(r, ngx_http_ssl_module); - if (sscf->enable) { + if (sscf->enable || hia[i].ssl) { if (c->ssl == NULL) { + + c->log->action = "SSL handshaking"; + + if (hia[i].ssl && sscf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + ngx_http_close_connection(c); + return; + } + if (ngx_ssl_create_connection(&sscf->ssl, c, NGX_SSL_BUFFER) == NGX_ERROR) { @@ -526,6 +539,8 @@ ngx_http_ssl_handshake(ngx_event_t *rev) } } + c->log->action = "reading client request line"; + rev->handler = ngx_http_process_request_line; ngx_http_process_request_line(rev); } @@ -568,6 +583,7 @@ ngx_http_ssl_handshake_handler(ngx_conne int ngx_http_ssl_servername(ngx_ssl_conn_t *ssl_conn, int *ad, void *arg) { + size_t len; const char *servername; ngx_connection_t *c; ngx_http_request_t *r; @@ -584,12 +600,15 @@ ngx_http_ssl_servername(ngx_ssl_conn_t * ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "SSL server name: \"%s\"", servername); + len = ngx_strlen(servername); + + if (len == 0) { + return SSL_TLSEXT_ERR_NOACK; + } + r = c->data; - if (ngx_http_find_virtual_server(r, (u_char *) servername, - ngx_strlen(servername)) - != NGX_OK) - { + if (ngx_http_find_virtual_server(r, (u_char *) servername, len) != NGX_OK) { return SSL_TLSEXT_ERR_NOACK; } @@ -1283,7 +1302,7 @@ static ngx_int_t ngx_http_process_user_agent(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { - u_char *ua, *user_agent; + u_char *user_agent, *msie; if (r->headers_in.user_agent) { return NGX_OK; @@ -1295,14 +1314,22 @@ ngx_http_process_user_agent(ngx_http_req user_agent = h->value.data; - ua = ngx_strstrn(user_agent, "MSIE", 4 - 1); - - if (ua && ua + 8 < user_agent + h->value.len) { + msie = ngx_strstrn(user_agent, "MSIE ", 5 - 1); + + if (msie && msie + 7 < user_agent + h->value.len) { r->headers_in.msie = 1; - if (ua[4] == ' ' && ua[5] == '4' && ua[6] == '.') { - r->headers_in.msie4 = 1; + if (msie[6] == '.') { + + switch (msie[5]) { + case '4': + r->headers_in.msie4 = 1; + /* fall through */ + case '5': + case '6': + r->headers_in.msie6 = 1; + } } #if 0 @@ -1317,6 +1344,7 @@ ngx_http_process_user_agent(ngx_http_req r->headers_in.opera = 1; r->headers_in.msie = 0; r->headers_in.msie4 = 0; + r->headers_in.msie6 = 0; } if (!r->headers_in.msie && !r->headers_in.opera) { @@ -1556,7 +1584,7 @@ ngx_http_find_virtual_server(ngx_http_re ngx_http_core_srv_conf_t *cscf; u_char buf[32]; - if (len == 0 || r->virtual_names == NULL) { + if (r->virtual_names == NULL) { return NGX_DECLINED; } @@ -1723,6 +1751,9 @@ ngx_http_finalize_request(ngx_http_reque } } + c->read->handler = ngx_http_request_handler; + c->write->handler = ngx_http_request_handler; + ngx_http_finalize_request(r, ngx_http_special_response_handler(r, rc)); return; } diff --git a/src/http/ngx_http_request.h b/src/http/ngx_http_request.h --- a/src/http/ngx_http_request.h +++ b/src/http/ngx_http_request.h @@ -214,6 +214,7 @@ typedef struct { unsigned connection_type:2; unsigned msie:1; unsigned msie4:1; + unsigned msie6:1; unsigned opera:1; unsigned gecko:1; unsigned konqueror:1; diff --git a/src/http/ngx_http_request_body.c b/src/http/ngx_http_request_body.c --- a/src/http/ngx_http_request_body.c +++ b/src/http/ngx_http_request_body.c @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/http/ngx_http_script.c b/src/http/ngx_http_script.c --- a/src/http/ngx_http_script.c +++ b/src/http/ngx_http_script.c @@ -574,6 +574,7 @@ ngx_http_script_start_args_code(ngx_http ngx_log_debug0(NGX_LOG_DEBUG_HTTP, e->request->connection->log, 0, "http script args"); + e->is_args = 1; e->args = e->pos; e->ip += sizeof(uintptr_t); } 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 @@ -327,7 +327,6 @@ static ngx_str_t ngx_http_get_name = { ngx_int_t ngx_http_special_response_handler(ngx_http_request_t *r, ngx_int_t error) { - ngx_int_t rc; ngx_uint_t i, err; ngx_http_err_page_t *err_page; ngx_http_core_loc_conf_t *clcf; @@ -336,12 +335,6 @@ ngx_http_special_response_handler(ngx_ht "http special response: %d, \"%V?%V\"", error, &r->uri, &r->args); - rc = ngx_http_discard_request_body(r); - - if (rc == NGX_HTTP_INTERNAL_SERVER_ERROR) { - error = NGX_HTTP_INTERNAL_SERVER_ERROR; - } - r->err_status = error; if (r->keepalive) { @@ -386,6 +379,10 @@ ngx_http_special_response_handler(ngx_ht } } + if (ngx_http_discard_request_body(r) != NGX_OK) { + error = NGX_HTTP_INTERNAL_SERVER_ERROR; + } + if (clcf->msie_refresh && r->headers_in.msie && (error == NGX_HTTP_MOVED_PERMANENTLY @@ -493,8 +490,10 @@ ngx_http_send_error_page(ngx_http_reques if (uri->data[0] == '/') { - r->method = NGX_HTTP_GET; - r->method_name = ngx_http_get_name; + if (r->method != NGX_HTTP_HEAD) { + r->method = NGX_HTTP_GET; + r->method_name = ngx_http_get_name; + } return ngx_http_internal_redirect(r, uri, args); } diff --git a/src/http/ngx_http_upstream.c b/src/http/ngx_http_upstream.c --- a/src/http/ngx_http_upstream.c +++ b/src/http/ngx_http_upstream.c @@ -2632,7 +2632,17 @@ ngx_http_upstream_copy_content_type(ngx_ r->headers_out.content_type_len = last - h->value.data; - r->headers_out.charset.len = h->value.data + h->value.len - p; + if (*p == '"') { + p++; + } + + last = h->value.data + h->value.len; + + if (*(last - 1) == '"') { + last--; + } + + r->headers_out.charset.len = last - p; r->headers_out.charset.data = p; return NGX_OK; diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c --- a/src/http/ngx_http_upstream_round_robin.c +++ b/src/http/ngx_http_upstream_round_robin.c @@ -281,14 +281,14 @@ ngx_http_upstream_create_round_robin_pee for (i = 0; i < ur->naddrs; i++) { - len = INET_ADDRSTRLEN - 1 + 1 + sizeof(":65536") - 1; + len = NGX_INET_ADDRSTRLEN + sizeof(":65536") - 1; p = ngx_pnalloc(r->pool, len); if (p == NULL) { return NGX_ERROR; } - len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, INET_ADDRSTRLEN); + len = ngx_inet_ntop(AF_INET, &ur->addrs[i], p, NGX_INET_ADDRSTRLEN); len = ngx_sprintf(&p[len], ":%d", ur->port) - p; sin = ngx_pcalloc(r->pool, sizeof(struct sockaddr_in)); @@ -645,7 +645,9 @@ ngx_http_upstream_free_round_robin_peer( peer->fails++; peer->accessed = now; - peer->current_weight -= peer->weight / peer->max_fails; + if (peer->max_fails) { + peer->current_weight -= peer->weight / peer->max_fails; + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, pc->log, 0, "free rr peer failed: %ui %i", 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 @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -79,6 +78,8 @@ static ngx_int_t ngx_http_variable_nginx ngx_http_variable_value_t *v, uintptr_t data); static ngx_int_t ngx_http_variable_hostname(ngx_http_request_t *r, ngx_http_variable_value_t *v, uintptr_t data); +static ngx_int_t ngx_http_variable_pid(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data); /* * TODO: @@ -228,6 +229,9 @@ static ngx_http_variable_t ngx_http_cor { ngx_string("hostname"), NULL, ngx_http_variable_hostname, 0, 0, 0 }, + { ngx_string("pid"), NULL, ngx_http_variable_pid, + 0, 0, 0 }, + { ngx_null_string, NULL, NULL, 0, 0, 0 } }; @@ -872,7 +876,7 @@ ngx_http_variable_server_addr(ngx_http_r { ngx_str_t s; - s.data = ngx_pnalloc(r->pool, INET_ADDRSTRLEN); + s.data = ngx_pnalloc(r->pool, NGX_INET_ADDRSTRLEN); if (s.data == NULL) { return NGX_ERROR; } @@ -1354,6 +1358,27 @@ ngx_http_variable_hostname(ngx_http_requ } +static ngx_int_t +ngx_http_variable_pid(ngx_http_request_t *r, + ngx_http_variable_value_t *v, uintptr_t data) +{ + u_char *p; + + p = ngx_pnalloc(r->pool, NGX_INT64_LEN); + if (p == NULL) { + return NGX_ERROR; + } + + v->len = ngx_sprintf(p, "%P", ngx_pid) - p; + v->valid = 1; + v->no_cacheable = 0; + v->not_found = 0; + v->data = p; + + return NGX_OK; +} + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf) { diff --git a/src/http/ngx_http_variables.h b/src/http/ngx_http_variables.h --- a/src/http/ngx_http_variables.h +++ b/src/http/ngx_http_variables.h @@ -10,7 +10,6 @@ #include #include -#include #include diff --git a/src/http/ngx_http_write_filter_module.c b/src/http/ngx_http_write_filter_module.c --- a/src/http/ngx_http_write_filter_module.c +++ b/src/http/ngx_http_write_filter_module.c @@ -6,7 +6,6 @@ #include #include -#include #include diff --git a/src/mail/ngx_mail.c b/src/mail/ngx_mail.c --- a/src/mail/ngx_mail.c +++ b/src/mail/ngx_mail.c @@ -261,6 +261,9 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma in_addr->addr = imls[l].addr; in_addr->ctx = imls[l].ctx; in_addr->bind = imls[l].bind; +#if (NGX_MAIL_SSL) + in_addr->ssl = imls[l].ssl; +#endif } /* optimize the lists of ports and addresses */ @@ -358,18 +361,22 @@ ngx_mail_block(ngx_conf_t *cf, ngx_comma imip->addrs[i].ctx = in_addr[i].ctx; text = ngx_pnalloc(cf->pool, - INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); + NGX_INET_ADDRSTRLEN + sizeof(":65535") - 1); if (text == NULL) { return NGX_CONF_ERROR; } len = ngx_inet_ntop(AF_INET, &in_addr[i].addr, text, - INET_ADDRSTRLEN); + NGX_INET_ADDRSTRLEN); len = ngx_sprintf(text + len, ":%d", in_port[p].port) - text; imip->addrs[i].addr_text.len = len; imip->addrs[i].addr_text.data = text; + +#if (NGX_MAIL_SSL) + imip->addrs[i].ssl = in_addr[i].ssl; +#endif } if (done) { diff --git a/src/mail/ngx_mail.h b/src/mail/ngx_mail.h --- a/src/mail/ngx_mail.h +++ b/src/mail/ngx_mail.h @@ -34,6 +34,9 @@ typedef struct { ngx_mail_conf_ctx_t *ctx; unsigned bind:1; +#if (NGX_MAIL_SSL) + unsigned ssl:1; +#endif } ngx_mail_listen_t; @@ -41,6 +44,9 @@ typedef struct { in_addr_t addr; ngx_mail_conf_ctx_t *ctx; ngx_str_t addr_text; +#if (NGX_MAIL_SSL) + ngx_uint_t ssl; /* unsigned ssl:1; */ +#endif } ngx_mail_in_addr_t; @@ -60,6 +66,9 @@ typedef struct { in_addr_t addr; ngx_mail_conf_ctx_t *ctx; unsigned bind:1; +#if (NGX_MAIL_SSL) + unsigned ssl:1; +#endif } ngx_mail_conf_in_addr_t; diff --git a/src/mail/ngx_mail_core_module.c b/src/mail/ngx_mail_core_module.c --- a/src/mail/ngx_mail_core_module.c +++ b/src/mail/ngx_mail_core_module.c @@ -329,7 +329,7 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx imls->addr = u.addr.in_addr; imls->port = u.port; - imls->family = AF_INET; + imls->family = u.family; imls->ctx = cf->ctx; for (m = 0; ngx_modules[m]; m++) { @@ -351,18 +351,31 @@ ngx_mail_core_listen(ngx_conf_t *cf, ngx } } - if (cf->args->nelts == 2) { - return NGX_CONF_OK; + for (i = 2; i < cf->args->nelts; i++) { + + if (ngx_strcmp(value[i].data, "bind") == 0) { + imls->bind = 1; + continue; + } + + if (ngx_strcmp(value[i].data, "ssl") == 0) { +#if (NGX_MAIL_SSL) + imls->ssl = 1; + continue; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the \"ssl\" parameter requires " + "ngx_mail_ssl_module"); + return NGX_CONF_ERROR; +#endif + } + + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the invalid \"%V\" parameter", &value[i]); + return NGX_CONF_ERROR; } - if (ngx_strcmp(value[2].data, "bind") == 0) { - imls->bind = 1; - return NGX_CONF_OK; - } - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "the invalid \"%V\" parameter", &value[2]); - return NGX_CONF_ERROR; + return NGX_CONF_OK; } diff --git a/src/mail/ngx_mail_handler.c b/src/mail/ngx_mail_handler.c --- a/src/mail/ngx_mail_handler.c +++ b/src/mail/ngx_mail_handler.c @@ -118,9 +118,28 @@ ngx_mail_init_connection(ngx_connection_ sslcf = ngx_mail_get_module_srv_conf(s, ngx_mail_ssl_module); if (sslcf->enable) { + c->log->action = "SSL handshaking"; + ngx_mail_ssl_init_connection(&sslcf->ssl, c); return; } + + if (imia[i].ssl) { + + c->log->action = "SSL handshaking"; + + if (sslcf->ssl.ctx == NULL) { + ngx_log_error(NGX_LOG_ERR, c->log, 0, + "no \"ssl_certificate\" is defined " + "in server listening on SSL port"); + ngx_mail_close_connection(c); + return; + } + + ngx_mail_ssl_init_connection(&sslcf->ssl, c); + return; + } + } #endif diff --git a/src/mail/ngx_mail_ssl_module.c b/src/mail/ngx_mail_ssl_module.c --- a/src/mail/ngx_mail_ssl_module.c +++ b/src/mail/ngx_mail_ssl_module.c @@ -9,13 +9,16 @@ #include -#define NGX_DEFAULT_CERTIFICATE "cert.pem" -#define NGX_DEFAULT_CERTIFICATE_KEY "cert.pem" #define NGX_DEFAULT_CIPHERS "ALL:!ADH:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv2:+EXP" static void *ngx_mail_ssl_create_conf(ngx_conf_t *cf); static char *ngx_mail_ssl_merge_conf(ngx_conf_t *cf, void *parent, void *child); + +static char *ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); +static char *ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); @@ -50,14 +53,14 @@ static ngx_command_t ngx_mail_ssl_comma { ngx_string("ssl"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_FLAG, - ngx_conf_set_flag_slot, + ngx_mail_ssl_enable, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, enable), NULL }, { ngx_string("starttls"), NGX_MAIL_MAIN_CONF|NGX_MAIL_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_enum_slot, + ngx_mail_ssl_starttls, NGX_MAIL_SRV_CONF_OFFSET, offsetof(ngx_mail_ssl_conf_t, starttls), ngx_http_starttls_state }, @@ -194,14 +197,12 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, ngx_mail_ssl_conf_t *prev = parent; ngx_mail_ssl_conf_t *conf = child; + char *mode; ngx_pool_cleanup_t *cln; ngx_conf_merge_value(conf->enable, prev->enable, 0); - ngx_conf_merge_value(conf->starttls, prev->starttls, NGX_MAIL_STARTTLS_OFF); - - if (conf->enable == 0 && conf->starttls == NGX_MAIL_STARTTLS_OFF) { - return NGX_CONF_OK; - } + ngx_conf_merge_uint_value(conf->starttls, prev->starttls, + NGX_MAIL_STARTTLS_OFF); ngx_conf_merge_value(conf->session_timeout, prev->session_timeout, 300); @@ -213,11 +214,8 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, (NGX_CONF_BITMASK_SET |NGX_SSL_SSLv2|NGX_SSL_SSLv3|NGX_SSL_TLSv1)); - ngx_conf_merge_str_value(conf->certificate, prev->certificate, - NGX_DEFAULT_CERTIFICATE); - - ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, - NGX_DEFAULT_CERTIFICATE_KEY); + ngx_conf_merge_str_value(conf->certificate, prev->certificate, ""); + ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key, ""); ngx_conf_merge_str_value(conf->dhparam, prev->dhparam, ""); @@ -226,6 +224,49 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, conf->ssl.log = cf->log; + if (conf->enable) { + mode = "ssl"; + + } else if (conf->starttls != NGX_MAIL_STARTTLS_OFF) { + mode = "starttls"; + + } else { + mode = ""; + } + + if (*mode) { + + if (conf->certificate.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate\" is defined for " + "the \"%s\" directive in %s:%ui", + mode, conf->file, conf->line); + return NGX_CONF_ERROR; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined for " + "the \"%s\" directive in %s:%ui", + mode, conf->file, conf->line); + return NGX_CONF_ERROR; + } + + } else { + + if (conf->certificate.len == 0) { + return NGX_CONF_OK; + } + + if (conf->certificate_key.len == 0) { + ngx_log_error(NGX_LOG_EMERG, cf->log, 0, + "no \"ssl_certificate_key\" is defined " + "for certificate \"%V\"", + &conf->certificate); + return NGX_CONF_ERROR; + } + } + if (ngx_ssl_create(&conf->ssl, conf->protocols, NULL) != NGX_OK) { return NGX_CONF_ERROR; } @@ -292,6 +333,58 @@ ngx_mail_ssl_merge_conf(ngx_conf_t *cf, static char * +ngx_mail_ssl_enable(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *scf = conf; + + char *rv; + + rv = ngx_conf_set_flag_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + if (scf->enable && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"starttls\" directive conflicts with \"ssl on\""); + return NGX_CONF_ERROR; + } + + scf->file = cf->conf_file->file.name.data; + scf->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +static char * +ngx_mail_ssl_starttls(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_mail_ssl_conf_t *scf = conf; + + char *rv; + + rv = ngx_conf_set_enum_slot(cf, cmd, conf); + + if (rv != NGX_CONF_OK) { + return rv; + } + + if (scf->enable == 1 && (ngx_int_t) scf->starttls > NGX_MAIL_STARTTLS_OFF) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "\"ssl\" directive conflicts with \"starttls\""); + return NGX_CONF_ERROR; + } + + scf->file = cf->conf_file->file.name.data; + scf->line = cf->conf_file->line; + + return NGX_CONF_OK; +} + + +static char * ngx_mail_ssl_session_cache(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_mail_ssl_conf_t *scf = conf; diff --git a/src/mail/ngx_mail_ssl_module.h b/src/mail/ngx_mail_ssl_module.h --- a/src/mail/ngx_mail_ssl_module.h +++ b/src/mail/ngx_mail_ssl_module.h @@ -20,12 +20,11 @@ typedef struct { ngx_flag_t enable; + ngx_flag_t prefer_server_ciphers; ngx_ssl_t ssl; - ngx_flag_t prefer_server_ciphers; - ngx_flag_t starttls; - + ngx_uint_t starttls; ngx_uint_t protocols; ssize_t builtin_session_cache; @@ -39,6 +38,9 @@ typedef struct { ngx_str_t ciphers; ngx_shm_zone_t *shm_zone; + + u_char *file; + ngx_uint_t line; } ngx_mail_ssl_conf_t; diff --git a/src/os/unix/ngx_files.c b/src/os/unix/ngx_files.c --- a/src/os/unix/ngx_files.c +++ b/src/os/unix/ngx_files.c @@ -249,12 +249,33 @@ ngx_open_dir(ngx_str_t *name, ngx_dir_t } dir->valid_info = 0; +#if (NGX_HAVE_D_TYPE) + dir->valid_type = 1; +#else + dir->valid_type = 0; +#endif return NGX_OK; } ngx_int_t +ngx_read_dir(ngx_dir_t *dir) +{ + dir->de = readdir(dir->dir); + + if (dir->de) { +#if (NGX_HAVE_D_TYPE) + dir->type = dir->de->d_type; +#endif + return NGX_OK; + } + + return NGX_ERROR; +} + + +ngx_int_t ngx_open_glob(ngx_glob_t *gl) { int n; @@ -265,10 +286,14 @@ ngx_open_glob(ngx_glob_t *gl) return NGX_OK; } +#ifdef GLOB_NOMATCH + if (n == GLOB_NOMATCH && gl->test) { return NGX_OK; } +#endif + return NGX_ERROR; } @@ -276,7 +301,15 @@ ngx_open_glob(ngx_glob_t *gl) ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name) { - if (gl->n < (size_t) gl->pglob.gl_pathc) { + size_t count; + +#ifdef GLOB_NOMATCH + count = (size_t) gl->pglob.gl_pathc; +#else + count = (size_t) gl->pglob.gl_matchc; +#endif + + if (gl->n < count) { name->len = (size_t) ngx_strlen(gl->pglob.gl_pathv[gl->n]); name->data = (u_char *) gl->pglob.gl_pathv[gl->n]; @@ -356,7 +389,7 @@ ngx_unlock_fd(ngx_fd_t fd) #if (NGX_HAVE_O_DIRECT) ngx_int_t -ngx_directio(ngx_fd_t fd) +ngx_directio_on(ngx_fd_t fd) { int flags; @@ -369,4 +402,19 @@ ngx_directio(ngx_fd_t fd) return fcntl(fd, F_SETFL, flags | O_DIRECT); } + +ngx_int_t +ngx_directio_off(ngx_fd_t fd) +{ + int flags; + + flags = fcntl(fd, F_GETFL); + + if (flags == -1) { + return -1; + } + + return fcntl(fd, F_SETFL, flags & ~O_DIRECT); +} + #endif diff --git a/src/os/unix/ngx_files.h b/src/os/unix/ngx_files.h --- a/src/os/unix/ngx_files.h +++ b/src/os/unix/ngx_files.h @@ -12,6 +12,31 @@ #include +typedef int ngx_fd_t; +typedef struct stat ngx_file_info_t; +typedef ino_t ngx_file_uniq_t; + + +typedef struct { + DIR *dir; + struct dirent *de; + struct stat info; + + unsigned type:8; + unsigned valid_info:1; + unsigned valid_type:1; +} ngx_dir_t; + + +typedef struct { + size_t n; + glob_t pglob; + u_char *pattern; + ngx_log_t *log; + ngx_uint_t test; +} ngx_glob_t; + + #define NGX_INVALID_FILE -1 #define NGX_FILE_ERROR -1 @@ -135,8 +160,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_close_dir_n "closedir()" -#define ngx_read_dir(d) \ - (((d)->de = readdir((d)->dir)) ? NGX_OK : NGX_ERROR) +ngx_int_t ngx_read_dir(ngx_dir_t *dir); #define ngx_read_dir_n "readdir()" @@ -152,7 +176,7 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_de_name(dir) ((u_char *) (dir)->de->d_name) -#if (NGX_FREEBSD) +#if (NGX_HAVE_D_NAMLEN) #define ngx_de_namelen(dir) (dir)->de->d_namlen #else #define ngx_de_namelen(dir) ngx_strlen((dir)->de->d_name) @@ -161,23 +185,26 @@ ngx_int_t ngx_open_dir(ngx_str_t *name, #define ngx_de_info_n "stat()" #define ngx_de_link_info(name, dir) lstat((const char *) name, &(dir)->info) #define ngx_de_link_info_n "lstat()" + +#if (NGX_HAVE_D_TYPE) + +#define ngx_de_is_dir(dir) ((dir)->type == DT_DIR) +#define ngx_de_is_file(dir) ((dir)->type == DT_REG) +#define ngx_de_is_link(dir) ((dir)->type == DT_LINK) + +#else + #define ngx_de_is_dir(dir) (S_ISDIR((dir)->info.st_mode)) #define ngx_de_is_file(dir) (S_ISREG((dir)->info.st_mode)) #define ngx_de_is_link(dir) (S_ISLNK((dir)->info.st_mode)) + +#endif + #define ngx_de_access(dir) (((dir)->info.st_mode) & 0777) #define ngx_de_size(dir) (dir)->info.st_size #define ngx_de_mtime(dir) (dir)->info.st_mtime -typedef struct { - size_t n; - glob_t pglob; - u_char *pattern; - ngx_log_t *log; - ngx_uint_t test; -} ngx_glob_t; - - ngx_int_t ngx_open_glob(ngx_glob_t *gl); #define ngx_open_glob_n "glob()" ngx_int_t ngx_read_glob(ngx_glob_t *gl, ngx_str_t *name); @@ -195,23 +222,26 @@ ngx_err_t ngx_unlock_fd(ngx_fd_t fd); #if (NGX_HAVE_O_DIRECT) -ngx_int_t ngx_directio(ngx_fd_t fd); -#define ngx_directio_n "fcntl(O_DIRECT)" +ngx_int_t ngx_directio_on(ngx_fd_t fd); +#define ngx_directio_on_n "fcntl(O_DIRECT)" + +ngx_int_t ngx_directio_off(ngx_fd_t fd); +#define ngx_directio_off_n "fcntl(!O_DIRECT)" #elif (NGX_HAVE_F_NOCACHE) -#define ngx_directio(fd) fcntl(fd, F_NOCACHE, 1) -#define ngx_directio_n "fcntl(F_NOCACHE)" +#define ngx_directio_on(fd) fcntl(fd, F_NOCACHE, 1) +#define ngx_directio_on_n "fcntl(F_NOCACHE, 1)" #elif (NGX_HAVE_DIRECTIO) -#define ngx_directio(fd) directio(fd, DIRECTIO_ON) -#define ngx_directio_n "directio(DIRECTIO_ON)" +#define ngx_directio_on(fd) directio(fd, DIRECTIO_ON) +#define ngx_directio_on_n "directio(DIRECTIO_ON)" #else -#define ngx_directio(fd) 0 -#define ngx_directio_n "ngx_directio_n" +#define ngx_directio_on(fd) 0 +#define ngx_directio_on_n "ngx_directio_on_n" #endif diff --git a/src/os/unix/ngx_time.c b/src/os/unix/ngx_time.c --- a/src/os/unix/ngx_time.c +++ b/src/os/unix/ngx_time.c @@ -8,6 +8,50 @@ #include +/* + * FreeBSD does not test /etc/localtime change, however, we can workaround it + * by calling tzset() with TZ and then without TZ to update timezone. + * The trick should work since FreeBSD 2.1.0. + * + * Linux does not test /etc/localtime change in localtime(), + * but may stat("/etc/localtime") several times in every strftime(), + * therefore we use it to update timezone. + * + * Solaris does not test /etc/TIMEZONE change too and no workaround available. + */ + +void +ngx_timezone_update(void) +{ +#if (NGX_FREEBSD) + + if (getenv("TZ")) { + return; + } + + putenv("TZ=UTC"); + + tzset(); + + unsetenv("TZ"); + + tzset(); + +#elif (NGX_LINUX) + time_t s; + struct tm *t; + char buf[4]; + + s = time(0); + + t = localtime(&s); + + strftime(buf, 4, "%H", t); + +#endif +} + + void ngx_localtime(time_t s, ngx_tm_t *tm) { diff --git a/src/os/unix/ngx_time.h b/src/os/unix/ngx_time.h --- a/src/os/unix/ngx_time.h +++ b/src/os/unix/ngx_time.h @@ -52,6 +52,7 @@ typedef struct tm ngx_tm_t; #endif +void ngx_timezone_update(void); void ngx_localtime(time_t s, ngx_tm_t *tm); void ngx_libc_localtime(time_t s, struct tm *tm); void ngx_libc_gmtime(time_t s, struct tm *tm); diff --git a/src/os/unix/ngx_types.h b/src/os/unix/ngx_types.h deleted file mode 100644 --- a/src/os/unix/ngx_types.h +++ /dev/null @@ -1,27 +0,0 @@ - -/* - * Copyright (C) Igor Sysoev - */ - - -#ifndef _NGX_TYPES_H_INCLUDED_ -#define _NGX_TYPES_H_INCLUDED_ - - -#include - - -typedef int ngx_fd_t; -typedef struct stat ngx_file_info_t; -typedef ino_t ngx_file_uniq_t; - -typedef struct { - DIR *dir; - struct dirent *de; - struct stat info; - - ngx_uint_t valid_info:1; /* unsigned valid_info:1; */ -} ngx_dir_t; - - -#endif /* _NGX_TYPES_H_INCLUDED_ */