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 {