changeset 616:8214eaef3530 NGINX_0_9_6

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.
author Igor Sysoev <http://sysoev.ru>
date Mon, 21 Mar 2011 00:00:00 +0300
parents 02221dcea723
children fcda3d3eb4ff
files CHANGES CHANGES.ru src/core/nginx.h src/core/ngx_log.c src/core/ngx_times.c src/core/ngx_times.h src/http/modules/ngx_http_log_module.c src/http/modules/ngx_http_map_module.c src/http/modules/perl/nginx.pm src/http/modules/perl/nginx.xs src/http/ngx_http_variables.c src/http/ngx_http_variables.h
diffstat 12 files changed, 172 insertions(+), 12 deletions(-) [+]
line wrap: on
line diff
--- 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 
--- 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 для 
--- 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"
--- 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,
--- 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);
 }
--- 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,
--- 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)
--- 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++;
--- 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);
--- 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);
 
--- 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
--- 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);