Annotation of embedaddon/nginx/src/http/modules/ngx_http_userid_filter_module.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (C) Igor Sysoev
! 4: * Copyright (C) Nginx, Inc.
! 5: */
! 6:
! 7:
! 8: #include <ngx_config.h>
! 9: #include <ngx_core.h>
! 10: #include <ngx_http.h>
! 11:
! 12:
! 13: #define NGX_HTTP_USERID_OFF 0
! 14: #define NGX_HTTP_USERID_LOG 1
! 15: #define NGX_HTTP_USERID_V1 2
! 16: #define NGX_HTTP_USERID_ON 3
! 17:
! 18: /* 31 Dec 2037 23:55:55 GMT */
! 19: #define NGX_HTTP_USERID_MAX_EXPIRES 2145916555
! 20:
! 21:
! 22: typedef struct {
! 23: ngx_uint_t enable;
! 24:
! 25: ngx_int_t service;
! 26:
! 27: ngx_str_t name;
! 28: ngx_str_t domain;
! 29: ngx_str_t path;
! 30: ngx_str_t p3p;
! 31:
! 32: time_t expires;
! 33:
! 34: u_char mark;
! 35: } ngx_http_userid_conf_t;
! 36:
! 37:
! 38: typedef struct {
! 39: uint32_t uid_got[4];
! 40: uint32_t uid_set[4];
! 41: ngx_str_t cookie;
! 42: ngx_uint_t reset;
! 43: } ngx_http_userid_ctx_t;
! 44:
! 45:
! 46: static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r,
! 47: ngx_http_userid_conf_t *conf);
! 48: static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r,
! 49: ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid);
! 50: static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,
! 51: ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
! 52: static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r,
! 53: ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
! 54:
! 55: static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf);
! 56: static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf);
! 57: static void *ngx_http_userid_create_conf(ngx_conf_t *cf);
! 58: static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent,
! 59: void *child);
! 60: static char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data);
! 61: static char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data);
! 62: static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd,
! 63: void *conf);
! 64: static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data);
! 65: static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd,
! 66: void *conf);
! 67: static ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle);
! 68:
! 69:
! 70:
! 71: static uint32_t start_value;
! 72: static uint32_t sequencer_v1 = 1;
! 73: static uint32_t sequencer_v2 = 0x03030302;
! 74:
! 75:
! 76: static u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55 GMT";
! 77:
! 78:
! 79: static ngx_http_output_header_filter_pt ngx_http_next_header_filter;
! 80:
! 81:
! 82: static ngx_conf_enum_t ngx_http_userid_state[] = {
! 83: { ngx_string("off"), NGX_HTTP_USERID_OFF },
! 84: { ngx_string("log"), NGX_HTTP_USERID_LOG },
! 85: { ngx_string("v1"), NGX_HTTP_USERID_V1 },
! 86: { ngx_string("on"), NGX_HTTP_USERID_ON },
! 87: { ngx_null_string, 0 }
! 88: };
! 89:
! 90:
! 91: static ngx_conf_post_handler_pt ngx_http_userid_domain_p =
! 92: ngx_http_userid_domain;
! 93: static ngx_conf_post_handler_pt ngx_http_userid_path_p = ngx_http_userid_path;
! 94: static ngx_conf_post_handler_pt ngx_http_userid_p3p_p = ngx_http_userid_p3p;
! 95:
! 96:
! 97: static ngx_command_t ngx_http_userid_commands[] = {
! 98:
! 99: { ngx_string("userid"),
! 100: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 101: ngx_conf_set_enum_slot,
! 102: NGX_HTTP_LOC_CONF_OFFSET,
! 103: offsetof(ngx_http_userid_conf_t, enable),
! 104: ngx_http_userid_state },
! 105:
! 106: { ngx_string("userid_service"),
! 107: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 108: ngx_conf_set_num_slot,
! 109: NGX_HTTP_LOC_CONF_OFFSET,
! 110: offsetof(ngx_http_userid_conf_t, service),
! 111: NULL },
! 112:
! 113: { ngx_string("userid_name"),
! 114: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 115: ngx_conf_set_str_slot,
! 116: NGX_HTTP_LOC_CONF_OFFSET,
! 117: offsetof(ngx_http_userid_conf_t, name),
! 118: NULL },
! 119:
! 120: { ngx_string("userid_domain"),
! 121: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 122: ngx_conf_set_str_slot,
! 123: NGX_HTTP_LOC_CONF_OFFSET,
! 124: offsetof(ngx_http_userid_conf_t, domain),
! 125: &ngx_http_userid_domain_p },
! 126:
! 127: { ngx_string("userid_path"),
! 128: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 129: ngx_conf_set_str_slot,
! 130: NGX_HTTP_LOC_CONF_OFFSET,
! 131: offsetof(ngx_http_userid_conf_t, path),
! 132: &ngx_http_userid_path_p },
! 133:
! 134: { ngx_string("userid_expires"),
! 135: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 136: ngx_http_userid_expires,
! 137: NGX_HTTP_LOC_CONF_OFFSET,
! 138: 0,
! 139: NULL },
! 140:
! 141: { ngx_string("userid_p3p"),
! 142: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 143: ngx_conf_set_str_slot,
! 144: NGX_HTTP_LOC_CONF_OFFSET,
! 145: offsetof(ngx_http_userid_conf_t, p3p),
! 146: &ngx_http_userid_p3p_p },
! 147:
! 148: { ngx_string("userid_mark"),
! 149: NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
! 150: ngx_http_userid_mark,
! 151: NGX_HTTP_LOC_CONF_OFFSET,
! 152: 0,
! 153: NULL },
! 154:
! 155: ngx_null_command
! 156: };
! 157:
! 158:
! 159: static ngx_http_module_t ngx_http_userid_filter_module_ctx = {
! 160: ngx_http_userid_add_variables, /* preconfiguration */
! 161: ngx_http_userid_init, /* postconfiguration */
! 162:
! 163: NULL, /* create main configuration */
! 164: NULL, /* init main configuration */
! 165:
! 166: NULL, /* create server configuration */
! 167: NULL, /* merge server configuration */
! 168:
! 169: ngx_http_userid_create_conf, /* create location configuration */
! 170: ngx_http_userid_merge_conf /* merge location configuration */
! 171: };
! 172:
! 173:
! 174: ngx_module_t ngx_http_userid_filter_module = {
! 175: NGX_MODULE_V1,
! 176: &ngx_http_userid_filter_module_ctx, /* module context */
! 177: ngx_http_userid_commands, /* module directives */
! 178: NGX_HTTP_MODULE, /* module type */
! 179: NULL, /* init master */
! 180: NULL, /* init module */
! 181: ngx_http_userid_init_worker, /* init process */
! 182: NULL, /* init thread */
! 183: NULL, /* exit thread */
! 184: NULL, /* exit process */
! 185: NULL, /* exit master */
! 186: NGX_MODULE_V1_PADDING
! 187: };
! 188:
! 189:
! 190: static ngx_str_t ngx_http_userid_got = ngx_string("uid_got");
! 191: static ngx_str_t ngx_http_userid_set = ngx_string("uid_set");
! 192: static ngx_str_t ngx_http_userid_reset = ngx_string("uid_reset");
! 193: static ngx_uint_t ngx_http_userid_reset_index;
! 194:
! 195:
! 196: static ngx_int_t
! 197: ngx_http_userid_filter(ngx_http_request_t *r)
! 198: {
! 199: ngx_http_userid_ctx_t *ctx;
! 200: ngx_http_userid_conf_t *conf;
! 201:
! 202: if (r != r->main) {
! 203: return ngx_http_next_header_filter(r);
! 204: }
! 205:
! 206: conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
! 207:
! 208: if (conf->enable < NGX_HTTP_USERID_V1) {
! 209: return ngx_http_next_header_filter(r);
! 210: }
! 211:
! 212: ctx = ngx_http_userid_get_uid(r, conf);
! 213:
! 214: if (ctx == NULL) {
! 215: return NGX_ERROR;
! 216: }
! 217:
! 218: if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) {
! 219: return ngx_http_next_header_filter(r);
! 220: }
! 221:
! 222: return NGX_ERROR;
! 223: }
! 224:
! 225:
! 226: static ngx_int_t
! 227: ngx_http_userid_got_variable(ngx_http_request_t *r,
! 228: ngx_http_variable_value_t *v, uintptr_t data)
! 229: {
! 230: ngx_http_userid_ctx_t *ctx;
! 231: ngx_http_userid_conf_t *conf;
! 232:
! 233: conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
! 234:
! 235: if (conf->enable == NGX_HTTP_USERID_OFF) {
! 236: v->not_found = 1;
! 237: return NGX_OK;
! 238: }
! 239:
! 240: ctx = ngx_http_userid_get_uid(r->main, conf);
! 241:
! 242: if (ctx == NULL) {
! 243: return NGX_ERROR;
! 244: }
! 245:
! 246: if (ctx->uid_got[3] != 0) {
! 247: return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_got);
! 248: }
! 249:
! 250: v->not_found = 1;
! 251:
! 252: return NGX_OK;
! 253: }
! 254:
! 255:
! 256: static ngx_int_t
! 257: ngx_http_userid_set_variable(ngx_http_request_t *r,
! 258: ngx_http_variable_value_t *v, uintptr_t data)
! 259: {
! 260: ngx_http_userid_ctx_t *ctx;
! 261: ngx_http_userid_conf_t *conf;
! 262:
! 263: conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
! 264:
! 265: if (conf->enable < NGX_HTTP_USERID_V1) {
! 266: v->not_found = 1;
! 267: return NGX_OK;
! 268: }
! 269:
! 270: ctx = ngx_http_userid_get_uid(r->main, conf);
! 271:
! 272: if (ctx == NULL) {
! 273: return NGX_ERROR;
! 274: }
! 275:
! 276: if (ngx_http_userid_create_uid(r->main, ctx, conf) != NGX_OK) {
! 277: return NGX_ERROR;
! 278: }
! 279:
! 280: if (ctx->uid_set[3] == 0) {
! 281: v->not_found = 1;
! 282: return NGX_OK;
! 283: }
! 284:
! 285: return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_set);
! 286: }
! 287:
! 288:
! 289: static ngx_http_userid_ctx_t *
! 290: ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
! 291: {
! 292: ngx_int_t n;
! 293: ngx_str_t src, dst;
! 294: ngx_table_elt_t **cookies;
! 295: ngx_http_userid_ctx_t *ctx;
! 296:
! 297: ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
! 298:
! 299: if (ctx) {
! 300: return ctx;
! 301: }
! 302:
! 303: if (ctx == NULL) {
! 304: ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_userid_ctx_t));
! 305: if (ctx == NULL) {
! 306: return NULL;
! 307: }
! 308:
! 309: ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module);
! 310: }
! 311:
! 312: n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
! 313: &ctx->cookie);
! 314: if (n == NGX_DECLINED) {
! 315: return ctx;
! 316: }
! 317:
! 318: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 319: "uid cookie: \"%V\"", &ctx->cookie);
! 320:
! 321: if (ctx->cookie.len < 22) {
! 322: cookies = r->headers_in.cookies.elts;
! 323: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 324: "client sent too short userid cookie \"%V\"",
! 325: &cookies[n]->value);
! 326: return ctx;
! 327: }
! 328:
! 329: src = ctx->cookie;
! 330:
! 331: /*
! 332: * we have to limit the encoded string to 22 characters because
! 333: * 1) cookie may be marked by "userid_mark",
! 334: * 2) and there are already the millions cookies with a garbage
! 335: * instead of the correct base64 trail "=="
! 336: */
! 337:
! 338: src.len = 22;
! 339:
! 340: dst.data = (u_char *) ctx->uid_got;
! 341:
! 342: if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
! 343: cookies = r->headers_in.cookies.elts;
! 344: ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
! 345: "client sent invalid userid cookie \"%V\"",
! 346: &cookies[n]->value);
! 347: return ctx;
! 348: }
! 349:
! 350: ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 351: "uid: %08XD%08XD%08XD%08XD",
! 352: ctx->uid_got[0], ctx->uid_got[1],
! 353: ctx->uid_got[2], ctx->uid_got[3]);
! 354:
! 355: return ctx;
! 356: }
! 357:
! 358:
! 359: static ngx_int_t
! 360: ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
! 361: ngx_http_userid_conf_t *conf)
! 362: {
! 363: u_char *cookie, *p;
! 364: size_t len;
! 365: ngx_str_t src, dst;
! 366: ngx_table_elt_t *set_cookie, *p3p;
! 367:
! 368: if (ngx_http_userid_create_uid(r, ctx, conf) != NGX_OK) {
! 369: return NGX_ERROR;
! 370: }
! 371:
! 372: if (ctx->uid_set[3] == 0) {
! 373: return NGX_OK;
! 374: }
! 375:
! 376: len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
! 377:
! 378: if (conf->expires) {
! 379: len += sizeof(expires) - 1 + 2;
! 380: }
! 381:
! 382: if (conf->domain.len) {
! 383: len += conf->domain.len;
! 384: }
! 385:
! 386: cookie = ngx_pnalloc(r->pool, len);
! 387: if (cookie == NULL) {
! 388: return NGX_ERROR;
! 389: }
! 390:
! 391: p = ngx_copy(cookie, conf->name.data, conf->name.len);
! 392: *p++ = '=';
! 393:
! 394: if (ctx->uid_got[3] == 0 || ctx->reset) {
! 395: src.len = 16;
! 396: src.data = (u_char *) ctx->uid_set;
! 397: dst.data = p;
! 398:
! 399: ngx_encode_base64(&dst, &src);
! 400:
! 401: p += dst.len;
! 402:
! 403: if (conf->mark) {
! 404: *(p - 2) = conf->mark;
! 405: }
! 406:
! 407: } else {
! 408: p = ngx_cpymem(p, ctx->cookie.data, 22);
! 409: *p++ = conf->mark;
! 410: *p++ = '=';
! 411: }
! 412:
! 413: if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) {
! 414: p = ngx_cpymem(p, expires, sizeof(expires) - 1);
! 415:
! 416: } else if (conf->expires) {
! 417: p = ngx_cpymem(p, expires, sizeof("; expires=") - 1);
! 418: p = ngx_http_cookie_time(p, ngx_time() + conf->expires);
! 419: }
! 420:
! 421: p = ngx_copy(p, conf->domain.data, conf->domain.len);
! 422:
! 423: p = ngx_copy(p, conf->path.data, conf->path.len);
! 424:
! 425: set_cookie = ngx_list_push(&r->headers_out.headers);
! 426: if (set_cookie == NULL) {
! 427: return NGX_ERROR;
! 428: }
! 429:
! 430: set_cookie->hash = 1;
! 431: ngx_str_set(&set_cookie->key, "Set-Cookie");
! 432: set_cookie->value.len = p - cookie;
! 433: set_cookie->value.data = cookie;
! 434:
! 435: ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
! 436: "uid cookie: \"%V\"", &set_cookie->value);
! 437:
! 438: if (conf->p3p.len == 0) {
! 439: return NGX_OK;
! 440: }
! 441:
! 442: p3p = ngx_list_push(&r->headers_out.headers);
! 443: if (p3p == NULL) {
! 444: return NGX_ERROR;
! 445: }
! 446:
! 447: p3p->hash = 1;
! 448: ngx_str_set(&p3p->key, "P3P");
! 449: p3p->value = conf->p3p;
! 450:
! 451: return NGX_OK;
! 452: }
! 453:
! 454:
! 455: static ngx_int_t
! 456: ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
! 457: ngx_http_userid_conf_t *conf)
! 458: {
! 459: ngx_connection_t *c;
! 460: struct sockaddr_in *sin;
! 461: ngx_http_variable_value_t *vv;
! 462: #if (NGX_HAVE_INET6)
! 463: u_char *p;
! 464: struct sockaddr_in6 *sin6;
! 465: #endif
! 466:
! 467: if (ctx->uid_set[3] != 0) {
! 468: return NGX_OK;
! 469: }
! 470:
! 471: if (ctx->uid_got[3] != 0) {
! 472:
! 473: vv = ngx_http_get_indexed_variable(r, ngx_http_userid_reset_index);
! 474:
! 475: if (vv->len == 0 || (vv->len == 1 && vv->data[0] == '0')) {
! 476:
! 477: if (conf->mark == '\0'
! 478: || (ctx->cookie.len > 23
! 479: && ctx->cookie.data[22] == conf->mark
! 480: && ctx->cookie.data[23] == '='))
! 481: {
! 482: return NGX_OK;
! 483: }
! 484:
! 485: ctx->uid_set[0] = ctx->uid_got[0];
! 486: ctx->uid_set[1] = ctx->uid_got[1];
! 487: ctx->uid_set[2] = ctx->uid_got[2];
! 488: ctx->uid_set[3] = ctx->uid_got[3];
! 489:
! 490: return NGX_OK;
! 491:
! 492: } else {
! 493: ctx->reset = 1;
! 494:
! 495: if (vv->len == 3 && ngx_strncmp(vv->data, "log", 3) == 0) {
! 496: ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
! 497: "userid cookie \"%V=%08XD%08XD%08XD%08XD\" was reset",
! 498: &conf->name, ctx->uid_got[0], ctx->uid_got[1],
! 499: ctx->uid_got[2], ctx->uid_got[3]);
! 500: }
! 501: }
! 502: }
! 503:
! 504: /*
! 505: * TODO: in the threaded mode the sequencers should be in TLS and their
! 506: * ranges should be divided between threads
! 507: */
! 508:
! 509: if (conf->enable == NGX_HTTP_USERID_V1) {
! 510: if (conf->service == NGX_CONF_UNSET) {
! 511: ctx->uid_set[0] = 0;
! 512: } else {
! 513: ctx->uid_set[0] = conf->service;
! 514: }
! 515: ctx->uid_set[1] = (uint32_t) ngx_time();
! 516: ctx->uid_set[2] = start_value;
! 517: ctx->uid_set[3] = sequencer_v1;
! 518: sequencer_v1 += 0x100;
! 519:
! 520: } else {
! 521: if (conf->service == NGX_CONF_UNSET) {
! 522:
! 523: c = r->connection;
! 524:
! 525: if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
! 526: return NGX_ERROR;
! 527: }
! 528:
! 529: switch (c->local_sockaddr->sa_family) {
! 530:
! 531: #if (NGX_HAVE_INET6)
! 532: case AF_INET6:
! 533: sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
! 534:
! 535: p = (u_char *) &ctx->uid_set[0];
! 536:
! 537: *p++ = sin6->sin6_addr.s6_addr[12];
! 538: *p++ = sin6->sin6_addr.s6_addr[13];
! 539: *p++ = sin6->sin6_addr.s6_addr[14];
! 540: *p = sin6->sin6_addr.s6_addr[15];
! 541:
! 542: break;
! 543: #endif
! 544: default: /* AF_INET */
! 545: sin = (struct sockaddr_in *) c->local_sockaddr;
! 546: ctx->uid_set[0] = sin->sin_addr.s_addr;
! 547: break;
! 548: }
! 549:
! 550: } else {
! 551: ctx->uid_set[0] = htonl(conf->service);
! 552: }
! 553:
! 554: ctx->uid_set[1] = htonl((uint32_t) ngx_time());
! 555: ctx->uid_set[2] = htonl(start_value);
! 556: ctx->uid_set[3] = htonl(sequencer_v2);
! 557: sequencer_v2 += 0x100;
! 558: if (sequencer_v2 < 0x03030302) {
! 559: sequencer_v2 = 0x03030302;
! 560: }
! 561: }
! 562:
! 563: return NGX_OK;
! 564: }
! 565:
! 566:
! 567: static ngx_int_t
! 568: ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
! 569: ngx_str_t *name, uint32_t *uid)
! 570: {
! 571: v->len = name->len + sizeof("=00001111222233334444555566667777") - 1;
! 572: v->data = ngx_pnalloc(r->pool, v->len);
! 573: if (v->data == NULL) {
! 574: return NGX_ERROR;
! 575: }
! 576:
! 577: v->valid = 1;
! 578: v->no_cacheable = 0;
! 579: v->not_found = 0;
! 580:
! 581: ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD",
! 582: name, uid[0], uid[1], uid[2], uid[3]);
! 583:
! 584: return NGX_OK;
! 585: }
! 586:
! 587:
! 588: static ngx_int_t
! 589: ngx_http_userid_reset_variable(ngx_http_request_t *r,
! 590: ngx_http_variable_value_t *v, uintptr_t data)
! 591: {
! 592: *v = ngx_http_variable_null_value;
! 593:
! 594: return NGX_OK;
! 595: }
! 596:
! 597:
! 598: static ngx_int_t
! 599: ngx_http_userid_add_variables(ngx_conf_t *cf)
! 600: {
! 601: ngx_int_t n;
! 602: ngx_http_variable_t *var;
! 603:
! 604: var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
! 605: if (var == NULL) {
! 606: return NGX_ERROR;
! 607: }
! 608:
! 609: var->get_handler = ngx_http_userid_got_variable;
! 610:
! 611: var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
! 612: if (var == NULL) {
! 613: return NGX_ERROR;
! 614: }
! 615:
! 616: var->get_handler = ngx_http_userid_set_variable;
! 617:
! 618: var = ngx_http_add_variable(cf, &ngx_http_userid_reset,
! 619: NGX_HTTP_VAR_CHANGEABLE);
! 620: if (var == NULL) {
! 621: return NGX_ERROR;
! 622: }
! 623:
! 624: var->get_handler = ngx_http_userid_reset_variable;
! 625:
! 626: n = ngx_http_get_variable_index(cf, &ngx_http_userid_reset);
! 627: if (n == NGX_ERROR) {
! 628: return NGX_ERROR;
! 629: }
! 630:
! 631: ngx_http_userid_reset_index = n;
! 632:
! 633: return NGX_OK;
! 634: }
! 635:
! 636:
! 637: static void *
! 638: ngx_http_userid_create_conf(ngx_conf_t *cf)
! 639: {
! 640: ngx_http_userid_conf_t *conf;
! 641:
! 642: conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t));
! 643: if (conf == NULL) {
! 644: return NULL;
! 645: }
! 646:
! 647: /*
! 648: * set by ngx_pcalloc():
! 649: *
! 650: * conf->name = { 0, NULL };
! 651: * conf->domain = { 0, NULL };
! 652: * conf->path = { 0, NULL };
! 653: * conf->p3p = { 0, NULL };
! 654: */
! 655:
! 656: conf->enable = NGX_CONF_UNSET_UINT;
! 657: conf->service = NGX_CONF_UNSET;
! 658: conf->expires = NGX_CONF_UNSET;
! 659: conf->mark = (u_char) '\xFF';
! 660:
! 661: return conf;
! 662: }
! 663:
! 664:
! 665: static char *
! 666: ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child)
! 667: {
! 668: ngx_http_userid_conf_t *prev = parent;
! 669: ngx_http_userid_conf_t *conf = child;
! 670:
! 671: ngx_conf_merge_uint_value(conf->enable, prev->enable,
! 672: NGX_HTTP_USERID_OFF);
! 673:
! 674: ngx_conf_merge_str_value(conf->name, prev->name, "uid");
! 675: ngx_conf_merge_str_value(conf->domain, prev->domain, "");
! 676: ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
! 677: ngx_conf_merge_str_value(conf->p3p, prev->p3p, "");
! 678:
! 679: ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET);
! 680: ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
! 681:
! 682: if (conf->mark == (u_char) '\xFF') {
! 683: if (prev->mark == (u_char) '\xFF') {
! 684: conf->mark = '\0';
! 685: } else {
! 686: conf->mark = prev->mark;
! 687: }
! 688: }
! 689:
! 690: return NGX_CONF_OK;
! 691: }
! 692:
! 693:
! 694: static ngx_int_t
! 695: ngx_http_userid_init(ngx_conf_t *cf)
! 696: {
! 697: ngx_http_next_header_filter = ngx_http_top_header_filter;
! 698: ngx_http_top_header_filter = ngx_http_userid_filter;
! 699:
! 700: return NGX_OK;
! 701: }
! 702:
! 703:
! 704: static char *
! 705: ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data)
! 706: {
! 707: ngx_str_t *domain = data;
! 708:
! 709: u_char *p, *new;
! 710:
! 711: if (ngx_strcmp(domain->data, "none") == 0) {
! 712: ngx_str_set(domain, "");
! 713: return NGX_CONF_OK;
! 714: }
! 715:
! 716: new = ngx_pnalloc(cf->pool, sizeof("; domain=") - 1 + domain->len);
! 717: if (new == NULL) {
! 718: return NGX_CONF_ERROR;
! 719: }
! 720:
! 721: p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1);
! 722: ngx_memcpy(p, domain->data, domain->len);
! 723:
! 724: domain->len += sizeof("; domain=") - 1;
! 725: domain->data = new;
! 726:
! 727: return NGX_CONF_OK;
! 728: }
! 729:
! 730:
! 731: static char *
! 732: ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data)
! 733: {
! 734: ngx_str_t *path = data;
! 735:
! 736: u_char *p, *new;
! 737:
! 738: new = ngx_pnalloc(cf->pool, sizeof("; path=") - 1 + path->len);
! 739: if (new == NULL) {
! 740: return NGX_CONF_ERROR;
! 741: }
! 742:
! 743: p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1);
! 744: ngx_memcpy(p, path->data, path->len);
! 745:
! 746: path->len += sizeof("; path=") - 1;
! 747: path->data = new;
! 748:
! 749: return NGX_CONF_OK;
! 750: }
! 751:
! 752:
! 753: static char *
! 754: ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 755: {
! 756: ngx_http_userid_conf_t *ucf = conf;
! 757:
! 758: ngx_str_t *value;
! 759:
! 760: if (ucf->expires != NGX_CONF_UNSET) {
! 761: return "is duplicate";
! 762: }
! 763:
! 764: value = cf->args->elts;
! 765:
! 766: if (ngx_strcmp(value[1].data, "max") == 0) {
! 767: ucf->expires = NGX_HTTP_USERID_MAX_EXPIRES;
! 768: return NGX_CONF_OK;
! 769: }
! 770:
! 771: if (ngx_strcmp(value[1].data, "off") == 0) {
! 772: ucf->expires = 0;
! 773: return NGX_CONF_OK;
! 774: }
! 775:
! 776: ucf->expires = ngx_parse_time(&value[1], 1);
! 777: if (ucf->expires == (time_t) NGX_ERROR) {
! 778: return "invalid value";
! 779: }
! 780:
! 781: return NGX_CONF_OK;
! 782: }
! 783:
! 784:
! 785: static char *
! 786: ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data)
! 787: {
! 788: ngx_str_t *p3p = data;
! 789:
! 790: if (ngx_strcmp(p3p->data, "none") == 0) {
! 791: ngx_str_set(p3p, "");
! 792: }
! 793:
! 794: return NGX_CONF_OK;
! 795: }
! 796:
! 797:
! 798: static char *
! 799: ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
! 800: {
! 801: ngx_http_userid_conf_t *ucf = conf;
! 802:
! 803: ngx_str_t *value;
! 804:
! 805: if (ucf->mark != (u_char) '\xFF') {
! 806: return "is duplicate";
! 807: }
! 808:
! 809: value = cf->args->elts;
! 810:
! 811: if (ngx_strcmp(value[1].data, "off") == 0) {
! 812: ucf->mark = '\0';
! 813: return NGX_CONF_OK;
! 814: }
! 815:
! 816: if (value[1].len != 1
! 817: || !((value[1].data[0] >= '0' && value[1].data[0] <= '9')
! 818: || (value[1].data[0] >= 'A' && value[1].data[0] <= 'Z')
! 819: || (value[1].data[0] >= 'a' && value[1].data[0] <= 'z')
! 820: || value[1].data[0] == '='))
! 821: {
! 822: return "value must be \"off\" or a single letter, digit or \"=\"";
! 823: }
! 824:
! 825: ucf->mark = value[1].data[0];
! 826:
! 827: return NGX_CONF_OK;
! 828: }
! 829:
! 830:
! 831: static ngx_int_t
! 832: ngx_http_userid_init_worker(ngx_cycle_t *cycle)
! 833: {
! 834: struct timeval tp;
! 835:
! 836: ngx_gettimeofday(&tp);
! 837:
! 838: /* use the most significant usec part that fits to 16 bits */
! 839: start_value = ((tp.tv_usec / 20) << 16) | ngx_pid;
! 840:
! 841: return NGX_OK;
! 842: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>