comparison src/http/modules/ngx_http_geoip_module.c @ 518:4b0d7f0bf22b NGINX_0_8_6

nginx 0.8.6 *) Feature: the ngx_http_geoip_module. *) Bugfix: XSLT filter may fail with message "not well formed XML document" for valid XML document. Thanks to Kuramoto Eiji. *) Bugfix: now in MacOSX, Cygwin, and nginx/Windows locations given by a regular expression are always tested in case insensitive mode; *) Bugfix: now nginx/Windows ignores trailing dots in URI. Thanks to Hugo Leisink. *) Bugfix: name of file specified in --conf-path was not honored during installation; the bug had appeared in 0.6.6. Thanks to Maxim Dounin.
author Igor Sysoev <http://sysoev.ru>
date Mon, 20 Jul 2009 00:00:00 +0400
parents
children 7efcdb937752
comparison
equal deleted inserted replaced
516:0001f4fa0501 518:4b0d7f0bf22b
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 GeoIPRecord *gr;
185 struct sockaddr_in *sin;
186 ngx_http_geoip_conf_t *gcf;
187
188 gcf = ngx_http_get_module_main_conf(r, ngx_http_geoip_module);
189
190 if (gcf->city == NULL) {
191 goto not_found;
192 }
193
194 if (r->connection->sockaddr->sa_family != AF_INET) {
195 goto not_found;
196 }
197
198 sin = (struct sockaddr_in *) r->connection->sockaddr;
199 addr = ntohl(sin->sin_addr.s_addr);
200
201 gr = GeoIP_record_by_ipnum(gcf->city, addr);
202
203 if (gr == NULL) {
204 goto not_found;
205 }
206
207 val = *(char **) ((char *) gr + data);
208
209 if (val == NULL) {
210 goto not_found;
211 }
212
213 v->len = ngx_strlen(val);
214 v->valid = 1;
215 v->no_cacheable = 0;
216 v->not_found = 0;
217 v->data = (u_char *) val;
218
219 return NGX_OK;
220
221 not_found:
222
223 v->not_found = 1;
224
225 return NGX_OK;
226 }
227
228
229 static ngx_int_t
230 ngx_http_geoip_add_variables(ngx_conf_t *cf)
231 {
232 ngx_http_variable_t *var, *v;
233
234 for (v = ngx_http_geoip_vars; v->name.len; v++) {
235 var = ngx_http_add_variable(cf, &v->name, v->flags);
236 if (var == NULL) {
237 return NGX_ERROR;
238 }
239
240 var->get_handler = v->get_handler;
241 var->data = v->data;
242 }
243
244 return NGX_OK;
245 }
246
247
248 static void *
249 ngx_http_geoip_create_conf(ngx_conf_t *cf)
250 {
251 ngx_pool_cleanup_t *cln;
252 ngx_http_geoip_conf_t *conf;
253
254 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_geoip_conf_t));
255 if (conf == NULL) {
256 return NULL;
257 }
258
259 cln = ngx_pool_cleanup_add(cf->pool, 0);
260 if (cln == NULL) {
261 return NULL;
262 }
263
264 cln->handler = ngx_http_geoip_cleanup;
265 cln->data = conf;
266
267 return conf;
268 }
269
270
271 static char *
272 ngx_http_geoip_country(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
273 {
274 ngx_http_geoip_conf_t *gcf = conf;
275
276 ngx_str_t *value;
277
278 if (gcf->country) {
279 return "is duplicate";
280 }
281
282 value = cf->args->elts;
283
284 gcf->country = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
285
286 if (gcf->country == NULL) {
287 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
288 "GeoIO_open(\"%V\") failed", &value[1]);
289
290 return NGX_CONF_ERROR;
291 }
292
293 switch (gcf->country->databaseType) {
294
295 case GEOIP_COUNTRY_EDITION:
296 case GEOIP_PROXY_EDITION:
297 case GEOIP_NETSPEED_EDITION:
298
299 return NGX_CONF_OK;
300
301 default:
302 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
303 "invalid GeoIP database \"%V\" type:%d",
304 &value[1], gcf->country->databaseType);
305 return NGX_CONF_ERROR;
306 }
307 }
308
309
310 static char *
311 ngx_http_geoip_city(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
312 {
313 ngx_http_geoip_conf_t *gcf = conf;
314
315 ngx_str_t *value;
316
317 if (gcf->city) {
318 return "is duplicate";
319 }
320
321 value = cf->args->elts;
322
323 gcf->city = GeoIP_open((char *) value[1].data, GEOIP_MEMORY_CACHE);
324
325 if (gcf->city == NULL) {
326 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
327 "GeoIO_open(\"%V\") failed", &value[1]);
328
329 return NGX_CONF_ERROR;
330 }
331
332 switch (gcf->city->databaseType) {
333
334 case GEOIP_CITY_EDITION_REV0:
335 case GEOIP_CITY_EDITION_REV1:
336
337 return NGX_CONF_OK;
338
339 default:
340 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
341 "invalid GeoIP City database \"%V\" type:%d",
342 &value[1], gcf->city->databaseType);
343 return NGX_CONF_ERROR;
344 }
345 }
346
347
348 static void
349 ngx_http_geoip_cleanup(void *data)
350 {
351 ngx_http_geoip_conf_t *gcf = data;
352
353 if (gcf->country) {
354 GeoIP_delete(gcf->country);
355 }
356
357 if (gcf->city) {
358 GeoIP_delete(gcf->city);
359 }
360 }