comparison src/http/modules/ngx_http_geoip_module.c @ 502:89dc5654117c NGINX_0_7_63

nginx 0.7.63 *) Security: now "/../" are disabled in "Destination" request header line. *) Change: minimum supported OpenSSL version is 0.9.7. *) Change: the "ask" parameter of the "ssl_verify_client" directive was changed to the "optional" parameter and now it checks a client certificate if it was offered. Thanks to Brice Figureau. *) Feature: now the "-V" switch shows TLS SNI support. *) Feature: the $ssl_client_verify variable. Thanks to Brice Figureau. *) Feature: the "ssl_crl" directive. Thanks to Brice Figureau. *) Bugfix: the $ssl_client_cert variable usage corrupted memory; the bug had appeared in 0.7.7. Thanks to Sergey Zhuravlev. *) Feature: now the start cache loader runs in a separate process; this should improve large caches handling. *) Feature: now temporary files and permanent storage area may reside at different file systems. *) Bugfix: nginx counted incorrectly disk cache size. *) Change: now directive "gzip_disable msie6" does not disable gzipping for MSIE 6.0 SV1. *) Bugfix: nginx always added "Vary: Accept-Encoding" response header line, if both "gzip_static" and "gzip_vary" were on. *) Feature: the "proxy" parameter of the "geo" directive. *) Feature: the ngx_http_geoip_module. *) Feature: the "limit_rate_after" directive. Thanks to Ivan Debnar. *) Feature: the "limit_req_log_level" and "limit_conn_log_level" directives. *) Bugfix: now "limit_req" directive conforms to the leaky bucket algorithm. Thanks to Maxim Dounin. *) Bugfix: in ngx_http_limit_req_module. Thanks to Maxim Dounin. *) Bugfix: now nginx allows underscores in a request method. *) Bugfix: "proxy_pass_header" and "fastcgi_pass_header" directives did not pass to a client the "X-Accel-Redirect", "X-Accel-Limit-Rate", "X-Accel-Buffering", and "X-Accel-Charset" lines from backend response header. Thanks to Maxim Dounin. *) Bugfix: in handling "Last-Modified" and "Accept-Ranges" backend response header lines; the bug had appeared in 0.7.44. Thanks to Maxim Dounin. *) Feature: the "image_filter_transparency" directive. *) Feature: the "image_filter" directive supports variables for setting size. *) Bugfix: in PNG alpha-channel support in the ngx_http_image_filter_module. *) Bugfix: in transparency support in the ngx_http_image_filter_module. *) Feature: now several "perl_modules" directives may be used. *) Bugfix: ngx_http_perl_module responses did not work in subrequests. *) Bugfix: nginx sent '\0' in a "Location" response header line on MKCOL request. Thanks to Xie Zhenye. *) Bugfix: an "error_page" directive did not redirect a 413 error; the bug had appeared in 0.6.10. *) Bugfix: in memory allocation error handling. Thanks to Maxim Dounin and Kirill A. Korinskiy.
author Igor Sysoev <http://sysoev.ru>
date Mon, 26 Oct 2009 00:00:00 +0300
parents
children 68c0ae0a4959
comparison
equal deleted inserted replaced
501:dc87c92181c7 502:89dc5654117c
1
2 /*
3 * Copyright (C) Igor Sysoev
4 */
5
6
7 #include <ngx_config.h>
8 #include <ngx_core.h>
9 #include <ngx_http.h>
10
11 #include <GeoIP.h>
12 #include <GeoIPCity.h>
13
14
15 typedef struct {
16 GeoIP *country;
17 GeoIP *city;
18 } ngx_http_geoip_conf_t;
19
20
21 typedef struct {
22 ngx_str_t *name;
23 uintptr_t data;
24 } ngx_http_geoip_var_t;
25
26
27 typedef const char *(*ngx_http_geoip_variable_handler_pt)(GeoIP *, u_long addr);
28
29 static ngx_int_t ngx_http_geoip_country_variable(ngx_http_request_t *r,
30 ngx_http_variable_value_t *v, uintptr_t data);
31 static ngx_int_t ngx_http_geoip_city_variable(ngx_http_request_t *r,
32 ngx_http_variable_value_t *v, uintptr_t data);
33
34 static ngx_int_t ngx_http_geoip_add_variables(ngx_conf_t *cf);
35 static void *ngx_http_geoip_create_conf(ngx_conf_t *cf);
36 static char *ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd,
37 void *conf);
38 static char *ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd,
39 void *conf);
40 static void ngx_http_geoip_cleanup(void *data);
41
42
43 static ngx_command_t ngx_http_geoip_commands[] = {
44
45 { ngx_string("geoip_country"),
46 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
47 ngx_http_geoip_country,
48 NGX_HTTP_MAIN_CONF_OFFSET,
49 0,
50 NULL },
51
52 { ngx_string("geoip_city"),
53 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE1,
54 ngx_http_geoip_city,
55 NGX_HTTP_MAIN_CONF_OFFSET,
56 0,
57 NULL },
58
59 ngx_null_command
60 };
61
62
63 static ngx_http_module_t ngx_http_geoip_module_ctx = {
64 ngx_http_geoip_add_variables, /* preconfiguration */
65 NULL, /* postconfiguration */
66
67 ngx_http_geoip_create_conf, /* create main configuration */
68 NULL, /* init main configuration */
69
70 NULL, /* create server configuration */
71 NULL, /* merge server configuration */
72
73 NULL, /* create location configuration */
74 NULL /* merge location configuration */
75 };
76
77
78 ngx_module_t ngx_http_geoip_module = {
79 NGX_MODULE_V1,
80 &ngx_http_geoip_module_ctx, /* module context */
81 ngx_http_geoip_commands, /* module directives */
82 NGX_HTTP_MODULE, /* module type */
83 NULL, /* init master */
84 NULL, /* init module */
85 NULL, /* init process */
86 NULL, /* init thread */
87 NULL, /* exit thread */
88 NULL, /* exit process */
89 NULL, /* exit master */
90 NGX_MODULE_V1_PADDING
91 };
92
93
94 static ngx_http_variable_t ngx_http_geoip_vars[] = {
95
96 { ngx_string("geoip_country_code"), NULL, ngx_http_geoip_country_variable,
97 (uintptr_t) GeoIP_country_code_by_ipnum, 0, 0 },
98
99 { ngx_string("geoip_country_code3"), NULL, ngx_http_geoip_country_variable,
100 (uintptr_t) GeoIP_country_code3_by_ipnum, 0, 0 },
101
102 { ngx_string("geoip_country_name"), NULL, ngx_http_geoip_country_variable,
103 (uintptr_t) GeoIP_country_name_by_ipnum, 0, 0 },
104
105 { ngx_string("geoip_city_country_code"), NULL, ngx_http_geoip_city_variable,
106 offsetof(GeoIPRecord, country_code), 0, 0 },
107
108 { ngx_string("geoip_city_country_code3"), NULL,
109 ngx_http_geoip_city_variable,
110 offsetof(GeoIPRecord, country_code3), 0, 0 },
111
112 { ngx_string("geoip_city_country_name"), NULL, ngx_http_geoip_city_variable,
113 offsetof(GeoIPRecord, country_name), 0, 0 },
114
115 { ngx_string("geoip_region"), NULL,
116 ngx_http_geoip_city_variable,
117 offsetof(GeoIPRecord, region), 0, 0 },
118
119 { ngx_string("geoip_city"), NULL,
120 ngx_http_geoip_city_variable,
121 offsetof(GeoIPRecord, city), 0, 0 },
122
123 { ngx_string("geoip_postal_code"), NULL,
124 ngx_http_geoip_city_variable,
125 offsetof(GeoIPRecord, postal_code), 0, 0 },
126
127 { ngx_null_string, NULL, NULL, 0, 0, 0 }
128 };
129
130
131 static ngx_int_t
132 ngx_http_geoip_country_variable(ngx_http_request_t *r,
133 ngx_http_variable_value_t *v, uintptr_t data)
134 {
135 ngx_http_geoip_variable_handler_pt handler =
136 (ngx_http_geoip_variable_handler_pt) data;
137
138 u_long addr;
139 const char *val;
140 struct sockaddr_in *sin;
141 ngx_http_geoip_conf_t *gcf;
142
143 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
144
145 if (gcf->country == NULL) {
146 goto not_found;
147 }
148
149 if (r->connection->sockaddr->sa_family != AF_INET) {
150 goto not_found;
151 }
152
153 sin = (struct sockaddr_in *) r->connection->sockaddr;
154 addr = ntohl(sin->sin_addr.s_addr);
155
156 val = handler(gcf->country, addr);
157
158 if (val == NULL) {
159 goto not_found;
160 }
161
162 v->len = ngx_strlen(val);
163 v->valid = 1;
164 v->no_cacheable = 0;
165 v->not_found = 0;
166 v->data = (u_char *) val;
167
168 return NGX_OK;
169
170 not_found:
171
172 v->not_found = 1;
173
174 return NGX_OK;
175 }
176
177
178 static ngx_int_t
179 ngx_http_geoip_city_variable(ngx_http_request_t *r,
180 ngx_http_variable_value_t *v, uintptr_t data)
181 {
182 u_long addr;
183 char *val;
184 size_t len;
185 GeoIPRecord *gr;
186 struct sockaddr_in *sin;
187 ngx_http_geoip_conf_t *gcf;
188
189 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
190
191 if (gcf->city == NULL) {
192 goto not_found;
193 }
194
195 if (r->connection->sockaddr->sa_family != AF_INET) {
196 goto not_found;
197 }
198
199 sin = (struct sockaddr_in *) r->connection->sockaddr;
200 addr = ntohl(sin->sin_addr.s_addr);
201
202 gr = GeoIP_record_by_ipnum(gcf->city, addr);
203
204 if (gr == NULL) {
205 goto not_found;
206 }
207
208 val = *(char **) ((char *) gr + data);
209
210 if (val == NULL) {
211 goto no_value;
212 }
213
214 len = ngx_strlen(val);
215 v->data = ngx_pnalloc(r->pool, len);
216
217 if (v->data == NULL) {
218 GeoIPRecord_delete(gr);
219 return NGX_ERROR;
220 }
221
222 ngx_memcpy(v->data, val, len);
223
224 v->len = len;
225 v->valid = 1;
226 v->no_cacheable = 0;
227 v->not_found = 0;
228
229 GeoIPRecord_delete(gr);
230
231 return NGX_OK;
232
233 no_value:
234
235 GeoIPRecord_delete(gr);
236
237 not_found:
238
239 v->not_found = 1;
240
241 return NGX_OK;
242 }
243
244
245 static ngx_int_t
246 ngx_http_geoip_add_variables(ngx_conf_t *cf)
247 {
248 ngx_http_variable_t *var, *v;
249
250 for (v = ngx_http_geoip_vars; v->name.len; v++) {
251 var = ngx_http_add_variable(cf, &v->name, v->flags);
252 if (var == NULL) {
253 return NGX_ERROR;
254 }
255
256 var->get_handler = v->get_handler;
257 var->data = v->data;
258 }
259
260 return NGX_OK;
261 }
262
263
264 static void *
265 ngx_http_geoip_create_conf(ngx_conf_t *cf)
266 {
267 ngx_pool_cleanup_t *cln;
268 ngx_http_geoip_conf_t *conf;
269
270 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
271 if (conf == NULL) {
272 return NULL;
273 }
274
275 cln = ngx_pool_cleanup_add(cf->pool, 0);
276 if (cln == NULL) {
277 return NULL;
278 }
279
280 cln->handler = ngx_http_geoip_cleanup;
281 cln->data = conf;
282
283 return conf;
284 }
285
286
287 static char *
288 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
289 {
290 ngx_http_geoip_conf_t *gcf = conf;
291
292 ngx_str_t *value;
293
294 if (gcf->country) {
295 return "is duplicate";
296 }
297
298 value = cf->args->elts;
299
300 gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
301
302 if (gcf->country == NULL) {
303 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
304 "GeoIO_open(\"%V\") failed", &value[1]);
305
306 return NGX_CONF_ERROR;
307 }
308
309 switch (gcf->country->databaseType) {
310
311 case GEOIP_COUNTRY_EDITION:
312 case GEOIP_PROXY_EDITION:
313 case GEOIP_NETSPEED_EDITION:
314
315 return NGX_CONF_OK;
316
317 default:
318 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
319 "invalid GeoIP database \"%V\" type:%d",
320 &value[1], gcf->country->databaseType);
321 return NGX_CONF_ERROR;
322 }
323 }
324
325
326 static char *
327 ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
328 {
329 ngx_http_geoip_conf_t *gcf = conf;
330
331 ngx_str_t *value;
332
333 if (gcf->city) {
334 return "is duplicate";
335 }
336
337 value = cf->args->elts;
338
339 gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
340
341 if (gcf->city == NULL) {
342 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
343 "GeoIO_open(\"%V\") failed", &value[1]);
344
345 return NGX_CONF_ERROR;
346 }
347
348 switch (gcf->city->databaseType) {
349
350 case GEOIP_CITY_EDITION_REV0:
351 case GEOIP_CITY_EDITION_REV1:
352
353 return NGX_CONF_OK;
354
355 default:
356 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
357 "invalid GeoIP City database \"%V\" type:%d",
358 &value[1], gcf->city->databaseType);
359 return NGX_CONF_ERROR;
360 }
361 }
362
363
364 static void
365 ngx_http_geoip_cleanup(void *data)
366 {
367 ngx_http_geoip_conf_t *gcf = data;
368
369 if (gcf->country) {
370 GeoIP_delete(gcf->country);
371 }
372
373 if (gcf->city) {
374 GeoIP_delete(gcf->city);
375 }
376 }