Mercurial > hg > nginx-vendor-current
comparison src/http/modules/ngx_http_geo_module.c @ 430:dac47e9ef0d5 NGINX_0_7_27
nginx 0.7.27
*) Feature: the "try_files" directive.
*) Feature: variables support in the "fastcgi_pass" directive.
*) Feature: now the $geo variable may get an address from a
variable.
Thanks to Andrei Nigmatulin.
*) Feature: now a location's modifier may be used without space before
name.
*) Feature: the $upstream_response_length variable.
*) Bugfix: now a "add_header" directive does not add an empty value.
*) Bugfix: if zero length static file was requested, then nginx just
closed connection; the bug had appeared in 0.7.25.
*) Bugfix: a MOVE method could not move file in non-existent directory.
*) Bugfix: a segmentation fault occurred in worker process, if no one
named location was defined in server, but some one was used in an
error_page directive.
Thanks to Sergey Bochenkov.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 15 Dec 2008 00:00:00 +0300 |
parents | e7dbea1ee115 |
children | ce4f9ff90bfa |
comparison
equal
deleted
inserted
replaced
429:3b8e9d1bc9bb | 430:dac47e9ef0d5 |
---|---|
8 #include <ngx_core.h> | 8 #include <ngx_core.h> |
9 #include <ngx_http.h> | 9 #include <ngx_http.h> |
10 | 10 |
11 | 11 |
12 typedef struct { | 12 typedef struct { |
13 u_short start; | 13 u_short start; |
14 u_short end; | 14 u_short end; |
15 ngx_http_variable_value_t *value; | 15 ngx_http_variable_value_t *value; |
16 } ngx_http_geo_range_t; | 16 } ngx_http_geo_range_t; |
17 | 17 |
18 | 18 |
19 typedef struct { | 19 typedef struct { |
20 ngx_http_geo_range_t *ranges; | 20 ngx_http_geo_range_t *ranges; |
21 ngx_uint_t n; | 21 ngx_uint_t n; |
22 } ngx_http_geo_low_ranges_t; | 22 } ngx_http_geo_low_ranges_t; |
23 | 23 |
24 | 24 |
25 typedef struct { | 25 typedef struct { |
26 ngx_http_geo_low_ranges_t low[0x10000]; | 26 ngx_http_geo_low_ranges_t low[0x10000]; |
27 ngx_http_variable_value_t *default_value; | 27 ngx_http_variable_value_t *default_value; |
28 } ngx_http_geo_high_ranges_t; | 28 } ngx_http_geo_high_ranges_t; |
29 | 29 |
30 | 30 |
31 typedef struct { | 31 typedef struct { |
32 ngx_http_variable_value_t *value; | 32 ngx_http_variable_value_t *value; |
33 ngx_str_t *net; | 33 ngx_str_t *net; |
34 ngx_http_geo_high_ranges_t *high; | 34 ngx_http_geo_high_ranges_t *high; |
35 ngx_radix_tree_t *tree; | 35 ngx_radix_tree_t *tree; |
36 ngx_rbtree_t rbtree; | 36 ngx_rbtree_t rbtree; |
37 ngx_rbtree_node_t sentinel; | 37 ngx_rbtree_node_t sentinel; |
38 ngx_pool_t *pool; | 38 ngx_pool_t *pool; |
39 ngx_pool_t *temp_pool; | 39 ngx_pool_t *temp_pool; |
40 } ngx_http_geo_conf_ctx_t; | 40 } ngx_http_geo_conf_ctx_t; |
41 | 41 |
42 | 42 |
43 typedef struct { | |
44 union { | |
45 ngx_radix_tree_t *tree; | |
46 ngx_http_geo_high_ranges_t *high; | |
47 } u; | |
48 | |
49 ngx_int_t index; | |
50 } ngx_http_geo_ctx_t; | |
51 | |
52 | |
53 static in_addr_t ngx_http_geo_addr(ngx_http_request_t *r, | |
54 ngx_http_geo_ctx_t *ctx); | |
43 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); | 55 static char *ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf); |
44 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); | 56 static char *ngx_http_geo(ngx_conf_t *cf, ngx_command_t *dummy, void *conf); |
45 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, | 57 static char *ngx_http_geo_range(ngx_conf_t *cf, ngx_http_geo_conf_ctx_t *ctx, |
46 ngx_str_t *value); | 58 ngx_str_t *value); |
47 static char *ngx_http_geo_add_range(ngx_conf_t *cf, | 59 static char *ngx_http_geo_add_range(ngx_conf_t *cf, |
55 | 67 |
56 | 68 |
57 static ngx_command_t ngx_http_geo_commands[] = { | 69 static ngx_command_t ngx_http_geo_commands[] = { |
58 | 70 |
59 { ngx_string("geo"), | 71 { ngx_string("geo"), |
60 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE1, | 72 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE12, |
61 ngx_http_geo_block, | 73 ngx_http_geo_block, |
62 NGX_HTTP_MAIN_CONF_OFFSET, | 74 NGX_HTTP_MAIN_CONF_OFFSET, |
63 0, | 75 0, |
64 NULL }, | 76 NULL }, |
65 | 77 |
102 | 114 |
103 static ngx_int_t | 115 static ngx_int_t |
104 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | 116 ngx_http_geo_cidr_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, |
105 uintptr_t data) | 117 uintptr_t data) |
106 { | 118 { |
107 ngx_radix_tree_t *tree = (ngx_radix_tree_t *) data; | 119 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; |
108 | 120 |
109 struct sockaddr_in *sin; | |
110 ngx_http_variable_value_t *vv; | 121 ngx_http_variable_value_t *vv; |
111 | 122 |
112 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
113 "http geo started"); | |
114 | |
115 sin = (struct sockaddr_in *) r->connection->sockaddr; | |
116 | |
117 vv = (ngx_http_variable_value_t *) | 123 vv = (ngx_http_variable_value_t *) |
118 ngx_radix32tree_find(tree, ntohl(sin->sin_addr.s_addr)); | 124 ngx_radix32tree_find(ctx->u.tree, ngx_http_geo_addr(r, ctx)); |
119 | 125 |
120 *v = *vv; | 126 *v = *vv; |
121 | 127 |
122 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 128 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
123 "http geo: %V %v", &r->connection->addr_text, v); | 129 "http geo: %v", v); |
124 | 130 |
125 return NGX_OK; | 131 return NGX_OK; |
126 } | 132 } |
127 | 133 |
128 | 134 |
129 static ngx_int_t | 135 static ngx_int_t |
130 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, | 136 ngx_http_geo_range_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, |
131 uintptr_t data) | 137 uintptr_t data) |
132 { | 138 { |
133 ngx_http_geo_high_ranges_t *high = (ngx_http_geo_high_ranges_t *) data; | 139 ngx_http_geo_ctx_t *ctx = (ngx_http_geo_ctx_t *) data; |
134 | 140 |
135 in_addr_t addr; | 141 in_addr_t addr; |
136 ngx_uint_t i, n; | 142 ngx_uint_t i, n; |
137 struct sockaddr_in *sin; | |
138 ngx_http_geo_range_t *range; | 143 ngx_http_geo_range_t *range; |
139 | 144 |
140 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 145 *v = *ctx->u.high->default_value; |
141 "http geo started"); | 146 |
142 | 147 addr = ngx_http_geo_addr(r, ctx); |
143 sin = (struct sockaddr_in *) r->connection->sockaddr; | 148 |
144 | 149 range = ctx->u.high->low[addr >> 16].ranges; |
145 *v = *high->default_value; | |
146 | |
147 addr = ntohl(sin->sin_addr.s_addr); | |
148 | |
149 range = high->low[addr >> 16].ranges; | |
150 | 150 |
151 n = addr & 0xffff; | 151 n = addr & 0xffff; |
152 | 152 |
153 for (i = 0; i < high->low[addr >> 16].n; i++) { | 153 for (i = 0; i < ctx->u.high->low[addr >> 16].n; i++) { |
154 if (n >= (ngx_uint_t) range[i].start | 154 if (n >= (ngx_uint_t) range[i].start |
155 && n <= (ngx_uint_t) range[i].end) | 155 && n <= (ngx_uint_t) range[i].end) |
156 { | 156 { |
157 *v = *range[i].value; | 157 *v = *range[i].value; |
158 } | 158 } |
159 } | 159 } |
160 | 160 |
161 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 161 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
162 "http geo: %V %v", &r->connection->addr_text, v); | 162 "http geo: %v", v); |
163 | 163 |
164 return NGX_OK; | 164 return NGX_OK; |
165 } | |
166 | |
167 | |
168 static in_addr_t | |
169 ngx_http_geo_addr(ngx_http_request_t *r, ngx_http_geo_ctx_t *ctx) | |
170 { | |
171 struct sockaddr_in *sin; | |
172 ngx_http_variable_value_t *v; | |
173 | |
174 if (ctx->index == -1) { | |
175 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
176 "http geo started: %V", &r->connection->addr_text); | |
177 | |
178 sin = (struct sockaddr_in *) r->connection->sockaddr; | |
179 return ntohl(sin->sin_addr.s_addr); | |
180 } | |
181 | |
182 v = ngx_http_get_flushed_variable(r, ctx->index); | |
183 | |
184 if (v == NULL || v->not_found) { | |
185 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
186 "http geo not found"); | |
187 | |
188 return 0; | |
189 } | |
190 | |
191 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
192 "http geo started: %v", v); | |
193 | |
194 return ntohl(ngx_inet_addr(v->data, v->len)); | |
165 } | 195 } |
166 | 196 |
167 | 197 |
168 static char * | 198 static char * |
169 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | 199 ngx_http_geo_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
174 ngx_uint_t i; | 204 ngx_uint_t i; |
175 ngx_conf_t save; | 205 ngx_conf_t save; |
176 ngx_pool_t *pool; | 206 ngx_pool_t *pool; |
177 ngx_array_t *a; | 207 ngx_array_t *a; |
178 ngx_http_variable_t *var; | 208 ngx_http_variable_t *var; |
209 ngx_http_geo_ctx_t *geo; | |
179 ngx_http_geo_conf_ctx_t ctx; | 210 ngx_http_geo_conf_ctx_t ctx; |
180 | 211 |
181 value = cf->args->elts; | 212 value = cf->args->elts; |
182 | 213 |
214 geo = ngx_palloc(cf->pool, sizeof(ngx_http_geo_ctx_t)); | |
215 if (geo == NULL) { | |
216 return NGX_CONF_ERROR; | |
217 } | |
218 | |
183 name = value[1]; | 219 name = value[1]; |
184 | 220 name.len--; |
185 if (name.data[0] != '$') { | 221 name.data++; |
186 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | 222 |
187 "\"%V\" variable name should start with '$'", | 223 if (cf->args->nelts == 3) { |
188 &value[1]); | 224 |
189 } else { | 225 geo->index = ngx_http_get_variable_index(cf, &name); |
226 if (geo->index == NGX_ERROR) { | |
227 return NGX_CONF_ERROR; | |
228 } | |
229 | |
230 name = value[2]; | |
190 name.len--; | 231 name.len--; |
191 name.data++; | 232 name.data++; |
233 | |
234 } else { | |
235 geo->index = -1; | |
192 } | 236 } |
193 | 237 |
194 var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); | 238 var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); |
195 if (var == NULL) { | 239 if (var == NULL) { |
196 return NGX_CONF_ERROR; | 240 return NGX_CONF_ERROR; |
242 } | 286 } |
243 | 287 |
244 ngx_memcpy(ctx.high->low[i].ranges, a->elts, len); | 288 ngx_memcpy(ctx.high->low[i].ranges, a->elts, len); |
245 } | 289 } |
246 | 290 |
291 geo->u.high = ctx.high; | |
292 | |
247 var->get_handler = ngx_http_geo_range_variable; | 293 var->get_handler = ngx_http_geo_range_variable; |
248 var->data = (uintptr_t) ctx.high; | 294 var->data = (uintptr_t) geo; |
249 | 295 |
250 ngx_destroy_pool(ctx.temp_pool); | 296 ngx_destroy_pool(ctx.temp_pool); |
251 ngx_destroy_pool(pool); | 297 ngx_destroy_pool(pool); |
252 | 298 |
253 if (ctx.high->default_value == NULL) { | 299 if (ctx.high->default_value == NULL) { |
260 if (ctx.tree == NULL) { | 306 if (ctx.tree == NULL) { |
261 return NGX_CONF_ERROR; | 307 return NGX_CONF_ERROR; |
262 } | 308 } |
263 } | 309 } |
264 | 310 |
311 geo->u.tree = ctx.tree; | |
312 | |
265 var->get_handler = ngx_http_geo_cidr_variable; | 313 var->get_handler = ngx_http_geo_cidr_variable; |
266 var->data = (uintptr_t) ctx.tree; | 314 var->data = (uintptr_t) geo; |
267 | 315 |
268 ngx_destroy_pool(ctx.temp_pool); | 316 ngx_destroy_pool(ctx.temp_pool); |
269 ngx_destroy_pool(pool); | 317 ngx_destroy_pool(pool); |
270 | 318 |
271 if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) { | 319 if (ngx_radix32tree_find(ctx.tree, 0) != NGX_RADIX_NO_VALUE) { |
642 } else { | 690 } else { |
643 net = &value[0]; | 691 net = &value[0]; |
644 del = 0; | 692 del = 0; |
645 } | 693 } |
646 | 694 |
647 rc = ngx_ptocidr(net, &cidrin); | 695 if (ngx_strcmp(net->data, "255.255.255.255") == 0) { |
648 | 696 cidrin.addr = 0xffffffff; |
649 if (rc == NGX_ERROR) { | 697 cidrin.mask = 0xffffffff; |
650 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | 698 |
651 "invalid network \"%V\"", net); | 699 } else { |
652 return NGX_CONF_ERROR; | 700 rc = ngx_ptocidr(net, &cidrin); |
653 } | 701 |
654 | 702 if (rc == NGX_ERROR) { |
655 if (rc == NGX_DONE) { | 703 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
656 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, | 704 "invalid network \"%V\"", net); |
657 "low address bits of %V are meaningless", net); | 705 return NGX_CONF_ERROR; |
658 } | 706 } |
659 | 707 |
660 cidrin.addr = ntohl(cidrin.addr); | 708 if (rc == NGX_DONE) { |
661 cidrin.mask = ntohl(cidrin.mask); | 709 ngx_conf_log_error(NGX_LOG_WARN, cf, 0, |
710 "low address bits of %V are meaningless", | |
711 net); | |
712 } | |
713 | |
714 cidrin.addr = ntohl(cidrin.addr); | |
715 cidrin.mask = ntohl(cidrin.mask); | |
716 } | |
662 | 717 |
663 if (del) { | 718 if (del) { |
664 if (ngx_radix32tree_delete(ctx->tree, cidrin.addr, cidrin.mask) | 719 if (ngx_radix32tree_delete(ctx->tree, cidrin.addr, cidrin.mask) |
665 != NGX_OK) | 720 != NGX_OK) |
666 { | 721 { |