# HG changeset patch # User Igor Sysoev # Date 1300654800 -10800 # Node ID 8214eaef3530da4aff945052fc2e99b0c097e21e # Parent 02221dcea7231a9ac07cdd9a09d22b95d26759d3 nginx 0.9.6 *) Feature: the "map" directive supports regular expressions as value of the first parameter. *) Feature: $time_iso8601 access_log variable. Thanks to Michael Lustfield. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,13 @@ +Changes with nginx 0.9.6 21 Mar 2011 + + *) Feature: the "map" directive supports regular expressions as value + of the first parameter. + + *) Feature: $time_iso8601 access_log variable. + Thanks to Michael Lustfield. + + Changes with nginx 0.9.5 21 Feb 2011 *) Change: now nginx uses a default listen backlog value -1 on diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,13 @@ +Изменения в nginx 0.9.6 21.03.2011 + + *) Добавление: директива map поддерживает регулярные выражения в + качестве значения первого параметра. + + *) Добавление: переменная $time_iso8601 для access_log. + Спасибо Michael Lustfield. + + Изменения в nginx 0.9.5 21.02.2011 *) Изменение: теперь по умолчанию nginx использует значение -1 для diff --git a/src/core/nginx.h b/src/core/nginx.h --- a/src/core/nginx.h +++ b/src/core/nginx.h @@ -8,8 +8,8 @@ #define _NGINX_H_INCLUDED_ -#define nginx_version 9005 -#define NGINX_VERSION "0.9.5" +#define nginx_version 9006 +#define NGINX_VERSION "0.9.6" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" diff --git a/src/core/ngx_log.c b/src/core/ngx_log.c --- a/src/core/ngx_log.c +++ b/src/core/ngx_log.c @@ -328,7 +328,7 @@ ngx_log_init(u_char *prefix) if (ngx_log_file.fd == NGX_INVALID_FILE) { ngx_log_stderr(ngx_errno, - "[alert]: could not open error log file: " + "[alert] could not open error log file: " ngx_open_file_n " \"%s\" failed", name); #if (NGX_WIN32) ngx_event_log(ngx_errno, 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 @@ -27,6 +27,7 @@ volatile ngx_time_t *ngx_cached_time volatile ngx_str_t ngx_cached_err_log_time; volatile ngx_str_t ngx_cached_http_time; volatile ngx_str_t ngx_cached_http_log_time; +volatile ngx_str_t ngx_cached_http_log_iso8601; #if !(NGX_WIN32) @@ -46,6 +47,8 @@ static u_char cached_http_tim [sizeof("Mon, 28 Sep 1970 06:00:00 GMT")]; static u_char cached_http_log_time[NGX_TIME_SLOTS] [sizeof("28/Sep/1970:12:00:00 +0600")]; +static u_char cached_http_log_iso8601[NGX_TIME_SLOTS] + [sizeof("1970-09-28T12:00:00+06:00")]; static char *week[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; @@ -58,6 +61,7 @@ ngx_time_init(void) ngx_cached_err_log_time.len = sizeof("1970/09/28 12:00:00") - 1; ngx_cached_http_time.len = sizeof("Mon, 28 Sep 1970 06:00:00 GMT") - 1; ngx_cached_http_log_time.len = sizeof("28/Sep/1970:12:00:00 +0600") - 1; + ngx_cached_http_log_iso8601.len = sizeof("1970-09-28T12:00:00+06:00") - 1; ngx_cached_time = &cached_time[0]; @@ -68,7 +72,7 @@ ngx_time_init(void) void ngx_time_update(void) { - u_char *p0, *p1, *p2; + u_char *p0, *p1, *p2, *p3; ngx_tm_t tm, gmt; time_t sec; ngx_uint_t msec; @@ -152,6 +156,15 @@ ngx_time_update(void) tp->gmtoff < 0 ? '-' : '+', ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); + p3 = &cached_http_log_iso8601[slot][0]; + + (void) ngx_sprintf(p3, "%4d-%02d-%02dT%02d:%02d:%02d%c%02d:%02d", + tm.ngx_tm_year, tm.ngx_tm_mon, + tm.ngx_tm_mday, tm.ngx_tm_hour, + tm.ngx_tm_min, tm.ngx_tm_sec, + tp->gmtoff < 0 ? '-' : '+', + ngx_abs(tp->gmtoff / 60), ngx_abs(tp->gmtoff % 60)); + ngx_memory_barrier(); @@ -159,6 +172,7 @@ ngx_time_update(void) ngx_cached_http_time.data = p0; ngx_cached_err_log_time.data = p1; ngx_cached_http_log_time.data = p2; + ngx_cached_http_log_iso8601.data = p3; ngx_unlock(&ngx_time_lock); } diff --git a/src/core/ngx_times.h b/src/core/ngx_times.h --- a/src/core/ngx_times.h +++ b/src/core/ngx_times.h @@ -38,6 +38,7 @@ extern volatile ngx_time_t *ngx_cached_ extern volatile ngx_str_t ngx_cached_err_log_time; extern volatile ngx_str_t ngx_cached_http_time; extern volatile ngx_str_t ngx_cached_http_log_time; +extern volatile ngx_str_t ngx_cached_http_log_iso8601; /* * milliseconds elapsed since epoch and truncated to ngx_msec_t, 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 @@ -83,6 +83,8 @@ static u_char *ngx_http_log_pipe(ngx_htt ngx_http_log_op_t *op); static u_char *ngx_http_log_time(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); +static u_char *ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, + ngx_http_log_op_t *op); static u_char *ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op); static u_char *ngx_http_log_request_time(ngx_http_request_t *r, u_char *buf, @@ -193,6 +195,8 @@ static ngx_http_log_var_t ngx_http_log_ { ngx_string("pipe"), 1, ngx_http_log_pipe }, { ngx_string("time_local"), sizeof("28/Sep/1970:12:00:00 +0600") - 1, ngx_http_log_time }, + { ngx_string("time_iso8601"), sizeof("1970-09-28T12:00:00+06:00") - 1, + ngx_http_log_iso8601 }, { ngx_string("msec"), NGX_TIME_T_LEN + 4, ngx_http_log_msec }, { ngx_string("request_time"), NGX_TIME_T_LEN + 4, ngx_http_log_request_time }, @@ -510,6 +514,12 @@ ngx_http_log_time(ngx_http_request_t *r, ngx_cached_http_log_time.len); } +static u_char * +ngx_http_log_iso8601(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) +{ + return ngx_cpymem(buf, ngx_cached_http_log_iso8601.data, + ngx_cached_http_log_iso8601.len); +} static u_char * ngx_http_log_msec(ngx_http_request_t *r, u_char *buf, ngx_http_log_op_t *op) diff --git a/src/http/modules/ngx_http_map_module.c b/src/http/modules/ngx_http_map_module.c --- a/src/http/modules/ngx_http_map_module.c +++ b/src/http/modules/ngx_http_map_module.c @@ -20,6 +20,9 @@ typedef struct { ngx_array_t *values_hash; ngx_array_t var_values; +#if (NGX_PCRE) + ngx_array_t regexes; +#endif ngx_http_variable_value_t *default_value; ngx_conf_t *cf; @@ -28,7 +31,7 @@ typedef struct { typedef struct { - ngx_hash_combined_t hash; + ngx_http_map_t map; ngx_http_complex_value_t value; ngx_http_variable_value_t *default_value; ngx_uint_t hostnames; /* unsigned hostnames:1 */ @@ -126,7 +129,7 @@ ngx_http_map_variable(ngx_http_request_t key = ngx_hash_strlow(val.data, val.data, len); - value = ngx_hash_find_combined(&map->hash, key, val.data, len); + value = ngx_http_map_find(r, &map->map, key, val.data, len, &val); if (value == NULL) { value = map->default_value; @@ -249,6 +252,15 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } +#if (NGX_PCRE) + if (ngx_array_init(&ctx.regexes, cf->pool, 2, sizeof(ngx_http_map_regex_t)) + != NGX_OK) + { + ngx_destroy_pool(pool); + return NGX_CONF_ERROR; + } +#endif + ctx.default_value = NULL; ctx.cf = &save; ctx.hostnames = 0; @@ -278,7 +290,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c hash.pool = cf->pool; if (ctx.keys.keys.nelts) { - hash.hash = &map->hash.hash; + hash.hash = &map->map.hash.hash; hash.temp_pool = NULL; if (ngx_hash_init(&hash, ctx.keys.keys.elts, ctx.keys.keys.nelts) @@ -306,7 +318,7 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - map->hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; + map->map.hash.wc_head = (ngx_hash_wildcard_t *) hash.hash; } if (ctx.keys.dns_wc_tail.nelts) { @@ -326,9 +338,18 @@ ngx_http_map_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } - map->hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; + map->map.hash.wc_tail = (ngx_hash_wildcard_t *) hash.hash; } +#if (NGX_PCRE) + + if (ctx.regexes.nelts) { + map->map.regex = ctx.regexes.elts; + map->map.nregex = ctx.regexes.nelts; + } + +#endif + ngx_destroy_pool(pool); return rv; @@ -491,6 +512,39 @@ found: return NGX_CONF_OK; } +#if (NGX_PCRE) + + if (value[0].len && value[0].data[0] == '~') { + ngx_regex_compile_t rc; + ngx_http_map_regex_t *regex; + u_char errstr[NGX_MAX_CONF_ERRSTR]; + + regex = ngx_array_push(&ctx->regexes); + if (regex == NULL) { + return NGX_CONF_ERROR; + } + + value[0].len--; + value[0].data++; + + ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); + + rc.pattern = value[0]; + rc.err.len = NGX_MAX_CONF_ERRSTR; + rc.err.data = errstr; + + regex->regex = ngx_http_regex_compile(ctx->cf, &rc); + if (regex->regex == NULL) { + return NGX_CONF_ERROR; + } + + regex->value = var; + + return NGX_CONF_OK; + } + +#endif + if (value[0].len && value[0].data[0] == '\\') { value[0].len--; value[0].data++; 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 @@ -48,7 +48,7 @@ our @EXPORT = qw( HTTP_INSUFFICIENT_STORAGE ); -our $VERSION = '0.9.5'; +our $VERSION = '0.9.6'; 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 @@ -467,7 +467,7 @@ header_out(r, key, value) } if (header->key.len == sizeof("Content-Length") - 1 - && ngx_strncasecmp(header->key.data, "Content-Length", + && ngx_strncasecmp(header->key.data, (u_char *) "Content-Length", sizeof("Content-Length") - 1) == 0) { r->headers_out.content_length_n = (off_t) SvIV(value); @@ -642,7 +642,7 @@ sendfile(r, filename, offset = -1, bytes XSRETURN_EMPTY; } - (void) ngx_cpystrn(path.data, filename, path.len + 1); + (void) ngx_cpystrn(path.data, (u_char *) filename, path.len + 1); clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 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 @@ -1660,6 +1660,50 @@ ngx_http_variable_pid(ngx_http_request_t } +void * +ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map, ngx_uint_t key, + u_char *text, size_t len, ngx_str_t *match) +{ + void *p; + + p = ngx_hash_find_combined(&map->hash, key, text, len); + if (p) { + return p; + } + +#if (NGX_PCRE) + + if (len && map->nregex) { + ngx_int_t n; + ngx_uint_t i; + ngx_http_map_regex_t *reg; + + reg = map->regex; + + for (i = 0; i < map->nregex; i++) { + + n = ngx_http_regex_exec(r, reg[i].regex, match); + + if (n == NGX_OK) { + return reg[i].value; + } + + if (n == NGX_DECLINED) { + continue; + } + + /* NGX_ERROR */ + + return NULL; + } + } + +#endif + + return NULL; +} + + #if (NGX_PCRE) static ngx_int_t 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 @@ -76,6 +76,12 @@ typedef struct { } ngx_http_regex_t; +typedef struct { + ngx_http_regex_t *regex; + void *value; +} ngx_http_map_regex_t; + + ngx_http_regex_t *ngx_http_regex_compile(ngx_conf_t *cf, ngx_regex_compile_t *rc); ngx_int_t ngx_http_regex_exec(ngx_http_request_t *r, ngx_http_regex_t *re, @@ -84,6 +90,19 @@ ngx_int_t ngx_http_regex_exec(ngx_http_r #endif +typedef struct { + ngx_hash_combined_t hash; +#if (NGX_PCRE) + ngx_http_map_regex_t *regex; + ngx_uint_t nregex; +#endif +} ngx_http_map_t; + + +void *ngx_http_map_find(ngx_http_request_t *r, ngx_http_map_t *map, + ngx_uint_t key, u_char *text, size_t len, ngx_str_t *match); + + ngx_int_t ngx_http_variables_add_core_vars(ngx_conf_t *cf); ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf);