# HG changeset patch # User Igor Sysoev # Date 1277841600 -14400 # Node ID c456a023113cfb4ce0dd5acede9b77b8277abb3c # Parent 22b2345b75d98474ba535508babd814f7ab95aa3 nginx 0.8.43 *) Feature: large geo ranges base loading speed-up. *) Bugfix: an error_page redirection to "location /zero { return 204; }" without changing status code kept the error body; the bug had appeared in 0.8.42. *) Bugfix: nginx might close IPv6 listen socket during reconfiguration. Thanks to Maxim Dounin. *) Bugfix: the $uid_set variable may be used at any request processing stage. diff --git a/CHANGES b/CHANGES --- a/CHANGES +++ b/CHANGES @@ -1,4 +1,20 @@ +Changes with nginx 0.8.43 30 Jun 2010 + + *) Feature: large geo ranges base loading speed-up. + + *) Bugfix: an error_page redirection to "location /zero { return 204; + }" without changing status code kept the error body; the bug had + appeared in 0.8.42. + + *) Bugfix: nginx might close IPv6 listen socket during + reconfiguration. + Thanks to Maxim Dounin. + + *) Bugfix: the $uid_set variable may be used at any request processing + stage. + + Changes with nginx 0.8.42 21 Jun 2010 *) Change: now nginx tests locations given by regular expressions, if diff --git a/CHANGES.ru b/CHANGES.ru --- a/CHANGES.ru +++ b/CHANGES.ru @@ -1,4 +1,20 @@ +Изменения в nginx 0.8.43 30.06.2010 + + *) Добавление: ускорение загрузки больших баз geo-диапазонов. + + *) Исправление: перенаправление ошибки в "location /zero { return 204; + }" без изменения кода ответа оставляло тело ошибки; ошибка появилась + в 0.8.42. + + *) Исправление: nginx мог закрывать IPv6 listen сокет во время + переконфигурации. + Спасибо Максиму Дунину. + + *) Исправление: переменную $uid_set можно использовать на любой стадии + обработки запроса. + + Изменения в nginx 0.8.42 21.06.2010 *) Изменение: теперь nginx проверяет location'ы, заданные регулярными 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 8042 -#define NGINX_VERSION "0.8.42" +#define nginx_version 8043 +#define NGINX_VERSION "0.8.43" #define NGINX_VER "nginx/" NGINX_VERSION #define NGINX_VAR "NGINX" 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 @@ -671,7 +671,8 @@ ngx_conf_read_token(ngx_conf_t *cf) } } else if (ch == ' ' || ch == '\t' || ch == CR || ch == LF - || ch == ';' || ch == '{') { + || ch == ';' || ch == '{') + { last_space = 1; found = 1; } 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 @@ -868,7 +868,7 @@ ngx_cmp_sockaddr(struct sockaddr *sa1, s sin61 = (struct sockaddr_in6 *) sa1; sin62 = (struct sockaddr_in6 *) sa2; - if (sin61->sin6_port != sin61->sin6_port) { + if (sin61->sin6_port != sin62->sin6_port) { return NGX_DECLINED; } diff --git a/src/core/ngx_resolver.c b/src/core/ngx_resolver.c --- a/src/core/ngx_resolver.c +++ b/src/core/ngx_resolver.c @@ -1836,7 +1836,7 @@ ngx_resolver_create_addr_query(ngx_resol p += sizeof(ngx_resolver_query_t); - for (n = 0; n < 32; n += 8){ + for (n = 0; n < 32; n += 8) { d = ngx_sprintf(&p[1], "%ud", (ctx->addr >> n) & 0xff); *p = (u_char) (d - &p[1]); p = d; 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 @@ -1638,6 +1638,89 @@ ngx_escape_html(u_char *dst, u_char *src } +void +ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) +{ + ngx_str_node_t *n, *t; + ngx_rbtree_node_t **p; + + for ( ;; ) { + + n = (ngx_str_node_t *) node; + t = (ngx_str_node_t *) temp; + + if (node->key != temp->key) { + + p = (node->key < temp->key) ? &temp->left : &temp->right; + + } else if (n->str.len != t->str.len) { + + p = (n->str.len < t->str.len) ? &temp->left : &temp->right; + + } else { + p = (ngx_memcmp(n->str.data, t->str.data, n->str.len) < 0) + ? &temp->left : &temp->right; + } + + if (*p == sentinel) { + break; + } + + temp = *p; + } + + *p = node; + node->parent = temp; + node->left = sentinel; + node->right = sentinel; + ngx_rbt_red(node); +} + + +ngx_str_node_t * +ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, uint32_t hash) +{ + ngx_int_t rc; + ngx_str_node_t *n; + ngx_rbtree_node_t *node, *sentinel; + + node = rbtree->root; + sentinel = rbtree->sentinel; + + while (node != sentinel) { + + n = (ngx_str_node_t *) node; + + if (hash != node->key) { + node = (hash < node->key) ? node->left : node->right; + continue; + } + + if (val->len != n->str.len) { + node = (val->len < n->str.len) ? node->left : node->right; + continue; + } + + rc = ngx_memcmp(val->data, n->str.data, val->len); + + if (rc < 0) { + node = node->left; + continue; + } + + if (rc > 0) { + node = node->right; + continue; + } + + return n; + } + + return NULL; +} + + /* ngx_sort() is implemented as insertion sort because we need stable sort */ void 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 @@ -89,7 +89,7 @@ ngx_strlchr(u_char *p, u_char *last, u_c #if (NGX_MEMCPY_LIMIT) void *ngx_memcpy(void *dst, void *src, size_t n); -#define ngx_cpymem(dst, src, n) ((u_char *) ngx_memcpy(dst, src, n)) + (n) +#define ngx_cpymem(dst, src, n) (((u_char *) ngx_memcpy(dst, src, n)) + (n)) #else @@ -99,7 +99,7 @@ void *ngx_memcpy(void *dst, void *src, s * icc8 compile memcpy(d, s, 4) to the inline "mov"es or XMM moves. */ #define ngx_memcpy(dst, src, n) (void) memcpy(dst, src, n) -#define ngx_cpymem(dst, src, n) ((u_char *) memcpy(dst, src, n)) + (n) +#define ngx_cpymem(dst, src, n) (((u_char *) memcpy(dst, src, n)) + (n)) #endif @@ -200,6 +200,17 @@ void ngx_unescape_uri(u_char **dst, u_ch uintptr_t ngx_escape_html(u_char *dst, u_char *src, size_t size); +typedef struct { + ngx_rbtree_node_t node; + ngx_str_t str; +} ngx_str_node_t; + + +void ngx_str_rbtree_insert_value(ngx_rbtree_node_t *temp, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); +ngx_str_node_t *ngx_str_rbtree_lookup(ngx_rbtree_t *rbtree, ngx_str_t *name, + uint32_t hash); + void ngx_sort(void *base, size_t n, size_t size, ngx_int_t (*cmp)(const void *, const void *)); diff --git a/src/http/modules/ngx_http_geo_module.c b/src/http/modules/ngx_http_geo_module.c --- a/src/http/modules/ngx_http_geo_module.c +++ b/src/http/modules/ngx_http_geo_module.c @@ -10,41 +10,53 @@ typedef struct { + ngx_http_variable_value_t *value; u_short start; u_short end; - ngx_http_variable_value_t *value; } ngx_http_geo_range_t; typedef struct { - ngx_http_geo_range_t *ranges; - ngx_uint_t n; -} ngx_http_geo_low_ranges_t; - - -typedef struct { - ngx_http_geo_low_ranges_t low[0x10000]; + ngx_http_geo_range_t **low; ngx_http_variable_value_t *default_value; } ngx_http_geo_high_ranges_t; typedef struct { + ngx_str_node_t sn; + ngx_http_variable_value_t *value; + size_t offset; +} ngx_http_geo_variable_value_node_t; + + +typedef struct { ngx_http_variable_value_t *value; ngx_str_t *net; - ngx_http_geo_high_ranges_t *high; + ngx_http_geo_high_ranges_t high; ngx_radix_tree_t *tree; ngx_rbtree_t rbtree; ngx_rbtree_node_t sentinel; ngx_array_t *proxies; ngx_pool_t *pool; ngx_pool_t *temp_pool; + + size_t data_size; + + ngx_str_t include_name; + ngx_uint_t includes; + ngx_uint_t entries; + + unsigned ranges:1; + unsigned outside_entries:1; + unsigned allow_binary_include:1; + unsigned binary_include:1; } ngx_http_geo_conf_ctx_t; typedef struct { union { ngx_radix_tree_t *tree; - ngx_http_geo_high_ranges_t *high; + ngx_http_geo_high_ranges_t high; } u; ngx_array_t *proxies; @@ -73,6 +85,13 @@ static char *ngx_http_geo_add_proxy(ngx_ ngx_http_geo_conf_ctx_t *ctx, ngx_cidr_t *cidr); static ngx_int_t ngx_http_geo_cidr_value(ngx_conf_t *cf, ngx_str_t *net, ngx_cidr_t *cidr); +static char *ngx_http_geo_include(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_str_t *name); +static ngx_int_t ngx_http_geo_include_binary_base(ngx_conf_t *cf, + ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *name); +static void ngx_http_geo_create_binary_base(ngx_http_geo_conf_ctx_t *ctx); +static u_char *ngx_http_geo_copy_values(u_char *base, u_char *p, + ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); static ngx_command_t ngx_http_geo_commands[] = { @@ -119,6 +138,20 @@ ngx_module_t ngx_http_geo_module = { }; +typedef struct { + u_char GEORNG[6]; + u_char version; + u_char ptr_size; + uint32_t endianess; + uint32_t crc32; +} ngx_http_geo_header_t; + + +static ngx_http_geo_header_t ngx_http_geo_header = { + { 'G', 'E', 'O', 'R', 'N', 'G' }, 0, sizeof(void *), 0x12345678, 0 +}; + + /* AF_INET only */ static ngx_int_t @@ -148,23 +181,24 @@ ngx_http_geo_range_variable(ngx_http_req ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; in_addr_t addr; - ngx_uint_t i, n; + ngx_uint_t n; ngx_http_geo_range_t *range; - *v = *ctx->u.high->default_value; + *v = *ctx->u.high.default_value; addr = ngx_http_geo_addr(r, ctx); - range = ctx->u.high->low[addr >> 16].ranges; - - n = addr & 0xffff; + range = ctx->u.high.low[addr >> 16]; - for (i = 0; i < ctx->u.high->low[addr >> 16].n; i++) { - if (n >= (ngx_uint_t) range[i].start - && n <= (ngx_uint_t) range[i].end) - { - *v = *range[i].value; - } + if (range) { + n = addr & 0xffff; + do { + if (n >= (ngx_uint_t) range->start && n <= (ngx_uint_t) range->end) + { + *v = *range->value; + break; + } + } while ((++range)->value); } ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, @@ -256,6 +290,7 @@ static char * ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) { char *rv; + void **p; size_t len; ngx_str_t *value, name; ngx_uint_t i; @@ -302,18 +337,20 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c return NGX_CONF_ERROR; } + ngx_memzero(&ctx, sizeof(ngx_http_geo_conf_ctx_t)); + ctx.temp_pool = ngx_create_pool(16384, cf->log); if (ctx.temp_pool == NULL) { return NGX_CONF_ERROR; } - ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, - ngx_http_variable_value_rbtree_insert); + ngx_rbtree_init(&ctx.rbtree, &ctx.sentinel, ngx_str_rbtree_insert_value); - ctx.high = NULL; - ctx.tree = NULL; - ctx.proxies = NULL; ctx.pool = cf->pool; + ctx.data_size = sizeof(ngx_http_geo_header_t) + + sizeof(ngx_http_variable_value_t) + + 0x10000 * sizeof(ngx_http_geo_range_t *); + ctx.allow_binary_include = 1; save = *cf; cf->pool = pool; @@ -327,25 +364,35 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c geo->proxies = ctx.proxies; - if (ctx.high) { + if (ctx.high.low) { + + if (!ctx.binary_include) { + for (i = 0; i < 0x10000; i++) { + a = (ngx_array_t *) ctx.high.low[i]; + + if (a == NULL || a->nelts == 0) { + continue; + } - for (i = 0; i < 0x10000; i++) { - a = (ngx_array_t *) ctx.high->low[i].ranges; + len = a->nelts * sizeof(ngx_http_geo_range_t); - if (a == NULL || a->nelts == 0) { - continue; + ctx.high.low[i] = ngx_palloc(cf->pool, len + sizeof(void *)); + if (ctx.high.low[i] == NULL) { + return NGX_CONF_ERROR; + } + + p = (void **) ngx_cpymem(ctx.high.low[i], a->elts, len); + *p = NULL; + ctx.data_size += len + sizeof(void *); } - ctx.high->low[i].n = a->nelts; - - len = a->nelts * sizeof(ngx_http_geo_range_t); - - ctx.high->low[i].ranges = ngx_palloc(cf->pool, len); - if (ctx.high->low[i].ranges == NULL ){ - return NGX_CONF_ERROR; + if (ctx.allow_binary_include + && !ctx.outside_entries + && ctx.entries > 100000 + && ctx.includes == 1) + { + ngx_http_geo_create_binary_base(&ctx); } - - ngx_memcpy(ctx.high->low[i].ranges, a->elts, len); } geo->u.high = ctx.high; @@ -353,13 +400,13 @@ ngx_http_geo_block(ngx_conf_t *cf, ngx_c var->get_handler = ngx_http_geo_range_variable; var->data = (uintptr_t) geo; + if (ctx.high.default_value == NULL) { + ctx.high.default_value = &ngx_http_variable_null_value; + } + ngx_destroy_pool(ctx.temp_pool); ngx_destroy_pool(pool); - if (ctx.high->default_value == NULL) { - ctx.high->default_value = &ngx_http_variable_null_value; - } - } else { if (ctx.tree == NULL) { ctx.tree = ngx_radix_tree_create(cf->pool, -1); @@ -396,7 +443,7 @@ static char * ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) { char *rv; - ngx_str_t *value, file; + ngx_str_t *value; ngx_cidr_t cidr; ngx_http_geo_conf_ctx_t *ctx; @@ -415,11 +462,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command goto failed; } - ctx->high = ngx_pcalloc(ctx->pool, - sizeof(ngx_http_geo_high_ranges_t)); - if (ctx->high == NULL) { - goto failed; - } + ctx->ranges = 1; rv = NGX_CONF_OK; @@ -435,20 +478,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command if (ngx_strcmp(value[0].data, "include") == 0) { - file.len = value[1].len++; - - file.data = ngx_pstrdup(ctx->temp_pool, &value[1]); - if (file.data == NULL) { - goto failed; - } - - if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){ - goto failed; - } - - ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); - - rv = ngx_conf_parse(cf, &file); + rv = ngx_http_geo_include(cf, ctx, &value[1]); goto done; @@ -463,7 +493,7 @@ ngx_http_geo(ngx_conf_t *cf, ngx_command goto done; } - if (ctx->high) { + if (ctx->ranges) { rv = ngx_http_geo_range(cf, ctx, value); } else { @@ -488,30 +518,45 @@ static char * ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value) { - u_char *p, *last; - in_addr_t start, end; - ngx_str_t *net; - ngx_uint_t del; - ngx_http_variable_value_t *old; + u_char *p, *last; + in_addr_t start, end; + ngx_str_t *net; + ngx_uint_t del; if (ngx_strcmp(value[0].data, "default") == 0) { - old = ctx->high->default_value; - - ctx->high->default_value = ngx_http_geo_value(cf, ctx, &value[1]); - if (ctx->high->default_value == NULL) { - return NGX_CONF_ERROR; + if (ctx->high.default_value) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "duplicate default geo range value: \"%V\", old value: \"%v\"", + &value[1], ctx->high.default_value); } - if (old) { - ngx_conf_log_error(NGX_LOG_WARN, cf, 0, - "duplicate range \"%V\", value: \"%v\", old value: \"%v\"", - &value[0], ctx->high->default_value, old); + ctx->high.default_value = ngx_http_geo_value(cf, ctx, &value[1]); + if (ctx->high.default_value == NULL) { + return NGX_CONF_ERROR; } return NGX_CONF_OK; } + if (ctx->binary_include) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "binary geo range base \"%s\" may not be mixed with usual entries", + ctx->include_name.data); + return NGX_CONF_ERROR; + } + + if (ctx->high.low == NULL) { + ctx->high.low = ngx_pcalloc(ctx->pool, + 0x10000 * sizeof(ngx_http_geo_range_t *)); + if (ctx->high.low == NULL) { + return NGX_CONF_ERROR; + } + } + + ctx->entries++; + ctx->outside_entries = 1; + if (ngx_strcmp(value[0].data, "delete") == 0) { net = &value[1]; del = 1; @@ -606,7 +651,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n e = 0xffff; } - a = (ngx_array_t *) ctx->high->low[h].ranges; + a = (ngx_array_t *) ctx->high.low[h]; if (a == NULL) { a = ngx_array_create(ctx->temp_pool, 64, @@ -615,7 +660,7 @@ ngx_http_geo_add_range(ngx_conf_t *cf, n return NGX_CONF_ERROR; } - ctx->high->low[h].ranges = (ngx_http_geo_range_t *) a; + ctx->high.low[h] = (ngx_http_geo_range_t *) a; } i = a->nelts; @@ -803,7 +848,7 @@ ngx_http_geo_delete_range(ngx_conf_t *cf e = 0xffff; } - a = (ngx_array_t *) ctx->high->low[h].ranges; + a = (ngx_array_t *) ctx->high.low[h]; if (a == NULL) { warn = 1; @@ -929,16 +974,17 @@ static ngx_http_variable_value_t * ngx_http_geo_value(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, ngx_str_t *value) { - uint32_t hash; - ngx_http_variable_value_t *val; - ngx_http_variable_value_node_t *vvn; + uint32_t hash; + ngx_http_variable_value_t *val; + ngx_http_geo_variable_value_node_t *gvvn; hash = ngx_crc32_long(value->data, value->len); - val = ngx_http_variable_value_lookup(&ctx->rbtree, value, hash); + gvvn = (ngx_http_geo_variable_value_node_t *) + ngx_str_rbtree_lookup(&ctx->rbtree, value, hash); - if (val) { - return val; + if (gvvn) { + return gvvn->value; } val = ngx_palloc(ctx->pool, sizeof(ngx_http_variable_value_t)); @@ -956,16 +1002,22 @@ ngx_http_geo_value(ngx_conf_t *cf, ngx_h val->no_cacheable = 0; val->not_found = 0; - vvn = ngx_palloc(ctx->temp_pool, sizeof(ngx_http_variable_value_node_t)); - if (vvn == NULL) { + gvvn = ngx_palloc(ctx->temp_pool, + sizeof(ngx_http_geo_variable_value_node_t)); + if (gvvn == NULL) { return NULL; } - vvn->node.key = hash; - vvn->len = val->len; - vvn->value = val; + gvvn->sn.node.key = hash; + gvvn->sn.str.len = val->len; + gvvn->sn.str.data = val->data; + gvvn->value = val; + gvvn->offset = 0; - ngx_rbtree_insert(&ctx->rbtree, &vvn->node); + ngx_rbtree_insert(&ctx->rbtree, &gvvn->sn.node); + + ctx->data_size += ngx_align(sizeof(ngx_http_variable_value_t) + value->len, + sizeof(void *)); return val; } @@ -1030,3 +1082,335 @@ ngx_http_geo_cidr_value(ngx_conf_t *cf, return NGX_OK; } + + +static char * +ngx_http_geo_include(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_str_t *name) +{ + char *rv; + ngx_str_t file; + + file.len = name->len + 4; + file.data = ngx_pnalloc(ctx->temp_pool, name->len + 5); + if (file.data == NULL) { + return NGX_CONF_ERROR; + } + + ngx_sprintf(file.data, "%V.bin%Z", name); + + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { + return NGX_CONF_ERROR; + } + + if (ctx->ranges) { + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + switch (ngx_http_geo_include_binary_base(cf, ctx, &file)) { + case NGX_OK: + return NGX_CONF_OK; + case NGX_ERROR: + return NGX_CONF_ERROR; + default: + break; + } + } + + file.len -= 4; + file.data[file.len] = '\0'; + + ctx->include_name = file; + + if (ctx->outside_entries) { + ctx->allow_binary_include = 0; + } + + ngx_log_debug1(NGX_LOG_DEBUG_CORE, cf->log, 0, "include %s", file.data); + + rv = ngx_conf_parse(cf, &file); + + ctx->includes++; + ctx->outside_entries = 0; + + return rv; +} + + +static ngx_int_t +ngx_http_geo_include_binary_base(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, + ngx_str_t *name) +{ + u_char *base, ch; + time_t mtime; + size_t size, len; + ssize_t n; + uint32_t crc32; + ngx_err_t err; + ngx_int_t rc; + ngx_uint_t i; + ngx_file_t file; + ngx_file_info_t fi; + ngx_http_geo_range_t *range, **ranges; + ngx_http_geo_header_t *header; + ngx_http_variable_value_t *vv; + + ngx_memzero(&file, sizeof(ngx_file_t)); + file.name = *name; + file.log = cf->log; + + file.fd = ngx_open_file(name->data, NGX_FILE_RDONLY, 0, 0); + if (file.fd == NGX_INVALID_FILE) { + err = ngx_errno; + if (err != NGX_ENOENT) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, err, + ngx_open_file_n " \"%s\" failed", name->data); + } + return NGX_DECLINED; + } + + if (ctx->outside_entries) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "binary geo range base \"%s\" may not be mixed with usual entries", + name->data); + rc = NGX_ERROR; + goto done; + } + + if (ctx->binary_include) { + ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, + "second binary geo range base \"%s\" may not be mixed with \"%s\"", + name->data, ctx->include_name.data); + rc = NGX_ERROR; + goto done; + } + + if (ngx_fd_info(file.fd, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_fd_info_n " \"%s\" failed", name->data); + goto failed; + } + + size = (size_t) ngx_file_size(&fi); + mtime = ngx_file_mtime(&fi); + + ch = name->data[name->len - 4]; + name->data[name->len - 4] = '\0'; + + if (ngx_file_info(name->data, &fi) == NGX_FILE_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_file_info_n " \"%s\" failed", name->data); + goto failed; + } + + name->data[name->len - 4] = ch; + + if (mtime < ngx_file_mtime(&fi)) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "stale binary geo range base \"%s\"", name->data); + goto failed; + } + + base = ngx_palloc(ctx->pool, size); + if (base == NULL) { + goto failed; + } + + n = ngx_read_file(&file, base, size, 0); + + if (n == NGX_ERROR) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, ngx_errno, + ngx_read_file_n " \"%s\" failed", name->data); + goto failed; + } + + if ((size_t) n != size) { + ngx_conf_log_error(NGX_LOG_CRIT, cf, 0, + ngx_read_file_n " \"%s\" returned only %z bytes instead of %z", + name->data, n, size); + goto failed; + } + + header = (ngx_http_geo_header_t *) base; + + if (size < 16 || ngx_memcmp(&ngx_http_geo_header, header, 12) != 0) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "incompatible binary geo range base \"%s\"", name->data); + goto failed; + } + + ngx_crc32_init(crc32); + + vv = (ngx_http_variable_value_t *) (base + sizeof(ngx_http_geo_header_t)); + + while(vv->data) { + len = ngx_align(sizeof(ngx_http_variable_value_t) + vv->len, + sizeof(void *)); + ngx_crc32_update(&crc32, (u_char *) vv, len); + vv->data += (size_t) base; + vv = (ngx_http_variable_value_t *) ((u_char *) vv + len); + } + ngx_crc32_update(&crc32, (u_char *) vv, sizeof(ngx_http_variable_value_t)); + vv++; + + ranges = (ngx_http_geo_range_t **) vv; + + for (i = 0; i < 0x10000; i++) { + ngx_crc32_update(&crc32, (u_char *) &ranges[i], sizeof(void *)); + if (ranges[i]) { + ranges[i] = (ngx_http_geo_range_t *) + ((u_char *) ranges[i] + (size_t) base); + } + } + + range = (ngx_http_geo_range_t *) &ranges[0x10000]; + + while ((u_char *) range < base + size) { + while (range->value) { + ngx_crc32_update(&crc32, (u_char *) range, + sizeof(ngx_http_geo_range_t)); + range->value = (ngx_http_variable_value_t *) + ((u_char *) range->value + (size_t) base); + range++; + } + ngx_crc32_update(&crc32, (u_char *) range, sizeof(void *)); + range = (ngx_http_geo_range_t *) ((u_char *) range + sizeof(void *)); + } + + ngx_crc32_final(crc32); + + if (crc32 != header->crc32) { + ngx_conf_log_error(NGX_LOG_WARN, cf, 0, + "CRC32 mismatch in binary geo range base \"%s\"", name->data); + goto failed; + } + + ngx_conf_log_error(NGX_LOG_NOTICE, cf, 0, + "using binary geo range base \"%s\"", name->data); + + ctx->include_name = *name; + ctx->binary_include = 1; + ctx->high.low = ranges; + rc = NGX_OK; + + goto done; + +failed: + + rc = NGX_DECLINED; + +done: + + if (ngx_close_file(file.fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, cf->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", name->data); + } + + return rc; +} + + +static void +ngx_http_geo_create_binary_base(ngx_http_geo_conf_ctx_t *ctx) +{ + u_char *p; + uint32_t hash; + ngx_str_t s; + ngx_uint_t i; + ngx_file_mapping_t fm; + ngx_http_geo_range_t *r, *range, **ranges; + ngx_http_geo_header_t *header; + ngx_http_geo_variable_value_node_t *gvvn; + + fm.name = ngx_pnalloc(ctx->temp_pool, ctx->include_name.len + 5); + if (fm.name == NULL) { + return; + } + + ngx_sprintf(fm.name, "%V.bin%Z", &ctx->include_name); + + fm.size = ctx->data_size; + fm.log = ctx->pool->log; + + ngx_log_error(NGX_LOG_NOTICE, fm.log, 0, + "creating binary geo range base \"%s\"", fm.name); + + if (ngx_create_file_mapping(&fm) != NGX_OK) { + return; + } + + p = ngx_cpymem(fm.addr, &ngx_http_geo_header, + sizeof(ngx_http_geo_header_t)); + + p = ngx_http_geo_copy_values(fm.addr, p, ctx->rbtree.root, + ctx->rbtree.sentinel); + + p += sizeof(ngx_http_variable_value_t); + + ranges = (ngx_http_geo_range_t **) p; + + p += 0x10000 * sizeof(ngx_http_geo_range_t *); + + for (i = 0; i < 0x10000; i++) { + r = ctx->high.low[i]; + if (r == NULL) { + continue; + } + + range = (ngx_http_geo_range_t *) p; + ranges[i] = (ngx_http_geo_range_t *) (p - (u_char *) fm.addr); + + do { + s.len = r->value->len; + s.data = r->value->data; + hash = ngx_crc32_long(s.data, s.len); + gvvn = (ngx_http_geo_variable_value_node_t *) + ngx_str_rbtree_lookup(&ctx->rbtree, &s, hash); + + range->value = (ngx_http_variable_value_t *) gvvn->offset; + range->start = r->start; + range->end = r->end; + range++; + + } while ((++r)->value); + + range->value = NULL; + + p = (u_char *) range + sizeof(void *); + } + + header = fm.addr; + header->crc32 = ngx_crc32_long((u_char *) fm.addr + + sizeof(ngx_http_geo_header_t), + fm.size - sizeof(ngx_http_geo_header_t)); + + ngx_close_file_mapping(&fm); +} + + +static u_char * +ngx_http_geo_copy_values(u_char *base, u_char *p, ngx_rbtree_node_t *node, + ngx_rbtree_node_t *sentinel) +{ + ngx_http_variable_value_t *vv; + ngx_http_geo_variable_value_node_t *gvvn; + + if (node == sentinel) { + return p; + } + + gvvn = (ngx_http_geo_variable_value_node_t *) node; + gvvn->offset = p - base; + + vv = (ngx_http_variable_value_t *) p; + *vv = *gvvn->value; + p += sizeof(ngx_http_variable_value_t); + vv->data = (u_char *) (p - base); + + p = ngx_cpymem(p, gvvn->sn.str.data, gvvn->sn.str.len); + + p = ngx_align_ptr(p, sizeof(void *)); + + p = ngx_http_geo_copy_values(base, p, node->left, sentinel); + + return ngx_http_geo_copy_values(base, p, node->right, sentinel); +} 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 @@ -374,7 +374,7 @@ ngx_http_map(ngx_conf_t *cf, ngx_command if (ngx_strcmp(value[0].data, "include") == 0) { file = value[1]; - if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK){ + if (ngx_conf_full_name(cf->cycle, &file, 1) != NGX_OK) { return NGX_CONF_ERROR; } diff --git a/src/http/modules/ngx_http_ssi_filter_module.c b/src/http/modules/ngx_http_ssi_filter_module.c --- a/src/http/modules/ngx_http_ssi_filter_module.c +++ b/src/http/modules/ngx_http_ssi_filter_module.c @@ -431,7 +431,7 @@ ngx_http_ssi_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { - if (ctx->buf == NULL ){ + if (ctx->buf == NULL) { ctx->buf = ctx->in->buf; ctx->in = ctx->in->next; ctx->pos = ctx->buf->pos; diff --git a/src/http/modules/ngx_http_sub_filter_module.c b/src/http/modules/ngx_http_sub_filter_module.c --- a/src/http/modules/ngx_http_sub_filter_module.c +++ b/src/http/modules/ngx_http_sub_filter_module.c @@ -210,7 +210,7 @@ ngx_http_sub_body_filter(ngx_http_reques while (ctx->in || ctx->buf) { - if (ctx->buf == NULL ){ + if (ctx->buf == NULL) { ctx->buf = ctx->in->buf; ctx->in = ctx->in->next; ctx->pos = ctx->buf->pos; diff --git a/src/http/modules/ngx_http_userid_filter_module.c b/src/http/modules/ngx_http_userid_filter_module.c --- a/src/http/modules/ngx_http_userid_filter_module.c +++ b/src/http/modules/ngx_http_userid_filter_module.c @@ -47,6 +47,8 @@ static ngx_int_t ngx_http_userid_variabl ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid); static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); +static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r, + ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf); static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf); @@ -199,7 +201,7 @@ ngx_http_userid_filter(ngx_http_request_ conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); - if (conf->enable <= NGX_HTTP_USERID_LOG) { + if (conf->enable < NGX_HTTP_USERID_V1) { return ngx_http_next_header_filter(r); } @@ -209,23 +211,6 @@ ngx_http_userid_filter(ngx_http_request_ return NGX_ERROR; } - if (ctx->uid_got[3] != 0) { - - if (conf->mark == '\0') { - return ngx_http_next_header_filter(r); - - } else { - if (ctx->cookie.len > 23 - && ctx->cookie.data[22] == conf->mark - && ctx->cookie.data[23] == '=') - { - return ngx_http_next_header_filter(r); - } - } - } - - /* ctx->status == NGX_DECLINED */ - if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) { return ngx_http_next_header_filter(r); } @@ -248,18 +233,16 @@ ngx_http_userid_got_variable(ngx_http_re return NGX_OK; } - ctx = ngx_http_userid_get_uid(r, conf); + ctx = ngx_http_userid_get_uid(r->main, conf); if (ctx == NULL) { return NGX_ERROR; } if (ctx->uid_got[3] != 0) { - return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_got); + return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_got); } - /* ctx->status == NGX_DECLINED */ - v->not_found = 1; return NGX_OK; @@ -273,16 +256,29 @@ ngx_http_userid_set_variable(ngx_http_re ngx_http_userid_ctx_t *ctx; ngx_http_userid_conf_t *conf; - ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); + conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module); - if (ctx == NULL || ctx->uid_set[3] == 0) { + if (conf->enable < NGX_HTTP_USERID_V1) { v->not_found = 1; return NGX_OK; } - conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); + ctx = ngx_http_userid_get_uid(r->main, conf); + + if (ctx == NULL) { + return NGX_ERROR; + } - return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_set); + if (ngx_http_userid_create_uid(r->main, ctx, conf) != NGX_OK) { + return NGX_ERROR; + } + + if (ctx->uid_set[3] == 0) { + v->not_found = 1; + return NGX_OK; + } + + return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_set); } @@ -360,82 +356,17 @@ static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf) { - u_char *cookie, *p; - size_t len; - ngx_str_t src, dst; - ngx_table_elt_t *set_cookie, *p3p; - ngx_connection_t *c; - struct sockaddr_in *sin; -#if (NGX_HAVE_INET6) - struct sockaddr_in6 *sin6; -#endif - - /* - * TODO: in the threaded mode the sequencers should be in TLS and their - * ranges should be divided between threads - */ - - if (ctx->uid_got[3] == 0) { - - if (conf->enable == NGX_HTTP_USERID_V1) { - if (conf->service == NGX_CONF_UNSET) { - ctx->uid_set[0] = 0; - } else { - ctx->uid_set[0] = conf->service; - } - ctx->uid_set[1] = (uint32_t) ngx_time(); - ctx->uid_set[2] = start_value; - ctx->uid_set[3] = sequencer_v1; - sequencer_v1 += 0x100; - - } else { - if (conf->service == NGX_CONF_UNSET) { - - c = r->connection; - - if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { - return NGX_ERROR; - } + u_char *cookie, *p; + size_t len; + ngx_str_t src, dst; + ngx_table_elt_t *set_cookie, *p3p; - switch (c->local_sockaddr->sa_family) { - -#if (NGX_HAVE_INET6) - case AF_INET6: - sin6 = (struct sockaddr_in6 *) c->local_sockaddr; - - p = (u_char *) &ctx->uid_set[0]; - - *p++ = sin6->sin6_addr.s6_addr[12]; - *p++ = sin6->sin6_addr.s6_addr[13]; - *p++ = sin6->sin6_addr.s6_addr[14]; - *p = sin6->sin6_addr.s6_addr[15]; + if (ngx_http_userid_create_uid(r, ctx, conf) != NGX_OK) { + return NGX_ERROR; + } - break; -#endif - default: /* AF_INET */ - sin = (struct sockaddr_in *) c->local_sockaddr; - ctx->uid_set[0] = sin->sin_addr.s_addr; - break; - } - - } else { - ctx->uid_set[0] = htonl(conf->service); - } - - ctx->uid_set[1] = htonl((uint32_t) ngx_time()); - ctx->uid_set[2] = htonl(start_value); - ctx->uid_set[3] = htonl(sequencer_v2); - sequencer_v2 += 0x100; - if (sequencer_v2 < 0x03030302) { - sequencer_v2 = 0x03030302; - } - } - - } else { - ctx->uid_set[0] = ctx->uid_got[0]; - ctx->uid_set[1] = ctx->uid_got[1]; - ctx->uid_set[2] = ctx->uid_got[2]; - ctx->uid_set[3] = ctx->uid_got[3]; + if (ctx->uid_set[3] == 0) { + return NGX_OK; } len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len; @@ -518,6 +449,102 @@ ngx_http_userid_set_uid(ngx_http_request static ngx_int_t +ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, + ngx_http_userid_conf_t *conf) +{ + ngx_connection_t *c; + struct sockaddr_in *sin; +#if (NGX_HAVE_INET6) + u_char *p; + struct sockaddr_in6 *sin6; +#endif + + if (ctx->uid_set[3] != 0) { + return NGX_OK; + } + + if (ctx->uid_got[3] != 0) { + + if (conf->mark == '\0' + || (ctx->cookie.len > 23 + && ctx->cookie.data[22] == conf->mark + && ctx->cookie.data[23] == '=')) + { + return NGX_OK; + } + + ctx->uid_set[0] = ctx->uid_got[0]; + ctx->uid_set[1] = ctx->uid_got[1]; + ctx->uid_set[2] = ctx->uid_got[2]; + ctx->uid_set[3] = ctx->uid_got[3]; + + return NGX_OK; + } + + /* + * TODO: in the threaded mode the sequencers should be in TLS and their + * ranges should be divided between threads + */ + + if (conf->enable == NGX_HTTP_USERID_V1) { + if (conf->service == NGX_CONF_UNSET) { + ctx->uid_set[0] = 0; + } else { + ctx->uid_set[0] = conf->service; + } + ctx->uid_set[1] = (uint32_t) ngx_time(); + ctx->uid_set[2] = start_value; + ctx->uid_set[3] = sequencer_v1; + sequencer_v1 += 0x100; + + } else { + if (conf->service == NGX_CONF_UNSET) { + + c = r->connection; + + if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) { + return NGX_ERROR; + } + + switch (c->local_sockaddr->sa_family) { + +#if (NGX_HAVE_INET6) + case AF_INET6: + sin6 = (struct sockaddr_in6 *) c->local_sockaddr; + + p = (u_char *) &ctx->uid_set[0]; + + *p++ = sin6->sin6_addr.s6_addr[12]; + *p++ = sin6->sin6_addr.s6_addr[13]; + *p++ = sin6->sin6_addr.s6_addr[14]; + *p = sin6->sin6_addr.s6_addr[15]; + + break; +#endif + default: /* AF_INET */ + sin = (struct sockaddr_in *) c->local_sockaddr; + ctx->uid_set[0] = sin->sin_addr.s_addr; + break; + } + + } else { + ctx->uid_set[0] = htonl(conf->service); + } + + ctx->uid_set[1] = htonl((uint32_t) ngx_time()); + ctx->uid_set[2] = htonl(start_value); + ctx->uid_set[3] = htonl(sequencer_v2); + sequencer_v2 += 0x100; + if (sequencer_v2 < 0x03030302) { + sequencer_v2 = 0x03030302; + } + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid) { @@ -550,7 +577,7 @@ ngx_http_userid_add_variables(ngx_conf_t var->get_handler = ngx_http_userid_got_variable; - var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH); + var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0); if (var == NULL) { return NGX_ERROR; } 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 @@ -268,7 +268,7 @@ ngx_http_xslt_body_filter(ngx_http_reque if (ngx_http_xslt_add_chunk(r, ctx, cl->buf) != NGX_OK) { - if (ctx->ctxt->myDoc){ + if (ctx->ctxt->myDoc) { #if (NGX_HTTP_XSLT_REUSE_DTD) ctx->ctxt->myDoc->extSubset = NULL; 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.8.42'; +our $VERSION = '0.8.43'; require XSLoader; XSLoader::load('nginx', $VERSION); 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 @@ -1748,6 +1748,7 @@ ngx_http_send_response(ngx_http_request_ r->headers_out.status = status; if (status == NGX_HTTP_NO_CONTENT) { + r->header_only = 1; return ngx_http_send_header(r); } 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 @@ -170,6 +170,10 @@ ngx_http_header_filter(ngx_http_request_ #endif u_char addr[NGX_SOCKADDR_STRLEN]; + if (r->header_sent) { + return NGX_OK; + } + r->header_sent = 1; if (r != r->main) { 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 @@ -272,7 +272,7 @@ ngx_http_parse_request_line(ngx_http_req /* space* before URI */ case sw_spaces_before_uri: - if (ch == '/' ){ + if (ch == '/') { r->uri_start = p; state = sw_after_slash_in_uri; break; 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 @@ -489,7 +489,6 @@ struct ngx_http_request_s { unsigned plain_http:1; unsigned chunked:1; unsigned header_only:1; - unsigned zero_body:1; unsigned keepalive:1; unsigned lingering_close:1; unsigned discard_body:1; 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 @@ -598,31 +598,24 @@ ngx_http_send_special_response(ngx_http_ msie_padding = 0; - if (!r->zero_body) { - if (ngx_http_error_pages[err].len) { - r->headers_out.content_length_n = ngx_http_error_pages[err].len - + len; - if (clcf->msie_padding - && (r->headers_in.msie || r->headers_in.chrome) - && r->http_version >= NGX_HTTP_VERSION_10 - && err >= NGX_HTTP_LEVEL_300) - { - r->headers_out.content_length_n += - sizeof(ngx_http_msie_padding) - 1; - msie_padding = 1; - } - - r->headers_out.content_type_len = sizeof("text/html") - 1; - ngx_str_set(&r->headers_out.content_type, "text/html"); - r->headers_out.content_type_lowcase = NULL; - - } else { - r->headers_out.content_length_n = -1; + if (ngx_http_error_pages[err].len) { + r->headers_out.content_length_n = ngx_http_error_pages[err].len + len; + if (clcf->msie_padding + && (r->headers_in.msie || r->headers_in.chrome) + && r->http_version >= NGX_HTTP_VERSION_10 + && err >= NGX_HTTP_LEVEL_300) + { + r->headers_out.content_length_n += + sizeof(ngx_http_msie_padding) - 1; + msie_padding = 1; } + r->headers_out.content_type_len = sizeof("text/html") - 1; + ngx_str_set(&r->headers_out.content_type, "text/html"); + r->headers_out.content_type_lowcase = NULL; + } else { - r->headers_out.content_length_n = 0; - err = 0; + r->headers_out.content_length_n = -1; } if (r->headers_out.content_length) { 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 @@ -1973,87 +1973,3 @@ ngx_http_variables_init_vars(ngx_conf_t return NGX_OK; } - - -void -ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp, - ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) -{ - ngx_rbtree_node_t **p; - ngx_http_variable_value_node_t *vvn, *vvt; - - for ( ;; ) { - - vvn = (ngx_http_variable_value_node_t *) node; - vvt = (ngx_http_variable_value_node_t *) temp; - - if (node->key != temp->key) { - - p = (node->key < temp->key) ? &temp->left : &temp->right; - - } else if (vvn->len != vvt->len) { - - p = (vvn->len < vvt->len) ? &temp->left : &temp->right; - - } else { - p = (ngx_memcmp(vvn->value->data, vvt->value->data, vvn->len) < 0) - ? &temp->left : &temp->right; - } - - if (*p == sentinel) { - break; - } - - temp = *p; - } - - *p = node; - node->parent = temp; - node->left = sentinel; - node->right = sentinel; - ngx_rbt_red(node); -} - - -ngx_http_variable_value_t * -ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree, ngx_str_t *val, - uint32_t hash) -{ - ngx_int_t rc; - ngx_rbtree_node_t *node, *sentinel; - ngx_http_variable_value_node_t *vvn; - - node = rbtree->root; - sentinel = rbtree->sentinel; - - while (node != sentinel) { - - vvn = (ngx_http_variable_value_node_t *) node; - - if (hash != node->key) { - node = (hash < node->key) ? node->left : node->right; - continue; - } - - if (val->len != vvn->len) { - node = (val->len < vvn->len) ? node->left : node->right; - continue; - } - - rc = ngx_memcmp(val->data, vvn->value->data, val->len); - - if (rc < 0) { - node = node->left; - continue; - } - - if (rc > 0) { - node = node->right; - continue; - } - - return vvn->value; - } - - return NULL; -} 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 @@ -88,19 +88,6 @@ ngx_int_t ngx_http_variables_add_core_va ngx_int_t ngx_http_variables_init_vars(ngx_conf_t *cf); -typedef struct { - ngx_rbtree_node_t node; - size_t len; - ngx_http_variable_value_t *value; -} ngx_http_variable_value_node_t; - - -void ngx_http_variable_value_rbtree_insert(ngx_rbtree_node_t *temp, - ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel); -ngx_http_variable_value_t *ngx_http_variable_value_lookup(ngx_rbtree_t *rbtree, - ngx_str_t *name, uint32_t hash); - - extern ngx_http_variable_value_t ngx_http_variable_null_value; extern ngx_http_variable_value_t ngx_http_variable_true_value; 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 @@ -346,7 +346,7 @@ ngx_mail_auth_plain(ngx_mail_session_t * #endif plain.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len)); - if (plain.data == NULL){ + if (plain.data == NULL) { return NGX_ERROR; } @@ -403,7 +403,7 @@ ngx_mail_auth_login_username(ngx_mail_se "mail auth login username: \"%V\"", &arg[n]); s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[n].len)); - if (s->login.data == NULL){ + if (s->login.data == NULL) { return NGX_ERROR; } @@ -434,7 +434,7 @@ ngx_mail_auth_login_password(ngx_mail_se s->passwd.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len)); - if (s->passwd.data == NULL){ + if (s->passwd.data == NULL) { return NGX_ERROR; } @@ -494,7 +494,7 @@ ngx_mail_auth_cram_md5(ngx_mail_session_ "mail auth cram-md5: \"%V\"", &arg[0]); s->login.data = ngx_pnalloc(c->pool, ngx_base64_decoded_length(arg[0].len)); - if (s->login.data == NULL){ + if (s->login.data == NULL) { return NGX_ERROR; } 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 @@ -76,7 +76,7 @@ ngx_write_file(ngx_file_t *file, u_char #if (NGX_HAVE_PWRITE) for ( ;; ) { - n = pwrite(file->fd, buf, size, offset); + n = pwrite(file->fd, buf + written, size, offset); if (n == -1) { ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, @@ -108,7 +108,7 @@ ngx_write_file(ngx_file_t *file, u_char } for ( ;; ) { - n = write(file->fd, buf, size); + n = write(file->fd, buf + written, size); if (n == -1) { ngx_log_error(NGX_LOG_CRIT, file->log, ngx_errno, @@ -259,6 +259,58 @@ ngx_set_file_time(u_char *name, ngx_fd_t ngx_int_t +ngx_create_file_mapping(ngx_file_mapping_t *fm) +{ + fm->fd = ngx_open_file(fm->name, NGX_FILE_RDWR, NGX_FILE_TRUNCATE, + NGX_FILE_DEFAULT_ACCESS); + if (fm->fd == NGX_INVALID_FILE) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + ngx_open_file_n " \"%s\" failed", fm->name); + return NGX_ERROR; + } + + if (ftruncate(fm->fd, fm->size) == -1) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "ftruncate() \"%s\" failed", fm->name); + goto failed; + } + + fm->addr = mmap(NULL, fm->size, PROT_READ|PROT_WRITE, MAP_SHARED, + fm->fd, 0); + if (fm->addr != MAP_FAILED) { + return NGX_OK; + } + + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "mmap(%uz) \"%s\" failed", fm->size, fm->name); + +failed: + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } + + return NGX_ERROR; +} + + +void +ngx_close_file_mapping(ngx_file_mapping_t *fm) +{ + if (munmap(fm->addr, fm->size) == -1) { + ngx_log_error(NGX_LOG_CRIT, fm->log, ngx_errno, + "munmap(%uz) \"%s\" failed", fm->size, fm->name); + } + + if (ngx_close_file(fm->fd) == NGX_FILE_ERROR) { + ngx_log_error(NGX_LOG_ALERT, fm->log, ngx_errno, + ngx_close_file_n " \"%s\" failed", fm->name); + } +} + + +ngx_int_t ngx_open_dir(ngx_str_t *name, ngx_dir_t *dir) { dir->dir = opendir((const char *) name->data); 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 @@ -18,6 +18,15 @@ typedef ino_t ngx_fil typedef struct { + u_char *name; + size_t size; + void *addr; + ngx_fd_t fd; + ngx_log_t *log; +} ngx_file_mapping_t; + + +typedef struct { DIR *dir; struct dirent *de; struct stat info; @@ -152,6 +161,10 @@ ngx_int_t ngx_set_file_time(u_char *name #define ngx_file_uniq(sb) (sb)->st_ino +ngx_int_t ngx_create_file_mapping(ngx_file_mapping_t *fm); +void ngx_close_file_mapping(ngx_file_mapping_t *fm); + + #if (NGX_HAVE_CASELESS_FILESYSTEM) #define ngx_filename_cmp(s1, s2, n) strncasecmp((char *) s1, (char *) s2, n) diff --git a/src/os/unix/ngx_readv_chain.c b/src/os/unix/ngx_readv_chain.c --- a/src/os/unix/ngx_readv_chain.c +++ b/src/os/unix/ngx_readv_chain.c @@ -158,7 +158,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx rev->ready = 0; - if (n == NGX_ERROR){ + if (n == NGX_ERROR) { c->read->error = 1; } @@ -247,7 +247,7 @@ ngx_readv_chain(ngx_connection_t *c, ngx rev->ready = 0; - if (n == NGX_ERROR){ + if (n == NGX_ERROR) { c->read->error = 1; } diff --git a/src/os/unix/ngx_recv.c b/src/os/unix/ngx_recv.c --- a/src/os/unix/ngx_recv.c +++ b/src/os/unix/ngx_recv.c @@ -113,7 +113,7 @@ ngx_unix_recv(ngx_connection_t *c, u_cha rev->ready = 0; - if (n == NGX_ERROR){ + if (n == NGX_ERROR) { rev->error = 1; } @@ -169,7 +169,7 @@ ngx_unix_recv(ngx_connection_t *c, u_cha rev->ready = 0; - if (n == NGX_ERROR){ + if (n == NGX_ERROR) { rev->error = 1; } diff --git a/src/os/unix/ngx_udp_recv.c b/src/os/unix/ngx_udp_recv.c --- a/src/os/unix/ngx_udp_recv.c +++ b/src/os/unix/ngx_udp_recv.c @@ -60,7 +60,7 @@ ngx_udp_unix_recv(ngx_connection_t *c, u rev->ready = 0; - if (n == NGX_ERROR){ + if (n == NGX_ERROR) { rev->error = 1; } @@ -104,7 +104,7 @@ ngx_udp_unix_recv(ngx_connection_t *c, u rev->ready = 0; - if (n == NGX_ERROR){ + if (n == NGX_ERROR) { rev->error = 1; }