Klaus Demo nginx / 4c80459
ancient browsers support in ngx_http_browser_module Igor Sysoev 15 years ago
1 changed file(s) with 289 addition(s) and 131 deletion(s). Raw diff Collapse all Expand all
1313 * X, X.X, X.X.X, and X.X.X.X. The maximum values of each format may be
1414 * 4000, 4000.99, 4000.99.99, and 4000.99.99.99.
1515 */
16
17
18 #define NGX_HTTP_MODERN_BROWSER 0
19 #define NGX_HTTP_ANCIENT_BROWSER 1
1620
1721
1822 typedef struct {
3438 typedef struct {
3539 ngx_str_t name;
3640 ngx_http_get_variable_pt handler;
37 } ngx_http_browser_t;
41 uintptr_t data;
42 } ngx_http_browser_variable_t;
3843
3944
4045 typedef struct {
4146 ngx_array_t *modern_browsers;
42 ngx_http_variable_value_t *value;
47 ngx_array_t *ancient_browsers;
48 ngx_http_variable_value_t *modern_browser_value;
49 ngx_http_variable_value_t *ancient_browser_value;
50
51 unsigned modern_unlisted_browsers:1;
52 unsigned netscape4:1;
4353 } ngx_http_browser_conf_t;
4454
4555
4656 static ngx_int_t ngx_http_msie_variable(ngx_http_request_t *r,
4757 ngx_http_variable_value_t *v, uintptr_t data);
58 static ngx_int_t ngx_http_browser_variable(ngx_http_request_t *r,
59 ngx_http_variable_value_t *v, uintptr_t data);
60
61 static ngx_uint_t ngx_http_browser(ngx_http_request_t *r,
62 ngx_http_browser_conf_t *cf);
63
4864 static ngx_int_t ngx_http_browser_add_variable(ngx_conf_t *cf);
4965 static void *ngx_http_browser_create_conf(ngx_conf_t *cf);
5066 static char *ngx_http_browser_merge_conf(ngx_conf_t *cf, void *parent,
5369 const void *two);
5470 static char *ngx_http_modern_browser(ngx_conf_t *cf, ngx_command_t *cmd,
5571 void *conf);
72 static char *ngx_http_ancient_browser(ngx_conf_t *cf, ngx_command_t *cmd,
73 void *conf);
5674 static char *ngx_http_modern_browser_value(ngx_conf_t *cf, ngx_command_t *cmd,
5775 void *conf);
76 static char *ngx_http_ancient_browser_value(ngx_conf_t *cf, ngx_command_t *cmd,
77 void *conf);
5878
5979
6080 static ngx_command_t ngx_http_browser_commands[] = {
6181
6282 { ngx_string("modern_browser"),
63 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2,
83 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12,
6484 ngx_http_modern_browser,
6585 NGX_HTTP_LOC_CONF_OFFSET,
6686 0,
6787 NULL },
6888
89 { ngx_string("ancient_browser"),
90 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_1MORE,
91 ngx_http_ancient_browser,
92 NGX_HTTP_LOC_CONF_OFFSET,
93 0,
94 NULL },
95
6996 { ngx_string("modern_browser_value"),
7097 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
7198 ngx_http_modern_browser_value,
99 NGX_HTTP_LOC_CONF_OFFSET,
100 0,
101 NULL },
102
103 { ngx_string("ancient_browser_value"),
104 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
105 ngx_http_ancient_browser_value,
72106 NGX_HTTP_LOC_CONF_OFFSET,
73107 0,
74108 NULL },
182216 };
183217
184218
185 static ngx_http_browser_t ngx_http_browsers[] = {
186 { ngx_string("msie"), ngx_http_msie_variable },
187 { ngx_null_string, NULL }
219 static ngx_http_browser_variable_t ngx_http_browsers[] = {
220 { ngx_string("msie"), ngx_http_msie_variable, 0 },
221 { ngx_string("modern_browser"), ngx_http_browser_variable,
222 NGX_HTTP_MODERN_BROWSER },
223 { ngx_string("ancient_browser"), ngx_http_browser_variable,
224 NGX_HTTP_ANCIENT_BROWSER },
225 { ngx_null_string, NULL, 0 }
188226 };
189227
190228
192230 ngx_http_browser_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
193231 uintptr_t data)
194232 {
233 ngx_uint_t rc;
234 ngx_http_browser_conf_t *cf;
235
236 cf = ngx_http_get_module_loc_conf(r, ngx_http_browser_module);
237
238 rc = ngx_http_browser(r, cf);
239
240 if (data == NGX_HTTP_MODERN_BROWSER && rc == NGX_HTTP_MODERN_BROWSER) {
241 *v = *cf->modern_browser_value;
242 return NGX_OK;
243 }
244
245 if (data == NGX_HTTP_ANCIENT_BROWSER && rc == NGX_HTTP_ANCIENT_BROWSER) {
246 *v = *cf->ancient_browser_value;
247 return NGX_OK;
248 }
249
250 *v = ngx_http_variable_null_value;
251 return NGX_OK;
252 }
253
254
255 static ngx_uint_t
256 ngx_http_browser(ngx_http_request_t *r, ngx_http_browser_conf_t *cf)
257 {
258 size_t len;
195259 u_char *name, *ua, *last, c;
260 ngx_str_t *ancient;
196261 ngx_uint_t i, version, ver, scale;
197 ngx_http_browser_conf_t *cf;
198 ngx_http_modern_browser_t *browsers;
199
200 cf = ngx_http_get_module_loc_conf(r, ngx_http_browser_module);
201
202 if (cf->modern_browsers == NULL || cf->value == NULL) {
203 *v = ngx_http_variable_null_value;
204 return NGX_OK;
205 }
206
207 #if 0
208 if (!r->headers_in.msie && !r->headers_in.opera
209 && !r->headers_in.gecko && !r->headers_in.konqueror)
210 {
211 *v = ngx_http_variable_null_value;
212 return NGX_OK;
213 }
214 #endif
262 ngx_http_modern_browser_t *modern;
215263
216264 if (r->headers_in.user_agent == NULL) {
217 *v = ngx_http_variable_null_value;
218 return NGX_OK;
219 }
220
265 if (cf->modern_unlisted_browsers) {
266 return NGX_HTTP_MODERN_BROWSER;
267 }
268
269 return NGX_HTTP_ANCIENT_BROWSER;
270 }
221271
222272 ua = r->headers_in.user_agent->value.data;
223 last = ua + r->headers_in.user_agent->value.len;
224
225 browsers = cf->modern_browsers->elts;
226
227 for (i = 0; i < cf->modern_browsers->nelts; i++) {
228 name = ua + browsers[i].skip;
229
230 if (name >= last) {
231 continue;
232 }
233
234 name = (u_char *) ngx_strstr(name, browsers[i].name);
235
236 if (name == NULL) {
237 continue;
238 }
239
240 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
241 "browser: \"%s\"", name);
242
243 name += browsers[i].add;
244
245 if (name >= last) {
246 continue;
247 }
248
249 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
250 "version: \"%ui\" \"%s\"", browsers[i].version, name);
251
252 version = 0;
253 ver = 0;
254 scale = 1000000;
255
256 while (name < last) {
257
258 c = *name++;
259
260 if (c >= '0' && c <= '9') {
261 ver = ver * 10 + (c - '0');
273 len = r->headers_in.user_agent->value.len;
274 last = ua + len;
275
276 if (cf->modern_browsers) {
277 modern = cf->modern_browsers->elts;
278
279 for (i = 0; i < cf->modern_browsers->nelts; i++) {
280 name = ua + modern[i].skip;
281
282 if (name >= last) {
262283 continue;
263284 }
264285
265 if (c == '.') {
266 version += ver * scale;
267
268 if (version > browsers[i].version) {
269 *v = *cf->value;
270 return NGX_OK;
271 }
272
273 ver = 0;
274 scale /= 100;
286 name = (u_char *) ngx_strstr(name, modern[i].name);
287
288 if (name == NULL) {
275289 continue;
276290 }
277291
278 break;
279 }
280
281 version += ver * scale;
282
283 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
284 "version: \"%ui\" \"%ui\"",
285 browsers[i].version, version);
286
287 if (version >= browsers[i].version) {
288 *v = *cf->value;
289 return NGX_OK;
290 }
291 }
292
293 *v = ngx_http_variable_null_value;
294
295 return NGX_OK;
292 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
293 "browser: \"%s\"", name);
294
295 name += modern[i].add;
296
297 if (name >= last) {
298 continue;
299 }
300
301 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
302 "version: \"%ui\" \"%s\"", modern[i].version, name);
303
304 version = 0;
305 ver = 0;
306 scale = 1000000;
307
308 while (name < last) {
309
310 c = *name++;
311
312 if (c >= '0' && c <= '9') {
313 ver = ver * 10 + (c - '0');
314 continue;
315 }
316
317 if (c == '.') {
318 version += ver * scale;
319
320 if (version > modern[i].version) {
321 return NGX_HTTP_MODERN_BROWSER;
322 }
323
324 ver = 0;
325 scale /= 100;
326 continue;
327 }
328
329 break;
330 }
331
332 version += ver * scale;
333
334 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
335 "version: \"%ui\" \"%ui\"",
336 modern[i].version, version);
337
338 if (version >= modern[i].version) {
339 return NGX_HTTP_MODERN_BROWSER;
340 }
341 }
342
343 if (!cf->modern_unlisted_browsers) {
344 return NGX_HTTP_ANCIENT_BROWSER;
345 }
346 }
347
348 if (cf->netscape4) {
349 if (len > sizeof("Mozilla/4.72 ") - 1
350 && ngx_strncmp(ua, "Mozilla/", sizeof("Mozilla/") - 1) == 0
351 && ua[8] > '0' && ua[8] < '5')
352 {
353 return NGX_HTTP_ANCIENT_BROWSER;
354 }
355 }
356
357 if (cf->ancient_browsers) {
358 ancient = cf->ancient_browsers->elts;
359
360 for (i = 0; i < cf->ancient_browsers->nelts; i++) {
361 if (len >= ancient[i].len
362 && ngx_strstr(ua, ancient[i].data) != NULL)
363 {
364 return NGX_HTTP_ANCIENT_BROWSER;
365 }
366 }
367 }
368
369 if (cf->modern_unlisted_browsers) {
370 return NGX_HTTP_MODERN_BROWSER;
371 }
372
373 return NGX_HTTP_ANCIENT_BROWSER;
296374 }
297375
298376
302380 {
303381 if (r->headers_in.msie) {
304382 *v = ngx_http_variable_true_value;
305
306383 return NGX_OK;
307384 }
308385
309386 *v = ngx_http_variable_null_value;
310
311387 return NGX_OK;
312388 }
313389
315391 static ngx_int_t
316392 ngx_http_browser_add_variable(ngx_conf_t *cf)
317393 {
318 ngx_http_browser_t *browser;
319 ngx_http_variable_t *var;
320
321 for (browser = ngx_http_browsers; browser->name.len; browser++) {
322
323 var = ngx_http_add_variable(cf, &browser->name, NGX_HTTP_VAR_CHANGABLE);
324 if (var == NULL) {
394 ngx_http_browser_variable_t *var;
395 ngx_http_variable_t *v;
396
397 for (var = ngx_http_browsers; var->name.len; var++) {
398
399 v = ngx_http_add_variable(cf, &var->name, NGX_HTTP_VAR_CHANGABLE);
400 if (v == NULL) {
325401 return NGX_ERROR;
326402 }
327403
328 var->get_handler = browser->handler;
404 v->get_handler = var->handler;
405 v->data = var->data;
329406 }
330407
331408 return NGX_OK;
345422 /*
346423 * set by ngx_pcalloc():
347424 *
348 * conf->browsers = NULL;
349 * conf->value = NULL;
425 * conf->modern_browsers = NULL;
426 * conf->ancient_browsers = NULL;
427 * conf->modern_browser_value = NULL;
428 * conf->ancient_browser_value = NULL;
429 *
430 * conf->modern_unlisted_browsers = 0;
431 * conf->netscape4 = 0;
350432 */
351433
352434 return conf;
411493 }
412494 }
413495
414 if (conf->value == NULL) {
415 conf->value = prev->value;
496 if (conf->ancient_browsers == NULL) {
497 conf->ancient_browsers = prev->ancient_browsers;
498 }
499
500 if (conf->modern_browser_value == NULL) {
501 conf->modern_browser_value = prev->modern_browser_value;
502 }
503
504 if (conf->modern_browser_value == NULL) {
505 conf->modern_browser_value = &ngx_http_variable_true_value;
506 }
507
508 if (conf->ancient_browser_value == NULL) {
509 conf->ancient_browser_value = prev->ancient_browser_value;
510 }
511
512 if (conf->ancient_browser_value == NULL) {
513 conf->ancient_browser_value = &ngx_http_variable_true_value;
416514 }
417515
418516 return NGX_CONF_OK;
440538 ngx_http_modern_browser_t *browser;
441539 ngx_http_modern_browser_mask_t *mask;
442540
541 value = cf->args->elts;
542
543 if (cf->args->nelts == 2) {
544 if (ngx_strcmp(value[1].data, "unlisted") == 0) {
545 bcf->modern_unlisted_browsers = 1;
546 return NGX_CONF_OK;
547 }
548
549 return NGX_CONF_ERROR;
550 }
551
443552 if (bcf->modern_browsers == NULL) {
444 bcf->modern_browsers = ngx_array_create(cf->pool, 4,
553 bcf->modern_browsers = ngx_array_create(cf->pool, 5,
445554 sizeof(ngx_http_modern_browser_t));
446555 if (bcf->modern_browsers == NULL) {
447556 return NGX_CONF_ERROR;
452561 if (browser == NULL) {
453562 return NGX_CONF_ERROR;
454563 }
455
456 value = cf->args->elts;
457564
458565 mask = ngx_http_modern_browser_masks;
459566
513620
514621
515622 static char *
623 ngx_http_ancient_browser(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
624 {
625 ngx_http_browser_conf_t *bcf = conf;
626
627 ngx_str_t *value, *browser;
628 ngx_uint_t i;
629
630 value = cf->args->elts;
631
632 for (i = 1; i < cf->args->nelts; i++) {
633 if (ngx_strcmp(value[i].data, "netscape4") == 0) {
634 bcf->netscape4 = 1;
635 continue;
636 }
637
638 if (bcf->ancient_browsers == NULL) {
639 bcf->ancient_browsers = ngx_array_create(cf->pool, 4,
640 sizeof(ngx_str_t));
641 if (bcf->ancient_browsers == NULL) {
642 return NGX_CONF_ERROR;
643 }
644 }
645
646 browser = ngx_array_push(bcf->ancient_browsers);
647 if (browser == NULL) {
648 return NGX_CONF_ERROR;
649 }
650
651 *browser = value[i];
652 }
653
654 return NGX_CONF_OK;
655 }
656
657
658 static char *
516659 ngx_http_modern_browser_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
517660 {
518661 ngx_http_browser_conf_t *bcf = conf;
519662
520 ngx_str_t *value, name;
521 ngx_http_variable_t *var;
663 ngx_str_t *value;
664
665 bcf->modern_browser_value = ngx_palloc(cf->pool,
666 sizeof(ngx_http_variable_value_t));
667 if (bcf->modern_browser_value == NULL) {
668 return NGX_CONF_ERROR;
669 }
522670
523671 value = cf->args->elts;
524672
525 name.len = sizeof("browser") - 1;
526 name.data = (u_char *) "browser";
527
528 var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGABLE);
529 if (var == NULL) {
673 bcf->modern_browser_value->len = value[1].len;
674 bcf->modern_browser_value->valid = 1;
675 bcf->modern_browser_value->no_cachable = 0;
676 bcf->modern_browser_value->not_found = 0;
677 bcf->modern_browser_value->data = value[1].data;
678
679 return NGX_CONF_OK;
680 }
681
682
683 static char *
684 ngx_http_ancient_browser_value(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
685 {
686 ngx_http_browser_conf_t *bcf = conf;
687
688 ngx_str_t *value;
689
690 bcf->ancient_browser_value = ngx_palloc(cf->pool,
691 sizeof(ngx_http_variable_value_t));
692 if (bcf->ancient_browser_value == NULL) {
530693 return NGX_CONF_ERROR;
531694 }
532695
533 var->get_handler = ngx_http_browser_variable;
534
535 bcf->value = ngx_palloc(cf->pool, sizeof(ngx_http_variable_value_t));
536 if (bcf->value == NULL) {
537 return NGX_CONF_ERROR;
538 }
539
540 bcf->value->len = value[1].len;
541 bcf->value->valid = 1;
542 bcf->value->no_cachable = 0;
543 bcf->value->not_found = 0;
544 bcf->value->data = value[1].data;
696 value = cf->args->elts;
697
698 bcf->ancient_browser_value->len = value[1].len;
699 bcf->ancient_browser_value->valid = 1;
700 bcf->ancient_browser_value->no_cachable = 0;
701 bcf->ancient_browser_value->not_found = 0;
702 bcf->ancient_browser_value->data = value[1].data;
545703
546704 return NGX_CONF_OK;
547705 }