# HG changeset patch # User Igor Sysoev # Date 1184616000 -14400 # Node ID 95183808f549b2d1c8d8004b704287025b4bf76b # Parent 6ccd0af7f70436f6940a1e174860ca7b09b3a8cf nginx 0.6.4 *) Security: the "msie_refresh" directive allowed XSS. Thanks to Maxim Boguk. *) Change: the "proxy_store" and "fastcgi_store" directives were changed. *) Feature: the "proxy_store_access" and "fastcgi_store_access" directives. *) Bugfix: nginx did not work on Solaris/sparc64 if it was built by Sun Studio. Thanks to Andrei Nigmatulin. *) Workaround: for Sun Studio 12. Thanks to Jiang Hong. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,10 +1,29 @@ +Changes with nginx 0.6.4 17 Jul 2007 + + *) Security: the "msie_refresh" directive allowed XSS. + + *) Change: the "proxy_store" and "fastcgi_store" directives were + changed. + + *) Feature: the "proxy_store_access" and "fastcgi_store_access" + directives. + + *) Bugfix: nginx did not work on Solaris/sparc64 if it was built by Sun + Studio. + Thanks to Andrei Nigmatulin. + + *) Workaround: for Sun Studio 12. + Thanks to Jiang Hong. + + Changes with nginx 0.6.3 12 Jul 2007 *) Feature: the "proxy_store" and "fastcgi_store" directives. *) Bugfix: a segmentation fault might occur in worker process if the "auth_http_header" directive was used. + Thanks to Maxim Dounin. *) Bugfix: a segmentation fault occurred in worker process if the CRAM-MD5 authentication method was used, but it was not enabled. diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,10 +1,28 @@ +Изменения в nginx 0.6.4 17.07.2007 + + *) Безопасность: при использовании директивы msie_refresh был возможен + XSS. + + *) Изменение: директивы proxy_store и fastcgi_store изменены. + + *) Добавление: директивы proxy_store_access и fastcgi_store_access. + + *) Исправление: nginx не работал на Solaris/sparc64, если был собран + Sun Studio. + Спасибо Андрею Нигматулину. + + *) Изменение: обход ошибки в Sun Studio 12. + Спасибо Jiang Hong. + + Изменения в nginx 0.6.3 12.07.2007 *) Добавление: директивы proxy_store и fastcgi_store. *) Исправление: при использовании директивы auth_http_header в рабочем процессе мог произойти segmentation fault. + Спасибо Максиму Дунину. *) Исправление: если использовался метод аутентификации CRAM-MD5, но он не был разрешён, то в рабочем процессе происходил segmentation fault. diff --git a/auto/cc/sunc b/auto/cc/sunc --- a/auto/cc/sunc +++ b/auto/cc/sunc @@ -2,8 +2,10 @@ # Copyright (C) Igor Sysoev -# Sun C 5.7 Patch 117837-04 2005/05/11 -# Sun C 5.8 2005/10/13 +# Sun C 5.7 Patch 117837-04 2005/05/11 Sun Studio 10 +# Sun C 5.8 2005/10/13 Sun Studio 11 +# Sun C 5.9 SunOS_i386 2007/05/03 Sun Studio 12 +# Sun C 5.9 SunOS_sparc 2007/05/03 NGX_SUNC_VER=`$CC -V 2>&1 | grep 'Sun C' 2>&1 \ | sed -e 's/^.* Sun C \(.*\)/\1/'` @@ -13,6 +15,33 @@ echo " + Sun C version: $NGX_SUNC_VER" have=NGX_COMPILER value="\"Sun C $NGX_SUNC_VER\"" . auto/define +cat << END > $NGX_AUTOTEST.c + +int main() { printf("%d", __SUNPRO_C); } + +END + +eval "$CC -o $NGX_AUTOTEST $NGX_AUTOTEST.c >> $NGX_ERR 2>&1" + +if [ -x $NGX_AUTOTEST ]; then + ngx_sunc_ver=`$NGX_AUTOTEST` +fi + +rm $NGX_AUTOTEST* + +# 1424 == 0x590, Sun Studio 12 + +if [ "$ngx_sunc_ver" -ge 1424 ]; then + ngx_sparc32="-m32" + ngx_sparc64="-m64" + ngx_amd64="-m64" + +else + ngx_sparc32="-xarch=v8plus" + ngx_sparc64="-xarch=v9" + ngx_amd64="-amd64" +fi + case "$NGX_MACHINE" in i86pc) @@ -35,9 +64,6 @@ case "$NGX_MACHINE" in ;; sun4u | sun4v) - # "-xarch=v9" enables the "casa" assembler instruction - CFLAGS="$CFLAGS -xarch=v9" - CORE_LINK="$CORE_LINK -xarch=v9" NGX_AUX=" src/os/unix/ngx_sunpro_sparc64.il" ;; @@ -46,7 +72,8 @@ esac # optimizations -CFLAGS="$CFLAGS -fast" +IPO=-xipo +CFLAGS="$CFLAGS -fast $IPO" case $CPU in @@ -81,11 +108,29 @@ case $CPU in CPU_OPT="$CPU_OPT -xcache=64/64/2:1024/64/16" ;; + sparc32) + # build 32-bit UltraSparc binary + CPU_OPT="$ngx_sparc32" + CORE_LINK="$CORE_LINK $ngx_sparc32" + CC_AUX_FLAGS="$CC_AUX_FLAGS $ngx_sparc32" + NGX_CPU_CACHE_LINE=64 + ;; + + sparc64) + # build 64-bit UltraSparc binary + CPU_OPT="$ngx_sparc64" + CORE_LINK="$CORE_LINK $ngx_sparc64" + CC_AUX_FLAGS="$CC_AUX_FLAGS $ngx_sparc64" + NGX_CPU_CACHE_LINE=64 + ;; + amd64) # build 64-bit amd64 binary - CPU_OPT="-xarch=amd64" - CORE_LINK="$CORE_LINK -xarch=amd64" + CPU_OPT="$ngx_amd64" + CORE_LINK="$CORE_LINK $ngx_amd64" + CC_AUX_FLAGS="$CC_AUX_FLAGS $ngx_amd4" NGX_AUX=" src/os/unix/ngx_sunpro_amd64.il" + NGX_CPU_CACHE_LINE=64 ;; esac @@ -95,15 +140,15 @@ CFLAGS="$CFLAGS $CPU_OPT" if [ ".$PCRE_OPT" = "." ]; then - PCRE_OPT="-fast $CPU_OPT" + PCRE_OPT="-fast $IPO $CPU_OPT" fi if [ ".$MD5_OPT" = "." ]; then - MD5_OPT="-fast $CPU_OPT" + MD5_OPT="-fast $IPO $CPU_OPT" fi if [ ".$ZLIB_OPT" = "." ]; then - ZLIB_OPT="-fast $CPU_OPT" + ZLIB_OPT="-fast $IPO $CPU_OPT" fi diff --git a/auto/lib/pcre/conf b/auto/lib/pcre/conf --- a/auto/lib/pcre/conf +++ b/auto/lib/pcre/conf @@ -17,7 +17,7 @@ if [ $PCRE != NONE ]; then CORE_LIBS="$CORE_LIBS $PCRE/pcre.lib" ;; - icc* | sunc ) + icc* ) have=NGX_PCRE . auto/have CORE_DEPS="$CORE_DEPS $PCRE/pcre.h" @@ -25,13 +25,18 @@ if [ $PCRE != NONE ]; then echo $ngx_n "checking for PCRE library ...$ngx_c" - if [ -e $PCRE/pcre.h ]; then + if [ -f $PCRE/pcre.h ]; then ngx_pcre_ver=`grep PCRE_MAJOR $PCRE/pcre.h \ | sed -e 's/^.*PCRE_MAJOR.* \(.*\)$/\1/'` - else + else if [ -f $PCRE/configure.in.h ]; then ngx_pcre_ver=`grep PCRE_MAJOR= $PCRE/configure.in \ | sed -e 's/^.*=\(.*\)$/\1/'` + + else + ngx_pcre_ver=`grep pcre_major, $PCRE/configure.ac \ + | sed -e 's/^.*pcre_major,.*\[\(.*\)\].*$/\1/'` + fi fi echo " $ngx_pcre_ver major version found" diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,7 +8,7 @@ #define _NGINX_H_INCLUDED_ -#define NGINX_VERSION "0.6.3" +#define NGINX_VERSION "0.6.4" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_file.c b/src/core/ngx_file.c --- a/src/core/ngx_file.c +++ b/src/core/ngx_file.c @@ -303,11 +303,11 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, ngx_uint_t i, right, shift, *access; access = (ngx_uint_t *) (confp + cmd->offset); - + if (*access != NGX_CONF_UNSET_UINT) { return "is duplicate"; } - + value = cf->args->elts; *access = 0600; @@ -328,10 +328,6 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, shift = 0; p += sizeof("all:") - 1; - } else if (ngx_strncmp(p, "off", sizeof("off") - 1) == 0) { - *access = 0; - return NGX_CONF_OK; - } else { goto invalid; } @@ -348,7 +344,7 @@ ngx_conf_set_access_slot(ngx_conf_t *cf, *access |= right << shift; } - + return NGX_CONF_OK; invalid: 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 @@ -105,21 +105,21 @@ ngx_snprintf(u_char *buf, size_t max, co u_char * ngx_vsnprintf(u_char *buf, size_t max, const char *fmt, va_list args) { - u_char *p, zero, *last, temp[NGX_INT64_LEN + 1]; + u_char *p, zero, *last, temp[NGX_INT64_LEN + 1]; /* * really we need temp[NGX_INT64_LEN] only, * but icc issues the warning */ - int d; - size_t len; - uint32_t ui32; - int64_t i64; - uint64_t ui64; - ngx_msec_t ms; - ngx_str_t *s; - ngx_uint_t width, sign, hexadecimal, max_width; - static u_char hex[] = "0123456789abcdef"; - static u_char HEX[] = "0123456789ABCDEF"; + int d; + size_t len; + uint32_t ui32; + int64_t i64; + uint64_t ui64; + ngx_msec_t ms; + ngx_uint_t width, sign, hexadecimal, max_width; + ngx_variable_value_t *v; + static u_char hex[] = "0123456789abcdef"; + static u_char HEX[] = "0123456789ABCDEF"; if (max == 0) { return buf; @@ -188,12 +188,12 @@ ngx_vsnprintf(u_char *buf, size_t max, c switch (*fmt) { case 'V': - s = va_arg(args, ngx_str_t *); + v = va_arg(args, ngx_variable_value_t *); - len = s->len & 0xffff; + len = v->len; len = (buf + len < last) ? len : (size_t) (last - buf); - buf = ngx_cpymem(buf, s->data, len); + buf = ngx_cpymem(buf, v->data, len); fmt++; continue; @@ -1025,7 +1025,7 @@ ngx_escape_uri(u_char *dst, u_char *src, 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ - 0x800000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ + 0x000000ad, /* 0000 0000 0000 0000 0000 0000 1010 1101 */ /* _^]\ [ZYX WVUT SRQP ONML KJIH GFED CBA@ */ 0x00000000, /* 0000 0000 0000 0000 0000 0000 0000 0000 */ @@ -1039,18 +1039,30 @@ ngx_escape_uri(u_char *dst, u_char *src, 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ }; + /* " ", """, "'", %00-%1F, %7F-%FF */ - switch (type) { - case NGX_ESCAPE_HTML: - escape = html; - break; - case NGX_ESCAPE_ARGS: - escape = args; - break; - default: - escape = uri; - break; - } + static uint32_t refresh[] = { + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + + /* ?>=< ;:98 7654 3210 /.-, +*)( '&%$ #"! */ + 0x00000085, /* 0000 0000 0000 0000 0000 0000 1000 0101 */ + + /* _^]\ [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 */ + + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff, /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + 0xffffffff /* 1111 1111 1111 1111 1111 1111 1111 1111 */ + }; + + static uint32_t *map[] = { uri, args, html, refresh }; + + + escape = map[type]; if (dst == 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 @@ -13,17 +13,28 @@ typedef struct { - size_t len; - u_char *data; + size_t len; + u_char *data; } ngx_str_t; typedef struct { - ngx_str_t key; - ngx_str_t value; + ngx_str_t key; + ngx_str_t value; } ngx_keyval_t; +typedef struct { + unsigned len:29; + + unsigned valid:1; + unsigned no_cachable:1; + unsigned not_found:1; + + u_char *data; +} ngx_variable_value_t; + + #define ngx_string(str) { sizeof(str) - 1, (u_char *) str } #define ngx_null_string { 0, NULL } @@ -142,6 +153,7 @@ u_char *ngx_utf_cpystrn(u_char *dst, u_c #define NGX_ESCAPE_URI 0 #define NGX_ESCAPE_ARGS 1 #define NGX_ESCAPE_HTML 2 +#define NGX_ESCAPE_REFRESH 3 #define NGX_UNESCAPE_URI 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 @@ -187,7 +187,7 @@ ngx_http_charset_header_filter(ngx_http_ { u_char *ct; ngx_int_t charset, source_charset; - ngx_str_t *mc, *from, *to; + ngx_str_t *mc, *from, *to, s; ngx_uint_t n; ngx_http_charset_t *charsets; ngx_http_charset_ctx_t *ctx; @@ -256,8 +256,10 @@ ngx_http_charset_header_filter(ngx_http_ return NGX_ERROR; } - charset = ngx_http_charset_get_charset(charsets, n, - (ngx_str_t *) vv); + s.len = vv->len; + s.data = vv->data; + + charset = ngx_http_charset_get_charset(charsets, n, &s); } } @@ -303,8 +305,10 @@ ngx_http_charset_header_filter(ngx_http_ return NGX_ERROR; } - source_charset = ngx_http_charset_get_charset(charsets, n, - (ngx_str_t *) vv); + s.len = vv->len; + s.data = vv->data; + + source_charset = ngx_http_charset_get_charset(charsets, n, &s); } if (charset != NGX_HTTP_NO_CHARSET) { @@ -373,17 +377,16 @@ static ngx_int_t ngx_http_charset_get_charset(ngx_http_charset_t *charsets, ngx_uint_t n, ngx_str_t *charset) { - size_t len; ngx_uint_t i; - len = charset->len & 0xffff; - for (i = 0; i < n; i++) { - if (charsets[i].name.len != len) { + if (charsets[i].name.len != charset->len) { continue; } - if (ngx_strncasecmp(charsets[i].name.data, charset->data, len) == 0) { + if (ngx_strncasecmp(charsets[i].name.data, charset->data, charset->len) + == 0) + { return i; } } diff --git a/src/http/modules/ngx_http_dav_module.c b/src/http/modules/ngx_http_dav_module.c --- a/src/http/modules/ngx_http_dav_module.c +++ b/src/http/modules/ngx_http_dav_module.c @@ -57,8 +57,6 @@ static ngx_int_t ngx_http_dav_depth(ngx_ static ngx_int_t ngx_http_dav_error(ngx_log_t *log, ngx_err_t err, ngx_int_t not_found, char *failed, u_char *path); static ngx_int_t ngx_http_dav_location(ngx_http_request_t *r, u_char *path); -static char *ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, - void *conf); static void *ngx_http_dav_create_loc_conf(ngx_conf_t *cf); static char *ngx_http_dav_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child); @@ -94,9 +92,9 @@ static ngx_command_t ngx_http_dav_comma { ngx_string("dav_access"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, - ngx_http_dav_access, + ngx_conf_set_access_slot, NGX_HTTP_LOC_CONF_OFFSET, - 0, + offsetof(ngx_http_dav_loc_conf_t, access), NULL }, ngx_null_command @@ -1106,66 +1104,6 @@ ngx_http_dav_location(ngx_http_request_t } -static char * -ngx_http_dav_access(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) -{ - ngx_http_dav_loc_conf_t *lcf = conf; - - u_char *p; - ngx_str_t *value; - ngx_uint_t i, right, shift; - - if (lcf->access != NGX_CONF_UNSET_UINT) { - return "is duplicate"; - } - - value = cf->args->elts; - - lcf->access = 0600; - - for (i = 1; i < cf->args->nelts; i++) { - - p = value[i].data; - - if (ngx_strncmp(p, "user:", sizeof("user:") - 1) == 0) { - shift = 6; - p += sizeof("user:") - 1; - - } else if (ngx_strncmp(p, "group:", sizeof("group:") - 1) == 0) { - shift = 3; - p += sizeof("group:") - 1; - - } else if (ngx_strncmp(p, "all:", sizeof("all:") - 1) == 0) { - shift = 0; - p += sizeof("all:") - 1; - - } else { - goto invalid; - } - - if (ngx_strcmp(p, "rw") == 0) { - right = 6; - - } else if (ngx_strcmp(p, "r") == 0) { - right = 4; - - } else { - goto invalid; - } - - lcf->access |= right << shift; - } - - return NGX_CONF_OK; - -invalid: - - ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, - "invalid value \"%V\"", &value[i]); - return NGX_CONF_ERROR; -} - - static void * ngx_http_dav_create_loc_conf(ngx_conf_t *cf) { 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 @@ -124,6 +124,8 @@ static ngx_int_t ngx_http_fastcgi_script static char *ngx_http_fastcgi_pass(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -201,10 +203,17 @@ static ngx_command_t ngx_http_fastcgi_c NULL }, { ngx_string("fastcgi_store"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_fastcgi_store, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("fastcgi_store_access"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, ngx_conf_set_access_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store), + offsetof(ngx_http_fastcgi_loc_conf_t, upstream.store_access), NULL }, { ngx_string("fastcgi_ignore_client_abort"), @@ -1635,12 +1644,15 @@ ngx_http_fastcgi_create_loc_conf(ngx_con * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; + * conf->upstream.store_lengths = NULL; + * conf->upstream.store_values = NULL; * * conf->index.len = 0; * conf->index.data = NULL; */ - conf->upstream.store = NGX_CONF_UNSET_UINT; + conf->upstream.store = NGX_CONF_UNSET; + conf->upstream.store_access = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; @@ -1685,8 +1697,18 @@ ngx_http_fastcgi_merge_loc_conf(ngx_conf ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; - ngx_conf_merge_uint_value(conf->upstream.store, - prev->upstream.store, 0); + if (conf->upstream.store != 0) { + ngx_conf_merge_value(conf->upstream.store, + prev->upstream.store, 0); + + if (conf->upstream.store_lengths == NULL) { + conf->upstream.store_lengths = prev->upstream.store_lengths; + conf->upstream.store_values = prev->upstream.store_values; + } + } + + ngx_conf_merge_uint_value(conf->upstream.store_access, + prev->upstream.store_access, 0600); ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); @@ -2159,6 +2181,52 @@ ngx_http_fastcgi_pass(ngx_conf_t *cf, ng static char * +ngx_http_fastcgi_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_fastcgi_loc_conf_t *flcf = conf; + + ngx_str_t *value; + ngx_http_script_compile_t sc; + + if (flcf->upstream.store != NGX_CONF_UNSET || flcf->upstream.store_lengths) + { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "on") == 0) { + flcf->upstream.store = 1; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + flcf->upstream.store = 0; + return NGX_CONF_OK; + } + + /* include the terminating '\0' into script */ + value[1].len++; + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &value[1]; + sc.lengths = &flcf->upstream.store_lengths; + sc.values = &flcf->upstream.store_values; + sc.variables = ngx_http_script_variables_count(&value[1]);; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * ngx_http_fastcgi_lowat_check(ngx_conf_t *cf, void *post, void *data) { #if (NGX_FREEBSD) 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 @@ -105,6 +105,8 @@ static char *ngx_http_proxy_pass(ngx_con void *conf); static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); +static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, + void *conf); static char *ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data); @@ -155,10 +157,17 @@ static ngx_command_t ngx_http_proxy_com NULL }, { ngx_string("proxy_store"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, + ngx_http_proxy_store, + NGX_HTTP_LOC_CONF_OFFSET, + 0, + NULL }, + + { ngx_string("proxy_store_access"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, ngx_conf_set_access_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_loc_conf_t, upstream.store), + offsetof(ngx_http_proxy_loc_conf_t, upstream.store_access), NULL }, { ngx_string("proxy_buffering"), @@ -1497,6 +1506,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * conf->upstream.schema = { 0, NULL }; * conf->upstream.uri = { 0, NULL }; * conf->upstream.location = NULL; + * conf->upstream.store_lengths = NULL; + * conf->upstream.store_values = NULL; * * conf->method = NULL; * conf->headers_source = NULL; @@ -1509,7 +1520,8 @@ ngx_http_proxy_create_loc_conf(ngx_conf_ * conf->rewrite_locations = NULL; */ - conf->upstream.store = NGX_CONF_UNSET_UINT; + conf->upstream.store = NGX_CONF_UNSET; + conf->upstream.store_access = NGX_CONF_UNSET_UINT; conf->upstream.buffering = NGX_CONF_UNSET; conf->upstream.ignore_client_abort = NGX_CONF_UNSET; @@ -1561,8 +1573,18 @@ ngx_http_proxy_merge_loc_conf(ngx_conf_t ngx_http_script_compile_t sc; ngx_http_script_copy_code_t *copy; - ngx_conf_merge_uint_value(conf->upstream.store, - prev->upstream.store, 0); + if (conf->upstream.store != 0) { + ngx_conf_merge_value(conf->upstream.store, + prev->upstream.store, 0); + + if (conf->upstream.store_lengths == NULL) { + conf->upstream.store_lengths = prev->upstream.store_lengths; + conf->upstream.store_values = prev->upstream.store_values; + } + } + + ngx_conf_merge_uint_value(conf->upstream.store_access, + prev->upstream.store_access, 0600); ngx_conf_merge_value(conf->upstream.buffering, prev->upstream.buffering, 1); @@ -2371,6 +2393,52 @@ ngx_http_proxy_redirect(ngx_conf_t *cf, static char * +ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) +{ + ngx_http_proxy_loc_conf_t *plcf = conf; + + ngx_str_t *value; + ngx_http_script_compile_t sc; + + if (plcf->upstream.store != NGX_CONF_UNSET || plcf->upstream.store_lengths) + { + return "is duplicate"; + } + + value = cf->args->elts; + + if (ngx_strcmp(value[1].data, "on") == 0) { + plcf->upstream.store = 1; + return NGX_CONF_OK; + } + + if (ngx_strcmp(value[1].data, "off") == 0) { + plcf->upstream.store = 0; + return NGX_CONF_OK; + } + + /* include the terminating '\0' into script */ + value[1].len++; + + ngx_memzero(&sc, sizeof(ngx_http_script_compile_t)); + + sc.cf = cf; + sc.source = &value[1]; + sc.lengths = &plcf->upstream.store_lengths; + sc.values = &plcf->upstream.store_values; + sc.variables = ngx_http_script_variables_count(&value[1]);; + sc.complete_lengths = 1; + sc.complete_values = 1; + + if (ngx_http_script_compile(&sc) != NGX_OK) { + return NGX_CONF_ERROR; + } + + return NGX_CONF_OK; +} + + +static char * ngx_http_proxy_lowat_check(ngx_conf_t *cf, void *post, void *data) { #if (NGX_FREEBSD) 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 @@ -197,11 +197,14 @@ ngx_http_ssl_static_variable(ngx_http_re { ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data; - size_t len; + size_t len; + ngx_str_t s; if (r->connection->ssl) { - (void) handler(r->connection, NULL, (ngx_str_t *) v); + (void) handler(r->connection, NULL, &s); + + v->data = s.data; for (len = 0; v->data[len]; len++) { /* void */ } @@ -225,11 +228,17 @@ ngx_http_ssl_variable(ngx_http_request_t { ngx_ssl_variable_handler_pt handler = (ngx_ssl_variable_handler_pt) data; + ngx_str_t s; + if (r->connection->ssl) { - if (handler(r->connection, r->pool, (ngx_str_t *) v) != NGX_OK) { + + if (handler(r->connection, r->pool, &s) != NGX_OK) { return NGX_ERROR; } + v->len = s.len; + v->data = s.data; + if (v->len) { v->valid = 1; v->no_cachable = 0; diff --git a/src/http/modules/perl/nginx.pm b/src/http/modules/perl/nginx.pm --- a/src/http/modules/perl/nginx.pm +++ b/src/http/modules/perl/nginx.pm @@ -47,7 +47,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.6.3'; +our $VERSION = '0.6.4'; require XSLoader; XSLoader::load('nginx', $VERSION); 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 @@ -315,6 +315,7 @@ ngx_http_special_response_handler(ngx_ht { u_char *p; size_t msie_refresh; + uintptr_t escape; ngx_int_t rc; ngx_buf_t *b; ngx_str_t *uri, *location; @@ -496,17 +497,19 @@ ngx_http_special_response_handler(ngx_ht r->headers_out.content_length = NULL; } - msie_refresh = 0; - location = NULL; - if (clcf->msie_refresh && r->headers_in.msie && (error == NGX_HTTP_MOVED_PERMANENTLY || error == NGX_HTTP_MOVED_TEMPORARILY)) { + location = &r->headers_out.location->value; + + escape = 2 * ngx_escape_uri(NULL, location->data, location->len, + NGX_ESCAPE_REFRESH); + msie_refresh = sizeof(ngx_http_msie_refresh_head) - 1 - + location->len + + escape + location->len + sizeof(ngx_http_msie_refresh_tail) - 1; r->err_status = NGX_HTTP_OK; @@ -514,6 +517,11 @@ ngx_http_special_response_handler(ngx_ht r->headers_out.content_length_n = msie_refresh; r->headers_out.location->hash = 0; r->headers_out.location = NULL; + + } else { + location = NULL; + escape = 0; + msie_refresh = 0; } ngx_http_clear_accept_ranges(r); @@ -595,7 +603,13 @@ ngx_http_special_response_handler(ngx_ht p = ngx_cpymem(b->pos, ngx_http_msie_refresh_head, sizeof(ngx_http_msie_refresh_head) - 1); - p = ngx_cpymem(p, location->data, location->len); + if (escape == 0) { + p = ngx_cpymem(p, location->data, location->len); + + } else { + p = (u_char *) ngx_escape_uri(p, location->data, location->len, + NGX_ESCAPE_REFRESH); + } b->last = ngx_cpymem(p, ngx_http_msie_refresh_tail, sizeof(ngx_http_msie_refresh_tail) - 1); 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 @@ -372,7 +372,7 @@ ngx_http_upstream_init(ngx_http_request_ cln->data = r; u->cleanup = &cln->handler; - u->store = (u->conf->store != 0); + u->store = (u->conf->store || u->conf->store_lengths); ngx_http_upstream_connect(r, u); } @@ -2029,7 +2029,9 @@ ngx_http_upstream_store(ngx_http_request #if !(NGX_WIN32) - if (ngx_change_file_access(temp->data, u->conf->store) == NGX_FILE_ERROR) { + if (ngx_change_file_access(temp->data, u->conf->store_access) + == NGX_FILE_ERROR) + { err = ngx_errno; failed = ngx_change_file_access_n; name = temp->data; @@ -2052,13 +2054,24 @@ ngx_http_upstream_store(ngx_http_request err = ngx_errno; failed = ngx_set_file_time_n; name = temp->data; - + goto failed; } } } - ngx_http_map_uri_to_path(r, &path, &root, 0); + if (u->conf->store_lengths == NULL) { + + ngx_http_map_uri_to_path(r, &path, &root, 0); + + } else { + if (ngx_http_script_run(r, &path, u->conf->store_lengths->elts, 0, + u->conf->store_values->elts) + == NULL) + { + return; + } + } ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, "upstream stores \"%s\" to \"%s\"", temp->data, path.data); @@ -2074,8 +2087,8 @@ ngx_http_upstream_store(ngx_http_request if (err == NGX_ENOENT) { - err = ngx_create_full_path(path.data, ngx_dir_access(u->conf->store)); - + err = ngx_create_full_path(path.data, + ngx_dir_access(u->conf->store_access)); if (err == 0) { if (ngx_rename_file(temp->data, path.data) != NGX_FILE_ERROR) { return; diff --git a/src/http/ngx_http_upstream.h b/src/http/ngx_http_upstream.h --- a/src/http/ngx_http_upstream.h +++ b/src/http/ngx_http_upstream.h @@ -118,7 +118,7 @@ typedef struct { size_t temp_file_write_size_conf; ngx_uint_t next_upstream; - ngx_uint_t store; + ngx_uint_t store_access; ngx_bufs_t bufs; @@ -141,6 +141,10 @@ typedef struct { ngx_str_t location; ngx_str_t url; /* used in proxy_rewrite_location */ + ngx_array_t *store_lengths; + ngx_array_t *store_values; + + signed store:2; unsigned intercept_404:1; unsigned change_buffering:1; 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 @@ -501,7 +501,7 @@ ngx_http_variable_request_set_size(ngx_h ssize_t s, *sp; ngx_str_t val; - val.len = v->len & 0xffff; + val.len = v->len; val.data = v->data; s = ngx_parse_size(&val); 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 @@ -14,15 +14,7 @@ #include -typedef struct { - unsigned len:29; - - unsigned valid:1; - unsigned no_cachable:1; - unsigned not_found:1; - - u_char *data; -} ngx_http_variable_value_t; +typedef ngx_variable_value_t ngx_http_variable_value_t; #define ngx_http_variable(v) { sizeof(v) - 1, 1, 0, 0, (u_char *) v } diff --git a/src/os/unix/ngx_atomic.h b/src/os/unix/ngx_atomic.h --- a/src/os/unix/ngx_atomic.h +++ b/src/os/unix/ngx_atomic.h @@ -87,10 +87,17 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, n ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); +/* + * Sun Studio 12 exits with segmentation fault on '__asm ("pause")', + * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_x86.il + */ + +void +ngx_cpu_pause(void); + /* the code in src/os/unix/ngx_sunpro_x86.il */ #define ngx_memory_barrier() __asm (".volatile"); __asm (".nonvolatile") -#define ngx_cpu_pause() __asm ("pause") #else /* ( __GNUC__ || __INTEL_COMPILER ) */ @@ -121,10 +128,17 @@ ngx_atomic_cmp_set(ngx_atomic_t *lock, n ngx_atomic_int_t ngx_atomic_fetch_add(ngx_atomic_t *value, ngx_atomic_int_t add); +/* + * Sun Studio 12 exits with segmentation fault on '__asm ("pause")', + * so ngx_cpu_pause is declared in src/os/unix/ngx_sunpro_amd64.il + */ + +void +ngx_cpu_pause(void); + /* the code in src/os/unix/ngx_sunpro_amd64.il */ #define ngx_memory_barrier() __asm (".volatile"); __asm (".nonvolatile") -#define ngx_cpu_pause() __asm ("pause") #else /* ( __GNUC__ || __INTEL_COMPILER ) */ @@ -136,7 +150,7 @@ ngx_atomic_fetch_add(ngx_atomic_t *value #endif -#elif ( __sparc__ || __sparcv9 ) +#elif ( __sparc__ || __sparc || __sparcv9 ) #if (NGX_PTR_SIZE == 8) diff --git a/src/os/unix/ngx_sunpro_amd64.il b/src/os/unix/ngx_sunpro_amd64.il --- a/src/os/unix/ngx_sunpro_amd64.il +++ b/src/os/unix/ngx_sunpro_amd64.il @@ -28,3 +28,10 @@ lock xaddq %rax, (%rdi) .end + + +/ ngx_cpu_pause() + + .inline ngx_cpu_pause,0 + pause + .end diff --git a/src/os/unix/ngx_sunpro_x86.il b/src/os/unix/ngx_sunpro_x86.il --- a/src/os/unix/ngx_sunpro_x86.il +++ b/src/os/unix/ngx_sunpro_x86.il @@ -29,3 +29,10 @@ lock xaddl %eax, (%ecx) .end + + +/ ngx_cpu_pause() + + .inline ngx_cpu_pause,0 + pause + .end