# HG changeset patch # User Igor Sysoev # Date 1118779200 -14400 # Node ID b31656313b59dd7f2e0f854c657dc500e03cfd0b # Parent 66f1f40f29d6f86d6ec04e139f79e8f957a1e212 nginx 0.1.36 *) Change: if the request header has duplicate the "Host", "Connection", "Content-Length", or "Authorization" lines, then nginx now returns the 400 error. *) Change: the "post_accept_timeout" directive was canceled. *) Feature: the "default", "af=", "bl=", "deferred", and "bind" parameters of the "listen" directive. *) Feature: the FreeBSD accept filters support. *) Feature: the Linux TCP_DEFER_ACCEPT support. *) Bugfix: the ngx_http_autoindex_module did not support the file names in UTF-8. *) Bugfix: the new log file can be rotated by the -USR1 signal only if the reconfiguration by the -HUP signal was made twice. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,3 +1,25 @@ + +Changes with nginx 0.1.36 15 Jun 2005 + + *) Change: if the request header has duplicate the "Host", + "Connection", "Content-Length", or "Authorization" lines, then nginx + now returns the 400 error. + + *) Change: The "post_accept_timeout" directive was canceled. + + *) Feature: the "default", "af=", "bl=", "deferred", and "bind" + parameters of the "listen" directive. + + *) Feature: the FreeBSD accept filters support. + + *) Feature: the Linux TCP_DEFER_ACCEPT support. + + *) Bugfix: the ngx_http_autoindex_module did not support the file names + in UTF-8. + + *) Bugfix: the new log file can be rotated by the -USR1 signal only if + the reconfiguration by the -HUP signal was made twice. + Changes with nginx 0.1.35 07 Jun 2005 diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,3 +1,26 @@ + +Изменения в nginx 0.1.36 15.06.2005 + + *) Изменение: если в заголовке запросе есть дублирующиеся строки + "Host", "Connection", "Content-Length" и "Authorization", то nginx + теперь выдаёт ошибку 400. + + *) Изменение: директива post_accept_timeout упразднена. + + *) Добавление: параметры default, af=, bl=, deferred и bind в директиве + listen. + + *) Добавление: поддержка accept фильтров во FreeBSD. + + *) Добавление: поддержка TCP_DEFER_ACCEPT в Linux. + + *) Исправление: модуль ngx_http_autoindex_module не поддерживал имена + файлов в UTF-8. + + *) Исправление: после добавления новый лог-файл ротация этого лога по + сигналу -USR1 выполнялась, только если переконфигурировать nginx два + раза по сигналу -HUP. + Изменения в nginx 0.1.35 07.06.2005 diff --git a/auto/cc/icc b/auto/cc/icc --- a/auto/cc/icc +++ b/auto/cc/icc @@ -97,7 +97,7 @@ case "$NGX_ICC_VER" in CFLAGS="$CFLAGS -wd1469" # STUB - # non-POD class type passed through ellipsis + # non-POD class type passed through ellipsis, Linux only ? CFLAGS="$CFLAGS -wd1595" ;; diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -23,11 +23,30 @@ if [ $PCRE != NONE ]; then LINK_DEPS="$LINK_DEPS $PCRE/.libs/libpcre.a" + echo $ngx_n "checking for PCRE library ...$ngx_c" + + ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \ + | sed -e 's/^.*=\(.*\)$/\1/'` + + echo " $ngx_pcre_ver major version found" + # to allow -ipo optimization we link with the *.o but not library - CORE_LIBS="$CORE_LIBS $PCRE/maketables.o" - CORE_LIBS="$CORE_LIBS $PCRE/get.o" - CORE_LIBS="$CORE_LIBS $PCRE/study.o" - CORE_LIBS="$CORE_LIBS $PCRE/pcre.o" + + case "$ngx_pcre_ver" in + 6) + CORE_LIBS="$CORE_LIBS $PCRE/pcre_chartables.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_compile.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_exec.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_fullinfo.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_globals.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_tables.o" + CORE_LIBS="$CORE_LIBS $PCRE/pcre_try_flipped.o" + ;; + + *) + CORE_LIBS="$CORE_LIBS $PCRE/pcre.o" + ;; + esac ;; *) diff --git a/auto/lib/pcre/make b/auto/lib/pcre/make --- a/auto/lib/pcre/make +++ b/auto/lib/pcre/make @@ -55,9 +55,7 @@ END $PCRE/pcre.h: $NGX_MAKEFILE cd $PCRE \\ - && if [ -f Makefile ]; then \$(MAKE) distclean; fi - - cd $PCRE \\ + && if [ -f Makefile ]; then \$(MAKE) distclean; fi \\ && CC="\$(CC)" CFLAGS="$PCRE_OPT" \\ ./configure --disable-shared diff --git a/conf/nginx.conf b/conf/nginx.conf --- a/conf/nginx.conf +++ b/conf/nginx.conf @@ -16,9 +16,9 @@ http { default_type application/octet-stream; sendfile on; - # tcp_nodelay on; + #tcp_nodelay on; - # keepalive_timeout 0; + #keepalive_timeout 0; #gzip on; diff --git a/src/core/nginx.c b/src/core/nginx.c --- a/src/core/nginx.c +++ b/src/core/nginx.c @@ -301,6 +301,8 @@ ngx_add_inherited_sockets(ngx_cycle_t *c return NGX_ERROR; } + ngx_memzero(ls, sizeof(ngx_listening_t)); + ls->fd = (ngx_socket_t) s; } } diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VER "nginx/0.1.35" +#define NGINX_VER "nginx/0.1.36" #define NGINX_VAR "NGINX" #define NGX_NEWPID_EXT ".newbin" diff --git a/src/core/ngx_connection.c b/src/core/ngx_connection.c --- a/src/core/ngx_connection.c +++ b/src/core/ngx_connection.c @@ -62,10 +62,18 @@ ngx_listening_inet_stream_socket(ngx_con ngx_int_t ngx_set_inherited_sockets(ngx_cycle_t *cycle) { - size_t len; - ngx_uint_t i; - ngx_listening_t *ls; - struct sockaddr_in *sin; + size_t len; + ngx_uint_t i; + ngx_listening_t *ls; + struct sockaddr_in *sin; +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + socklen_t aflen; + struct accept_filter_arg af; +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + socklen_t tlen; + int timeout; +#endif ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { @@ -98,7 +106,6 @@ ngx_set_inherited_sockets(ngx_cycle_t *c ls[i].addr_text_max_len = INET_ADDRSTRLEN; - ls[i].addr_text.data = ngx_palloc(cycle->pool, INET_ADDRSTRLEN - 1 + sizeof(":65535") - 1); if (ls[i].addr_text.data == NULL) { @@ -115,6 +122,54 @@ ngx_set_inherited_sockets(ngx_cycle_t *c ls[i].addr_text.len = ngx_sprintf(ls[i].addr_text.data + len, ":%d", ntohs(sin->sin_port)) - ls[i].addr_text.data; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + + ngx_memzero(&af, sizeof(struct accept_filter_arg)); + aflen = sizeof(struct accept_filter_arg); + + if (getsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, &af, &aflen) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno, + "getsockopt(SO_ACCEPTFILTER) for %V failed, ignored", + &ls[i].addr_text); + continue; + } + + if (aflen < sizeof(struct accept_filter_arg) || af.af_name[0] == '\0') { + continue; + } + + ls[i].accept_filter = ngx_palloc(cycle->pool, 16); + if (ls[i].accept_filter == NULL) { + return NGX_ERROR; + } + + (void) ngx_cpystrn((u_char *) ls[i].accept_filter, + (u_char *) af.af_name, 16); +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + + timeout = 0; + tlen = sizeof(int); + + if (getsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, &timeout, &tlen) + == -1) + { + ngx_log_error(NGX_LOG_NOTICE, cycle->log, ngx_errno, + "getsockopt(TCP_DEFER_ACCEPT) for %V failed, ignored", + &ls[i].addr_text); + continue; + } + + if (tlen < sizeof(int) || timeout == 0) { + continue; + } + + ls[i].deferred_accept = 1; +#endif } return NGX_OK; 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 @@ -47,11 +47,17 @@ typedef struct { unsigned nonblocking_accept:1; unsigned nonblocking:1; unsigned shared:1; /* shared between threads or processes */ + unsigned addr_ntop:1; + #if (NGX_HAVE_DEFERRED_ACCEPT) unsigned deferred_accept:1; + unsigned delete_deferred:1; + unsigned add_deferred:1; +#ifdef SO_ACCEPTFILTER + char *accept_filter; +#endif #endif - unsigned addr_ntop:1; } ngx_listening_t; 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 @@ -39,18 +39,24 @@ static ngx_str_t error_log = ngx_null_s ngx_cycle_t *ngx_init_cycle(ngx_cycle_t *old_cycle) { - void *rv; - ngx_uint_t i, n, failed; - ngx_log_t *log; - ngx_conf_t conf; - ngx_pool_t *pool; - ngx_cycle_t *cycle, **old; - ngx_socket_t fd; - ngx_list_part_t *part; - ngx_open_file_t *file; - ngx_listening_t *ls, *nls; - ngx_core_conf_t *ccf; - ngx_core_module_t *module; + void *rv; + ngx_uint_t i, n, failed; + ngx_log_t *log; + ngx_conf_t conf; + ngx_pool_t *pool; + ngx_cycle_t *cycle, **old; + ngx_socket_t fd; + ngx_list_part_t *part; + ngx_open_file_t *file; + ngx_listening_t *ls, *nls; + ngx_core_conf_t *ccf; + ngx_core_module_t *module; +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + struct accept_filter_arg af; +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + int timeout; +#endif log = old_cycle->log; @@ -307,7 +313,7 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t } if (ngx_cmp_sockaddr(nls[n].sockaddr, ls[i].sockaddr) - == NGX_OK) + == NGX_OK) { fd = ls[i].fd; #if (NGX_WIN32) @@ -330,8 +336,44 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t } nls[n].fd = ls[i].fd; - nls[i].remain = 1; + nls[n].remain = 1; ls[i].remain = 1; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + + /* + * FreeBSD, except the most recent versions, + * can not remove accept filter + */ + nls[n].deferred_accept = ls[i].deferred_accept; + + if (ls[i].accept_filter && nls[n].accept_filter) { + if (ngx_strcmp(ls[i].accept_filter, + nls[n].accept_filter) != 0) + { + nls[n].delete_deferred = 1; + nls[n].add_deferred = 1; + } + + } else if (ls[i].accept_filter) { + nls[n].delete_deferred = 1; + + } else if (nls[n].accept_filter) { + nls[n].add_deferred = 1; + } +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + + if (ls[n].deferred_accept && !nls[n].deferred_accept) { + nls[n].delete_deferred = 1; + + } else if (ls[i].deferred_accept + != nls[n].deferred_accept) + { + nls[n].add_deferred = 1; + } +#endif break; } } @@ -345,6 +387,16 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t ls = cycle->listening.elts; for (i = 0; i < cycle->listening.nelts; i++) { ls[i].open = 1; +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + if (ls[i].accept_filter) { + ls[i].add_deferred = 1; + } +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + if (ls[i].deferred_accept) { + ls[i].add_deferred = 1; + } +#endif } } @@ -352,6 +404,81 @@ ngx_cycle_t *ngx_init_cycle(ngx_cycle_t if (ngx_open_listening_sockets(cycle) == NGX_ERROR) { failed = 1; } + +#if (NGX_HAVE_DEFERRED_ACCEPT) + + if (!failed) { + ls = cycle->listening.elts; + for (i = 0; i < cycle->listening.nelts; i++) { + +#ifdef SO_ACCEPTFILTER + if (ls[i].delete_deferred) { + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, + NULL, 0) == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "setsockopt(SO_ACCEPTFILTER, NULL) " + "for %V failed, ignored", + &ls[i].addr_text); + + if (ls[i].accept_filter) { + ngx_log_error(NGX_LOG_ALERT, log, 0, + "could not change the accept filter " + "to \"%s\" for %V, ignored", + ls[i].accept_filter, &ls[i].addr_text); + } + + continue; + } + + ls[i].deferred_accept = 0; + } + + if (ls[i].add_deferred) { + ngx_memzero(&af, sizeof(struct accept_filter_arg)); + (void) ngx_cpystrn((u_char *) af.af_name, + (u_char *) ls[i].accept_filter, 16); + + if (setsockopt(ls[i].fd, SOL_SOCKET, SO_ACCEPTFILTER, + &af, sizeof(struct accept_filter_arg)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "setsockopt(SO_ACCEPTFILTER, \"%s\") " + "for %V failed, ignored", + ls[i].accept_filter, &ls[i].addr_text); + continue; + } + + ls[i].deferred_accept = 1; + } +#endif + +#ifdef TCP_DEFER_ACCEPT + if (ls[i].add_deferred || ls[i].delete_deferred) { + timeout = 0; + + if (ls[i].add_deferred) { + timeout = (int) (ls[i].post_accept_timeout / 1000); + } + + if (setsockopt(ls[i].fd, IPPROTO_TCP, TCP_DEFER_ACCEPT, + &timeout, sizeof(int)) == -1) + { + ngx_log_error(NGX_LOG_ALERT, log, ngx_errno, + "setsockopt(TCP_DEFER_ACCEPT, %d) " + "for %V failed, ignored", + timeout, &ls[i].addr_text); + continue; + } + } + + if (ls[i].add_deferred) { + ls[i].deferred_accept = 1; + } +#endif + } + } +#endif } } @@ -682,6 +809,7 @@ void ngx_reopen_files(ngx_cycle_t *cycle break; } part = part->next; + file = part->elts; i = 0; } diff --git a/src/core/ngx_string.c b/src/core/ngx_string.c --- a/src/core/ngx_string.c +++ b/src/core/ngx_string.c @@ -728,6 +728,35 @@ ngx_decode_base64(ngx_str_t *dst, ngx_st } +size_t +ngx_utf_length(ngx_str_t *utf) +{ + u_char c; + size_t len; + ngx_uint_t i; + + for (len = 0, i = 0; i < utf->len; len++, i++) { + + c = utf->data[i]; + + if (c < 0x80) { + continue; + } + + if (c < 0xC0) { + /* invalid utf */ + return utf->len; + } + + for (c <<= 1; c & 0x80; c <<= 1) { + i++; + } + } + + return len; +} + + uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type) { @@ -792,30 +821,8 @@ ngx_escape_uri(u_char *dst, u_char *src, 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; - /* " ", """, "%", "'", %00-%1F, %7F-%FF */ - - static uint32_t utf[] = - { 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ - - /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x800000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ - - /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ - - /* ~}| {zyx wvut srqp onml kjih gfed cba` */ - 0x80000000, /* 1000 0000 0000 0000 0000 0000 0000 0000 */ - - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ - 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ - 0x00000000 /* 0000 0000 0000 0000 0000 0000 0000 0000 */ }; - switch (type) { - case NGX_ESCAPE_UTF: - escape = utf; - break; case NGX_ESCAPE_HTML: escape = html; break; diff --git a/src/core/ngx_string.h b/src/core/ngx_string.h --- a/src/core/ngx_string.h +++ b/src/core/ngx_string.h @@ -96,11 +96,11 @@ void ngx_md5_text(u_char *text, u_char * void ngx_encode_base64(ngx_str_t *dst, ngx_str_t *src); ngx_int_t ngx_decode_base64(ngx_str_t *dst, ngx_str_t *src); +size_t ngx_utf_length(ngx_str_t *utf); #define NGX_ESCAPE_URI 0 #define NGX_ESCAPE_ARGS 1 #define NGX_ESCAPE_HTML 2 -#define NGX_ESCAPE_UTF 3 uintptr_t ngx_escape_uri(u_char *dst, u_char *src, size_t size, ngx_uint_t type); diff --git a/src/event/ngx_event_accept.c b/src/event/ngx_event_accept.c --- a/src/event/ngx_event_accept.c +++ b/src/event/ngx_event_accept.c @@ -247,6 +247,9 @@ ngx_event_accept(ngx_event_t *ev) if (ev->deferred_accept) { rev->ready = 1; +#if (NGX_HAVE_KQUEUE) + rev->available = 1; +#endif } c->ctx = ls->ctx; diff --git a/src/http/modules/ngx_http_autoindex_module.c b/src/http/modules/ngx_http_autoindex_module.c --- a/src/http/modules/ngx_http_autoindex_module.c +++ b/src/http/modules/ngx_http_autoindex_module.c @@ -217,6 +217,16 @@ ngx_http_autoindex_handler(ngx_http_requ return ngx_http_autoindex_error(r, &dir, dname.data); } + r->headers_out.status = NGX_HTTP_OK; + r->headers_out.content_type.len = sizeof("text/html") - 1; + r->headers_out.content_type.data = (u_char *) "text/html"; + + rc = ngx_http_send_header(r); + + if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { + return rc; + } + fname.len = 0; #if (NGX_SUPPRESS_WARN) fname.data = NULL; @@ -334,6 +344,10 @@ ngx_http_autoindex_handler(ngx_http_requ + sizeof(" 28-Sep-1970 12:00 ") - 1 + 19 + 2; + + if (r->utf8) { + len += entry[i].name.len - ngx_utf_length(&entry[i].name); + } } b = ngx_create_temp_buf(r->pool, len); @@ -380,7 +394,11 @@ ngx_http_autoindex_handler(ngx_http_requ b->last = ngx_cpystrn(b->last, entry[i].name.data, NGX_HTTP_AUTOINDEX_NAME_LEN + 1); - len = entry[i].name.len; + if (r->utf8) { + len = ngx_utf_length(&entry[i].name); + } else { + len = entry[i].name.len; + } if (len > NGX_HTTP_AUTOINDEX_NAME_LEN) { b->last = ngx_cpymem(b->last - 3, "..>", @@ -426,17 +444,6 @@ ngx_http_autoindex_handler(ngx_http_requ b->last = ngx_cpymem(b->last, tail, sizeof(tail) - 1); - r->headers_out.status = NGX_HTTP_OK; - r->headers_out.content_length_n = b->last - b->pos; - r->headers_out.content_type.len = sizeof("text/html") - 1; - r->headers_out.content_type.data = (u_char *) "text/html"; - - rc = ngx_http_send_header(r); - - if (rc == NGX_ERROR || rc > NGX_OK || r->header_only) { - return rc; - } - if (r->main == NULL) { b->last_buf = 1; } diff --git a/src/http/modules/ngx_http_charset_filter_module.c b/src/http/modules/ngx_http_charset_filter_module.c --- a/src/http/modules/ngx_http_charset_filter_module.c +++ b/src/http/modules/ngx_http_charset_filter_module.c @@ -12,15 +12,17 @@ typedef struct { char **tables; ngx_str_t name; - ngx_uint_t server; /* unsigned server:1; */ + + unsigned server:1; + unsigned utf8:1; } ngx_http_charset_t; typedef struct { - ngx_int_t src; - ngx_int_t dst; - char *src2dst; - char *dst2src; + ngx_int_t src; + ngx_int_t dst; + char *src2dst; + char *dst2src; } ngx_http_charset_tables_t; @@ -31,17 +33,17 @@ typedef struct { typedef struct { - ngx_flag_t enable; - ngx_flag_t autodetect; + ngx_flag_t enable; + ngx_flag_t autodetect; - ngx_int_t default_charset; - ngx_int_t source_charset; + ngx_int_t default_charset; + ngx_int_t source_charset; } ngx_http_charset_loc_conf_t; typedef struct { - ngx_int_t server; - ngx_int_t client; + ngx_int_t server; + ngx_int_t client; } ngx_http_charset_ctx_t; @@ -183,6 +185,7 @@ ngx_http_charset_header_filter(ngx_http_ charsets = mcf->charsets.elts; r->headers_out.charset = charsets[lcf->default_charset].name; + r->utf8 = charsets[lcf->default_charset].utf8; if (lcf->default_charset == lcf->source_charset) { return ngx_http_next_header_filter(r); @@ -448,6 +451,10 @@ ngx_http_add_charset(ngx_array_t *charse c->name = *name; c->server = 0; + if (ngx_strcasecmp(name->data, "utf-8") == 0) { + c->utf8 = 1; + } + return i; } 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 @@ -66,8 +66,9 @@ static char * ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; - ngx_uint_t mi, m, s, l, p, a, n; - ngx_uint_t port_found, addr_found, virtual_names, key; + ngx_uint_t mi, m, s, l, p, a, n, key; + ngx_uint_t port_found, addr_found; + ngx_uint_t virtual_names, separate_binding; ngx_conf_t pcf; ngx_array_t in_ports; ngx_listening_t *ls; @@ -408,9 +409,9 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * for this address:port */ - if (lscf[l].default_server) { + if (lscf[l].conf.default_server) { - if (in_addr[a].default_server) { + if (in_addr[a].conf.default_server) { ngx_log_error(NGX_LOG_ERR, cf->log, 0, "the duplicate default server in %V:%d", &lscf[l].file_name, lscf[l].line); @@ -419,7 +420,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } in_addr[a].core_srv_conf = cscfp[s]; - in_addr[a].default_server = 1; + in_addr[a].conf.default_server = 1; } addr_found = 1; @@ -449,8 +450,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_addr[a].names.elts = NULL; in_addr[a].hash = NULL; in_addr[a].wildcards.elts = NULL; - in_addr[a].default_server = lscf[l].default_server; in_addr[a].core_srv_conf = cscfp[s]; + in_addr[a].conf = lscf[l].conf; if (ngx_http_add_names(cf, &in_addr[a], cscfp[s]) != NGX_OK) @@ -518,6 +519,8 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_port = in_ports.elts; for (p = 0; p < in_ports.nelts; p++) { + separate_binding = 0; + /* * check whether all name-based servers have the same configuraiton * as the default server, or some servers restrict the host names @@ -526,6 +529,10 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma in_addr = in_port[p].addrs.elts; for (a = 0; a < in_port[p].addrs.nelts; a++) { + if (in_addr[a].conf.bind) { + separate_binding = 1; + } + virtual_names = 0; name = in_addr[a].names.elts; @@ -608,7 +615,7 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma * to the "*:port" only and ignore the other bindings */ - if (in_addr[a - 1].addr == INADDR_ANY) { + if (in_addr[a - 1].addr == INADDR_ANY && !separate_binding) { a--; } else { @@ -624,15 +631,13 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma return NGX_CONF_ERROR; } - ls->backlog = -1; - ls->addr_ntop = 1; ls->handler = ngx_http_init_connection; cscf = in_addr[a].core_srv_conf; ls->pool_size = cscf->connection_pool_size; - ls->post_accept_timeout = cscf->post_accept_timeout; + ls->post_accept_timeout = cscf->client_header_timeout; clcf = cscf->ctx->loc_conf[ngx_http_core_module.ctx_index]; ls->log = clcf->err_log; @@ -644,6 +649,16 @@ ngx_http_block(ngx_conf_t *cf, ngx_comma } #endif + ls->backlog = in_addr[a].conf.backlog; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + ls->accept_filter = in_addr[a].conf.accept_filter; +#endif + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ls->deferred_accept = in_addr[a].conf.deferred_accept; +#endif + ls->ctx = ctx; if (in_port[p].addrs.nelts > 1) { @@ -766,8 +781,8 @@ ngx_http_add_address(ngx_conf_t *cf, ngx in_addr->names.elts = NULL; in_addr->hash = NULL; in_addr->wildcards.elts = NULL; - in_addr->default_server = lscf->default_server; in_addr->core_srv_conf = cscf; + in_addr->conf = lscf->conf; #if (NGX_DEBUG) { 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 @@ -102,13 +102,6 @@ static ngx_command_t ngx_http_core_comm offsetof(ngx_http_core_srv_conf_t, connection_pool_size), NULL }, - { ngx_string("post_accept_timeout"), - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, - ngx_conf_set_msec_slot, - NGX_HTTP_SRV_CONF_OFFSET, - offsetof(ngx_http_core_srv_conf_t, post_accept_timeout), - NULL }, - { ngx_string("request_pool_size"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_size_slot, @@ -160,9 +153,9 @@ static ngx_command_t ngx_http_core_comm { ngx_string("listen"), #if 0 - NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, #else - NGX_HTTP_SRV_CONF|NGX_CONF_TAKE12, + NGX_HTTP_SRV_CONF|NGX_CONF_1MORE, #endif ngx_http_core_listen, NGX_HTTP_SRV_CONF_OFFSET, @@ -1592,7 +1585,6 @@ ngx_http_core_create_srv_conf(ngx_conf_t } cscf->connection_pool_size = NGX_CONF_UNSET_SIZE; - cscf->post_accept_timeout = NGX_CONF_UNSET_MSEC; cscf->request_pool_size = NGX_CONF_UNSET_SIZE; cscf->client_header_timeout = NGX_CONF_UNSET_MSEC; cscf->client_header_buffer_size = NGX_CONF_UNSET_SIZE; @@ -1621,6 +1613,8 @@ ngx_http_core_merge_srv_conf(ngx_conf_t return NGX_CONF_ERROR; } + ngx_memzero(ls, sizeof(ngx_http_listen_t)); + ls->addr = INADDR_ANY; #if (NGX_WIN32) ls->port = 80; @@ -1629,7 +1623,6 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ls->port = (getuid() == 0) ? 80 : 8000; #endif ls->family = AF_INET; - ls->default_server = 0; } if (conf->server_names.nelts == 0) { @@ -1662,8 +1655,6 @@ ngx_http_core_merge_srv_conf(ngx_conf_t ngx_conf_merge_size_value(conf->connection_pool_size, prev->connection_pool_size, 256); - ngx_conf_merge_msec_value(conf->post_accept_timeout, - prev->post_accept_timeout, 60000); ngx_conf_merge_size_value(conf->request_pool_size, prev->request_pool_size, 4096); ngx_conf_merge_msec_value(conf->client_header_timeout, @@ -1859,89 +1850,145 @@ ngx_http_core_merge_loc_conf(ngx_conf_t } +/* AF_INET only */ + static char * ngx_http_core_listen(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { ngx_http_core_srv_conf_t *scf = conf; - u_char *addr; - ngx_int_t port; - ngx_uint_t p; - ngx_str_t *args; - struct hostent *h; - ngx_http_listen_t *ls; + char *err; + ngx_str_t *value; + ngx_uint_t n; + struct hostent *h; + ngx_http_listen_t *ls; + ngx_inet_upstream_t inet_upstream; /* * TODO: check duplicate 'listen' directives, * add resolved name to server names ??? */ + value = cf->args->elts; + + ngx_memzero(&inet_upstream, sizeof(ngx_inet_upstream_t)); + + inet_upstream.url = value[1]; + inet_upstream.port_only = 1; + + err = ngx_inet_parse_host_port(&inet_upstream); + + if (err) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "%s in \"%V\" of the \"listen\" directive", + err, &inet_upstream.url); + return NGX_CONF_ERROR; + } + ls = ngx_array_push(&scf->listen); if (ls == NULL) { return NGX_CONF_ERROR; } - /* AF_INET only */ + ngx_memzero(ls, sizeof(ngx_http_listen_t)); ls->family = AF_INET; + ls->port = (in_port_t) (inet_upstream.default_port ? + 80 : inet_upstream.port); ls->file_name = cf->conf_file->file.name; ls->line = cf->conf_file->line; - ls->default_server = 0; - - args = cf->args->elts; - addr = args[1].data; - - for (p = 0; p < args[1].len; p++) { - if (addr[p] == ':') { - addr[p++] = '\0'; - break; + ls->conf.backlog = -1; + + if (inet_upstream.host.len) { + inet_upstream.host.data[inet_upstream.host.len] = '\0'; + + ls->addr = inet_addr((const char *) inet_upstream.host.data); + + if (ls->addr == INADDR_NONE) { + h = gethostbyname((const char *) inet_upstream.host.data); + + if (h == NULL || h->h_addr_list[0] == NULL) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "can not resolve host \"%s\" " + "in the \"listen\" directive", + inet_upstream.host.data); + return NGX_CONF_ERROR; + } + + ls->addr = *(in_addr_t *)(h->h_addr_list[0]); } + + } else { + ls->addr = INADDR_ANY; + } + + if (cf->args->nelts == 2) { + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[2].data, "default") == 0) { + ls->conf.default_server = 1; + n = 3; + } else { + n = 2; } - if (p == args[1].len) { - /* no ":" in the "listen" */ - p = 0; - } - - port = ngx_atoi(&addr[p], args[1].len - p); - - if (port == NGX_ERROR && p == 0) { - - /* "listen host" */ - ls->port = 80; - - } else if ((port == NGX_ERROR && p != 0) /* "listen host:NONNUMBER" */ - || (port < 1 || port > 65536)) { /* "listen 99999" */ + for ( /* void */ ; n < cf->args->nelts; n++) { + + if (ls->conf.default_server == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "\"%V\" parameter can be specified for " + "the default \"listen\" directive only", + &value[n]); + return NGX_CONF_ERROR; + } + + if (ngx_strcmp(value[n].data, "bind") == 0) { + ls->conf.bind = 1; + continue; + } + + if (ngx_strncmp(value[n].data, "bl=", 3) == 0) { + ls->conf.backlog = ngx_atoi(value[n].data + 3, value[n].len - 3); + ls->conf.bind = 1; + + if (ls->conf.backlog == NGX_ERROR || ls->conf.backlog == 0) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "invalid backlog \"%V\"", &value[n]); + return NGX_CONF_ERROR; + } + + continue; + } + + if (ngx_strncmp(value[n].data, "af=", 3) == 0) { +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + ls->conf.accept_filter = (char *) &value[n].data[3]; + ls->conf.bind = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "accept filters \"%V\" are not supported " + "on this platform, ignored", + &value[n]); +#endif + continue; + } + + if (ngx_strcmp(value[n].data, "deferred") == 0) { +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ls->conf.deferred_accept = 1; + ls->conf.bind = 1; +#else + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "the deferred accept is not supported " + "on this platform, ignored"); +#endif + continue; + } ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid port \"%s\" in \"%V\" directive, " - "it must be a number between 1 and 65535", - &addr[p], &cmd->name); - + "the invalid \"%V\" parameter", &value[n]); return NGX_CONF_ERROR; - - } else if (p == 0) { - ls->addr = INADDR_ANY; - ls->port = (in_port_t) port; - return NGX_CONF_OK; - - } else { - ls->port = (in_port_t) port; - } - - ls->addr = inet_addr((const char *) addr); - - if (ls->addr == INADDR_NONE) { - h = gethostbyname((const char *) addr); - - if (h == NULL || h->h_addr_list[0] == NULL) { - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "can not resolve host \"%s\" " - "in \"%V\" directive", addr, &cmd->name); - return NGX_CONF_ERROR; - } - - ls->addr = *(in_addr_t *)(h->h_addr_list[0]); } return NGX_CONF_OK; 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 @@ -14,13 +14,30 @@ typedef struct { + unsigned default_server:1; + unsigned bind:1; + + int backlog; + +#if (NGX_HAVE_DEFERRED_ACCEPT && defined SO_ACCEPTFILTER) + char *accept_filter; +#endif +#if (NGX_HAVE_DEFERRED_ACCEPT && defined TCP_DEFER_ACCEPT) + ngx_uint_t deferred_accept; +#endif + +} ngx_http_listen_conf_t; + + +typedef struct { in_addr_t addr; in_port_t port; int family; + ngx_str_t file_name; ngx_int_t line; - ngx_uint_t default_server; /* unsigned default_server:1; */ + ngx_http_listen_conf_t conf; } ngx_http_listen_t; @@ -83,7 +100,6 @@ typedef struct { ngx_bufs_t large_client_header_buffers; - ngx_msec_t post_accept_timeout; ngx_msec_t client_header_timeout; ngx_uint_t restrict_host_names; @@ -111,7 +127,7 @@ struct ngx_http_in_addr_s { /* the default server configuration for this address:port */ ngx_http_core_srv_conf_t *core_srv_conf; - ngx_uint_t default_server; /* unsigned default_server:1; */ + ngx_http_listen_conf_t conf; }; 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 @@ -22,6 +22,8 @@ static ngx_int_t ngx_http_alloc_large_he static ngx_int_t ngx_http_process_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); +static ngx_int_t ngx_http_process_unique_header_line(ngx_http_request_t *r, + ngx_table_elt_t *h, ngx_uint_t offset); static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset); @@ -62,10 +64,10 @@ static char *ngx_http_client_errors[] = ngx_http_header_t ngx_http_headers_in[] = { { ngx_string("Host"), offsetof(ngx_http_headers_in_t, host), - ngx_http_process_header_line }, + ngx_http_process_unique_header_line }, { ngx_string("Connection"), offsetof(ngx_http_headers_in_t, connection), - ngx_http_process_header_line }, + ngx_http_process_unique_header_line }, { ngx_string("If-Modified-Since"), offsetof(ngx_http_headers_in_t, if_modified_since), @@ -79,7 +81,7 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Content-Length"), offsetof(ngx_http_headers_in_t, content_length), - ngx_http_process_header_line }, + ngx_http_process_unique_header_line }, { ngx_string("Content-Type"), offsetof(ngx_http_headers_in_t, content_type), @@ -104,7 +106,7 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("Authorization"), offsetof(ngx_http_headers_in_t, authorization), - ngx_http_process_header_line }, + ngx_http_process_unique_header_line }, { ngx_string("Keep-Alive"), offsetof(ngx_http_headers_in_t, keep_alive), ngx_http_process_header_line }, @@ -113,12 +115,6 @@ ngx_http_header_t ngx_http_headers_in[] { ngx_string("X-Forwarded-For"), offsetof(ngx_http_headers_in_t, x_forwarded_for), ngx_http_process_header_line }, - - { ngx_string("X-Real-IP"), offsetof(ngx_http_headers_in_t, x_real_ip), - ngx_http_process_header_line }, - - { ngx_string("X-URL"), offsetof(ngx_http_headers_in_t, x_url), - ngx_http_process_header_line }, #endif #if (NGX_HTTP_HEADERS) @@ -906,13 +902,13 @@ ngx_http_read_request_header(ngx_http_re return n; } - if (!rev->ready) { - return NGX_AGAIN; + if (rev->ready) { + n = r->connection->recv(r->connection, r->header_in->last, + r->header_in->end - r->header_in->last); + } else { + n = NGX_AGAIN; } - n = r->connection->recv(r->connection, r->header_in->last, - r->header_in->end - r->header_in->last); - if (n == NGX_AGAIN) { if (!r->header_timeout_set) { cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); @@ -1107,21 +1103,44 @@ ngx_http_process_header_line(ngx_http_re static ngx_int_t +ngx_http_process_unique_header_line(ngx_http_request_t *r, ngx_table_elt_t *h, + ngx_uint_t offset) +{ + ngx_table_elt_t **ph; + + ph = (ngx_table_elt_t **) ((char *) &r->headers_in + offset); + + if (*ph == NULL) { + *ph = h; + return NGX_OK; + } + + ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, + "client sent duplicate header line: \"%V: %V\"", + &h->key, &h->value); + + ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); + + return NGX_ERROR; +} + + +static ngx_int_t ngx_http_process_cookie(ngx_http_request_t *r, ngx_table_elt_t *h, ngx_uint_t offset) { ngx_table_elt_t **cookie; cookie = ngx_array_push(&r->headers_in.cookies); - if (cookie == NULL) { - ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); - ngx_http_close_connection(r->connection); - return NGX_ERROR; + if (cookie) { + *cookie = h; + return NGX_OK; } - *cookie = h; - - return NGX_OK; + ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); + ngx_http_close_connection(r->connection); + + return NGX_ERROR; } 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 @@ -152,8 +152,6 @@ typedef struct { #if (NGX_HTTP_PROXY) ngx_table_elt_t *x_forwarded_for; - ngx_table_elt_t *x_real_ip; - ngx_table_elt_t *x_url; #endif #if (NGX_HTTP_HEADERS) @@ -365,6 +363,7 @@ struct ngx_http_request_s { unsigned internal:1; unsigned closed:1; unsigned done:1; + unsigned utf8:1; unsigned main_filter_need_in_memory:1; unsigned filter_need_in_memory:1; diff --git a/src/os/unix/ngx_freebsd_config.h b/src/os/unix/ngx_freebsd_config.h --- a/src/os/unix/ngx_freebsd_config.h +++ b/src/os/unix/ngx_freebsd_config.h @@ -76,7 +76,7 @@ #endif -#if defined SO_ACCEPTFILTER && !defined NGX_HAVE_DEFERRED_ACCEPT +#if (defined SO_ACCEPTFILTER && !defined NGX_HAVE_DEFERRED_ACCEPT) #define NGX_HAVE_DEFERRED_ACCEPT 1 #endif diff --git a/src/os/unix/ngx_process_cycle.c b/src/os/unix/ngx_process_cycle.c --- a/src/os/unix/ngx_process_cycle.c +++ b/src/os/unix/ngx_process_cycle.c @@ -839,7 +839,7 @@ ngx_worker_process_init(ngx_cycle_t *cyc #endif if (ccf->working_directory.len) { - if (chdir(ccf->working_directory.data) == -1) { + if (chdir((char *) ccf->working_directory.data) == -1) { ngx_log_error(NGX_LOG_ALERT, cycle->log, ngx_errno, "chdir(\"%s\") failed", ccf->working_directory.data); /* fatal */