comparison src/http/modules/ngx_http_userid_filter_module.c @ 582:c456a023113c NGINX_0_8_43

nginx 0.8.43 *) Feature: large geo ranges base loading speed-up. *) Bugfix: an error_page redirection to "location /zero { return 204; }" without changing status code kept the error body; the bug had appeared in 0.8.42. *) Bugfix: nginx might close IPv6 listen socket during reconfiguration. Thanks to Maxim Dounin. *) Bugfix: the $uid_set variable may be used at any request processing stage.
author Igor Sysoev <http://sysoev.ru>
date Wed, 30 Jun 2010 00:00:00 +0400
parents ff463db0be31
children ad6fee8052d7
comparison
equal deleted inserted replaced
581:22b2345b75d9 582:c456a023113c
44 static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r, 44 static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r,
45 ngx_http_userid_conf_t *conf); 45 ngx_http_userid_conf_t *conf);
46 static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, 46 static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r,
47 ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid); 47 ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid);
48 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, 48 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,
49 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
50 static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r,
49 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); 51 ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
50 52
51 static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf); 53 static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf);
52 static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf); 54 static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf);
53 static void *ngx_http_userid_create_conf(ngx_conf_t *cf); 55 static void *ngx_http_userid_create_conf(ngx_conf_t *cf);
197 return ngx_http_next_header_filter(r); 199 return ngx_http_next_header_filter(r);
198 } 200 }
199 201
200 conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); 202 conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
201 203
202 if (conf->enable <= NGX_HTTP_USERID_LOG) { 204 if (conf->enable < NGX_HTTP_USERID_V1) {
203 return ngx_http_next_header_filter(r); 205 return ngx_http_next_header_filter(r);
204 } 206 }
205 207
206 ctx = ngx_http_userid_get_uid(r, conf); 208 ctx = ngx_http_userid_get_uid(r, conf);
207 209
208 if (ctx == NULL) { 210 if (ctx == NULL) {
209 return NGX_ERROR; 211 return NGX_ERROR;
210 } 212 }
211
212 if (ctx->uid_got[3] != 0) {
213
214 if (conf->mark == '\0') {
215 return ngx_http_next_header_filter(r);
216
217 } else {
218 if (ctx->cookie.len > 23
219 && ctx->cookie.data[22] == conf->mark
220 && ctx->cookie.data[23] == '=')
221 {
222 return ngx_http_next_header_filter(r);
223 }
224 }
225 }
226
227 /* ctx->status == NGX_DECLINED */
228 213
229 if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) { 214 if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) {
230 return ngx_http_next_header_filter(r); 215 return ngx_http_next_header_filter(r);
231 } 216 }
232 217
246 if (conf->enable == NGX_HTTP_USERID_OFF) { 231 if (conf->enable == NGX_HTTP_USERID_OFF) {
247 v->not_found = 1; 232 v->not_found = 1;
248 return NGX_OK; 233 return NGX_OK;
249 } 234 }
250 235
251 ctx = ngx_http_userid_get_uid(r, conf); 236 ctx = ngx_http_userid_get_uid(r->main, conf);
252 237
253 if (ctx == NULL) { 238 if (ctx == NULL) {
254 return NGX_ERROR; 239 return NGX_ERROR;
255 } 240 }
256 241
257 if (ctx->uid_got[3] != 0) { 242 if (ctx->uid_got[3] != 0) {
258 return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_got); 243 return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_got);
259 } 244 }
260
261 /* ctx->status == NGX_DECLINED */
262 245
263 v->not_found = 1; 246 v->not_found = 1;
264 247
265 return NGX_OK; 248 return NGX_OK;
266 } 249 }
271 ngx_http_variable_value_t *v, uintptr_t data) 254 ngx_http_variable_value_t *v, uintptr_t data)
272 { 255 {
273 ngx_http_userid_ctx_t *ctx; 256 ngx_http_userid_ctx_t *ctx;
274 ngx_http_userid_conf_t *conf; 257 ngx_http_userid_conf_t *conf;
275 258
276 ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); 259 conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
277 260
278 if (ctx == NULL || ctx->uid_set[3] == 0) { 261 if (conf->enable < NGX_HTTP_USERID_V1) {
279 v->not_found = 1; 262 v->not_found = 1;
280 return NGX_OK; 263 return NGX_OK;
281 } 264 }
282 265
283 conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); 266 ctx = ngx_http_userid_get_uid(r->main, conf);
284 267
285 return ngx_http_userid_variable(r, v, &conf->name, ctx->uid_set); 268 if (ctx == NULL) {
269 return NGX_ERROR;
270 }
271
272 if (ngx_http_userid_create_uid(r->main, ctx, conf) != NGX_OK) {
273 return NGX_ERROR;
274 }
275
276 if (ctx->uid_set[3] == 0) {
277 v->not_found = 1;
278 return NGX_OK;
279 }
280
281 return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_set);
286 } 282 }
287 283
288 284
289 static ngx_http_userid_ctx_t * 285 static ngx_http_userid_ctx_t *
290 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) 286 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
358 354
359 static ngx_int_t 355 static ngx_int_t
360 ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, 356 ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
361 ngx_http_userid_conf_t *conf) 357 ngx_http_userid_conf_t *conf)
362 { 358 {
363 u_char *cookie, *p; 359 u_char *cookie, *p;
364 size_t len; 360 size_t len;
365 ngx_str_t src, dst; 361 ngx_str_t src, dst;
366 ngx_table_elt_t *set_cookie, *p3p; 362 ngx_table_elt_t *set_cookie, *p3p;
363
364 if (ngx_http_userid_create_uid(r, ctx, conf) != NGX_OK) {
365 return NGX_ERROR;
366 }
367
368 if (ctx->uid_set[3] == 0) {
369 return NGX_OK;
370 }
371
372 len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
373
374 if (conf->expires) {
375 len += sizeof(expires) - 1 + 2;
376 }
377
378 if (conf->domain.len) {
379 len += conf->domain.len;
380 }
381
382 cookie = ngx_pnalloc(r->pool, len);
383 if (cookie == NULL) {
384 return NGX_ERROR;
385 }
386
387 p = ngx_copy(cookie, conf->name.data, conf->name.len);
388 *p++ = '=';
389
390 if (ctx->uid_got[3] == 0) {
391 src.len = 16;
392 src.data = (u_char *) ctx->uid_set;
393 dst.data = p;
394
395 ngx_encode_base64(&dst, &src);
396
397 p += dst.len;
398
399 if (conf->mark) {
400 *(p - 2) = conf->mark;
401 }
402
403 } else {
404 p = ngx_cpymem(p, ctx->cookie.data, 22);
405 *p++ = conf->mark;
406 *p++ = '=';
407 }
408
409 if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) {
410 p = ngx_cpymem(p, expires, sizeof(expires) - 1);
411
412 } else if (conf->expires) {
413 p = ngx_cpymem(p, expires, sizeof("; expires=") - 1);
414 p = ngx_http_cookie_time(p, ngx_time() + conf->expires);
415 }
416
417 p = ngx_copy(p, conf->domain.data, conf->domain.len);
418
419 p = ngx_copy(p, conf->path.data, conf->path.len);
420
421 set_cookie = ngx_list_push(&r->headers_out.headers);
422 if (set_cookie == NULL) {
423 return NGX_ERROR;
424 }
425
426 set_cookie->hash = 1;
427 ngx_str_set(&set_cookie->key, "Set-Cookie");
428 set_cookie->value.len = p - cookie;
429 set_cookie->value.data = cookie;
430
431 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
432 "uid cookie: \"%V\"", &set_cookie->value);
433
434 if (conf->p3p.len == 0) {
435 return NGX_OK;
436 }
437
438 p3p = ngx_list_push(&r->headers_out.headers);
439 if (p3p == NULL) {
440 return NGX_ERROR;
441 }
442
443 p3p->hash = 1;
444 ngx_str_set(&p3p->key, "P3P");
445 p3p->value = conf->p3p;
446
447 return NGX_OK;
448 }
449
450
451 static ngx_int_t
452 ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
453 ngx_http_userid_conf_t *conf)
454 {
367 ngx_connection_t *c; 455 ngx_connection_t *c;
368 struct sockaddr_in *sin; 456 struct sockaddr_in *sin;
369 #if (NGX_HAVE_INET6) 457 #if (NGX_HAVE_INET6)
458 u_char *p;
370 struct sockaddr_in6 *sin6; 459 struct sockaddr_in6 *sin6;
371 #endif 460 #endif
461
462 if (ctx->uid_set[3] != 0) {
463 return NGX_OK;
464 }
465
466 if (ctx->uid_got[3] != 0) {
467
468 if (conf->mark == '\0'
469 || (ctx->cookie.len > 23
470 && ctx->cookie.data[22] == conf->mark
471 && ctx->cookie.data[23] == '='))
472 {
473 return NGX_OK;
474 }
475
476 ctx->uid_set[0] = ctx->uid_got[0];
477 ctx->uid_set[1] = ctx->uid_got[1];
478 ctx->uid_set[2] = ctx->uid_got[2];
479 ctx->uid_set[3] = ctx->uid_got[3];
480
481 return NGX_OK;
482 }
372 483
373 /* 484 /*
374 * TODO: in the threaded mode the sequencers should be in TLS and their 485 * TODO: in the threaded mode the sequencers should be in TLS and their
375 * ranges should be divided between threads 486 * ranges should be divided between threads
376 */ 487 */
377 488
378 if (ctx->uid_got[3] == 0) { 489 if (conf->enable == NGX_HTTP_USERID_V1) {
379 490 if (conf->service == NGX_CONF_UNSET) {
380 if (conf->enable == NGX_HTTP_USERID_V1) { 491 ctx->uid_set[0] = 0;
381 if (conf->service == NGX_CONF_UNSET) { 492 } else {
382 ctx->uid_set[0] = 0; 493 ctx->uid_set[0] = conf->service;
383 } else { 494 }
384 ctx->uid_set[0] = conf->service; 495 ctx->uid_set[1] = (uint32_t) ngx_time();
496 ctx->uid_set[2] = start_value;
497 ctx->uid_set[3] = sequencer_v1;
498 sequencer_v1 += 0x100;
499
500 } else {
501 if (conf->service == NGX_CONF_UNSET) {
502
503 c = r->connection;
504
505 if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
506 return NGX_ERROR;
385 } 507 }
386 ctx->uid_set[1] = (uint32_t) ngx_time(); 508
387 ctx->uid_set[2] = start_value; 509 switch (c->local_sockaddr->sa_family) {
388 ctx->uid_set[3] = sequencer_v1; 510
389 sequencer_v1 += 0x100; 511 #if (NGX_HAVE_INET6)
512 case AF_INET6:
513 sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
514
515 p = (u_char *) &ctx->uid_set[0];
516
517 *p++ = sin6->sin6_addr.s6_addr[12];
518 *p++ = sin6->sin6_addr.s6_addr[13];
519 *p++ = sin6->sin6_addr.s6_addr[14];
520 *p = sin6->sin6_addr.s6_addr[15];
521
522 break;
523 #endif
524 default: /* AF_INET */
525 sin = (struct sockaddr_in *) c->local_sockaddr;
526 ctx->uid_set[0] = sin->sin_addr.s_addr;
527 break;
528 }
390 529
391 } else { 530 } else {
392 if (conf->service == NGX_CONF_UNSET) { 531 ctx->uid_set[0] = htonl(conf->service);
393
394 c = r->connection;
395
396 if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
397 return NGX_ERROR;
398 }
399
400 switch (c->local_sockaddr->sa_family) {
401
402 #if (NGX_HAVE_INET6)
403 case AF_INET6:
404 sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
405
406 p = (u_char *) &ctx->uid_set[0];
407
408 *p++ = sin6->sin6_addr.s6_addr[12];
409 *p++ = sin6->sin6_addr.s6_addr[13];
410 *p++ = sin6->sin6_addr.s6_addr[14];
411 *p = sin6->sin6_addr.s6_addr[15];
412
413 break;
414 #endif
415 default: /* AF_INET */
416 sin = (struct sockaddr_in *) c->local_sockaddr;
417 ctx->uid_set[0] = sin->sin_addr.s_addr;
418 break;
419 }
420
421 } else {
422 ctx->uid_set[0] = htonl(conf->service);
423 }
424
425 ctx->uid_set[1] = htonl((uint32_t) ngx_time());
426 ctx->uid_set[2] = htonl(start_value);
427 ctx->uid_set[3] = htonl(sequencer_v2);
428 sequencer_v2 += 0x100;
429 if (sequencer_v2 < 0x03030302) {
430 sequencer_v2 = 0x03030302;
431 }
432 } 532 }
433 533
434 } else { 534 ctx->uid_set[1] = htonl((uint32_t) ngx_time());
435 ctx->uid_set[0] = ctx->uid_got[0]; 535 ctx->uid_set[2] = htonl(start_value);
436 ctx->uid_set[1] = ctx->uid_got[1]; 536 ctx->uid_set[3] = htonl(sequencer_v2);
437 ctx->uid_set[2] = ctx->uid_got[2]; 537 sequencer_v2 += 0x100;
438 ctx->uid_set[3] = ctx->uid_got[3]; 538 if (sequencer_v2 < 0x03030302) {
439 } 539 sequencer_v2 = 0x03030302;
440
441 len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
442
443 if (conf->expires) {
444 len += sizeof(expires) - 1 + 2;
445 }
446
447 if (conf->domain.len) {
448 len += conf->domain.len;
449 }
450
451 cookie = ngx_pnalloc(r->pool, len);
452 if (cookie == NULL) {
453 return NGX_ERROR;
454 }
455
456 p = ngx_copy(cookie, conf->name.data, conf->name.len);
457 *p++ = '=';
458
459 if (ctx->uid_got[3] == 0) {
460 src.len = 16;
461 src.data = (u_char *) ctx->uid_set;
462 dst.data = p;
463
464 ngx_encode_base64(&dst, &src);
465
466 p += dst.len;
467
468 if (conf->mark) {
469 *(p - 2) = conf->mark;
470 } 540 }
471 541 }
472 } else {
473 p = ngx_cpymem(p, ctx->cookie.data, 22);
474 *p++ = conf->mark;
475 *p++ = '=';
476 }
477
478 if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) {
479 p = ngx_cpymem(p, expires, sizeof(expires) - 1);
480
481 } else if (conf->expires) {
482 p = ngx_cpymem(p, expires, sizeof("; expires=") - 1);
483 p = ngx_http_cookie_time(p, ngx_time() + conf->expires);
484 }
485
486 p = ngx_copy(p, conf->domain.data, conf->domain.len);
487
488 p = ngx_copy(p, conf->path.data, conf->path.len);
489
490 set_cookie = ngx_list_push(&r->headers_out.headers);
491 if (set_cookie == NULL) {
492 return NGX_ERROR;
493 }
494
495 set_cookie->hash = 1;
496 ngx_str_set(&set_cookie->key, "Set-Cookie");
497 set_cookie->value.len = p - cookie;
498 set_cookie->value.data = cookie;
499
500 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
501 "uid cookie: \"%V\"", &set_cookie->value);
502
503 if (conf->p3p.len == 0) {
504 return NGX_OK;
505 }
506
507 p3p = ngx_list_push(&r->headers_out.headers);
508 if (p3p == NULL) {
509 return NGX_ERROR;
510 }
511
512 p3p->hash = 1;
513 ngx_str_set(&p3p->key, "P3P");
514 p3p->value = conf->p3p;
515 542
516 return NGX_OK; 543 return NGX_OK;
517 } 544 }
518 545
519 546
548 return NGX_ERROR; 575 return NGX_ERROR;
549 } 576 }
550 577
551 var->get_handler = ngx_http_userid_got_variable; 578 var->get_handler = ngx_http_userid_got_variable;
552 579
553 var = ngx_http_add_variable(cf, &ngx_http_userid_set, NGX_HTTP_VAR_NOHASH); 580 var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
554 if (var == NULL) { 581 if (var == NULL) {
555 return NGX_ERROR; 582 return NGX_ERROR;
556 } 583 }
557 584
558 var->get_handler = ngx_http_userid_set_variable; 585 var->get_handler = ngx_http_userid_set_variable;