Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.13.12 ]​[ nginx-1.12.2 ]​

0001 
0002 /*
0003  * Copyright (C) Igor Sysoev
0004  * Copyright (C) Nginx, Inc.
0005  */
0006 
0007 
0008 #include <ngx_config.h>
0009 #include <ngx_core.h>
0010 #include <ngx_http.h>
0011 
0012 
0013 #define NGX_HTTP_USERID_OFF   0
0014 #define NGX_HTTP_USERID_LOG   1
0015 #define NGX_HTTP_USERID_V1    2
0016 #define NGX_HTTP_USERID_ON    3
0017 
0018 /* 31 Dec 2037 23:55:55 GMT */
0019 #define NGX_HTTP_USERID_MAX_EXPIRES  2145916555
0020 
0021 
0022 typedef struct {
0023     ngx_uint_t  enable;
0024 
0025     ngx_int_t   service;
0026 
0027     ngx_str_t   name;
0028     ngx_str_t   domain;
0029     ngx_str_t   path;
0030     ngx_str_t   p3p;
0031 
0032     time_t      expires;
0033 
0034     u_char      mark;
0035 } ngx_http_userid_conf_t;
0036 
0037 
0038 typedef struct {
0039     uint32_t    uid_got[4];
0040     uint32_t    uid_set[4];
0041     ngx_str_t   cookie;
0042     ngx_uint_t  reset;
0043 } ngx_http_userid_ctx_t;
0044 
0045 
0046 static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r,
0047     ngx_http_userid_conf_t *conf);
0048 static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r,
0049     ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid);
0050 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,
0051     ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
0052 static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r,
0053     ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
0054 
0055 static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf);
0056 static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf);
0057 static void *ngx_http_userid_create_conf(ngx_conf_t *cf);
0058 static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent,
0059     void *child);
0060 static char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data);
0061 static char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data);
0062 static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd,
0063     void *conf);
0064 static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data);
0065 static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd,
0066     void *conf);
0067 static ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle);
0068 
0069 
0070 
0071 static uint32_t  start_value;
0072 static uint32_t  sequencer_v1 = 1;
0073 static uint32_t  sequencer_v2 = 0x03030302;
0074 
0075 
0076 static u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55 GMT";
0077 
0078 
0079 static ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
0080 
0081 
0082 static ngx_conf_enum_t  ngx_http_userid_state[] = {
0083     { ngx_string("off"), NGX_HTTP_USERID_OFF },
0084     { ngx_string("log"), NGX_HTTP_USERID_LOG },
0085     { ngx_string("v1"), NGX_HTTP_USERID_V1 },
0086     { ngx_string("on"), NGX_HTTP_USERID_ON },
0087     { ngx_null_string, 0 }
0088 };
0089 
0090 
0091 static ngx_conf_post_handler_pt  ngx_http_userid_domain_p =
0092     ngx_http_userid_domain;
0093 static ngx_conf_post_handler_pt  ngx_http_userid_path_p = ngx_http_userid_path;
0094 static ngx_conf_post_handler_pt  ngx_http_userid_p3p_p = ngx_http_userid_p3p;
0095 
0096 
0097 static ngx_command_t  ngx_http_userid_commands[] = {
0098 
0099     { ngx_string("userid"),
0100       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0101       ngx_conf_set_enum_slot,
0102       NGX_HTTP_LOC_CONF_OFFSET,
0103       offsetof(ngx_http_userid_conf_t, enable),
0104       ngx_http_userid_state },
0105 
0106     { ngx_string("userid_service"),
0107       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0108       ngx_conf_set_num_slot,
0109       NGX_HTTP_LOC_CONF_OFFSET,
0110       offsetof(ngx_http_userid_conf_t, service),
0111       NULL },
0112 
0113     { ngx_string("userid_name"),
0114       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0115       ngx_conf_set_str_slot,
0116       NGX_HTTP_LOC_CONF_OFFSET,
0117       offsetof(ngx_http_userid_conf_t, name),
0118       NULL },
0119 
0120     { ngx_string("userid_domain"),
0121       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0122       ngx_conf_set_str_slot,
0123       NGX_HTTP_LOC_CONF_OFFSET,
0124       offsetof(ngx_http_userid_conf_t, domain),
0125       &ngx_http_userid_domain_p },
0126 
0127     { ngx_string("userid_path"),
0128       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0129       ngx_conf_set_str_slot,
0130       NGX_HTTP_LOC_CONF_OFFSET,
0131       offsetof(ngx_http_userid_conf_t, path),
0132       &ngx_http_userid_path_p },
0133 
0134     { ngx_string("userid_expires"),
0135       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0136       ngx_http_userid_expires,
0137       NGX_HTTP_LOC_CONF_OFFSET,
0138       0,
0139       NULL },
0140 
0141     { ngx_string("userid_p3p"),
0142       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0143       ngx_conf_set_str_slot,
0144       NGX_HTTP_LOC_CONF_OFFSET,
0145       offsetof(ngx_http_userid_conf_t, p3p),
0146       &ngx_http_userid_p3p_p },
0147 
0148     { ngx_string("userid_mark"),
0149       NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
0150       ngx_http_userid_mark,
0151       NGX_HTTP_LOC_CONF_OFFSET,
0152       0,
0153       NULL },
0154 
0155       ngx_null_command
0156 };
0157 
0158 
0159 static ngx_http_module_t  ngx_http_userid_filter_module_ctx = {
0160     ngx_http_userid_add_variables,         /* preconfiguration */
0161     ngx_http_userid_init,                  /* postconfiguration */
0162 
0163     NULL,                                  /* create main configuration */
0164     NULL,                                  /* init main configuration */
0165 
0166     NULL,                                  /* create server configuration */
0167     NULL,                                  /* merge server configuration */
0168 
0169     ngx_http_userid_create_conf,           /* create location configuration */
0170     ngx_http_userid_merge_conf             /* merge location configuration */
0171 };
0172 
0173 
0174 ngx_module_t  ngx_http_userid_filter_module = {
0175     NGX_MODULE_V1,
0176     &ngx_http_userid_filter_module_ctx,    /* module context */
0177     ngx_http_userid_commands,              /* module directives */
0178     NGX_HTTP_MODULE,                       /* module type */
0179     NULL,                                  /* init master */
0180     NULL,                                  /* init module */
0181     ngx_http_userid_init_worker,           /* init process */
0182     NULL,                                  /* init thread */
0183     NULL,                                  /* exit thread */
0184     NULL,                                  /* exit process */
0185     NULL,                                  /* exit master */
0186     NGX_MODULE_V1_PADDING
0187 };
0188 
0189 
0190 static ngx_str_t   ngx_http_userid_got = ngx_string("uid_got");
0191 static ngx_str_t   ngx_http_userid_set = ngx_string("uid_set");
0192 static ngx_str_t   ngx_http_userid_reset = ngx_string("uid_reset");
0193 static ngx_uint_t  ngx_http_userid_reset_index;
0194 
0195 
0196 static ngx_int_t
0197 ngx_http_userid_filter(ngx_http_request_t *r)
0198 {
0199     ngx_http_userid_ctx_t   *ctx;
0200     ngx_http_userid_conf_t  *conf;
0201 
0202     if (r != r->main) {
0203         return ngx_http_next_header_filter(r);
0204     }
0205 
0206     conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
0207 
0208     if (conf->enable < NGX_HTTP_USERID_V1) {
0209         return ngx_http_next_header_filter(r);
0210     }
0211 
0212     ctx = ngx_http_userid_get_uid(r, conf);
0213 
0214     if (ctx == NULL) {
0215         return NGX_ERROR;
0216     }
0217 
0218     if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) {
0219         return ngx_http_next_header_filter(r);
0220     }
0221 
0222     return NGX_ERROR;
0223 }
0224 
0225 
0226 static ngx_int_t
0227 ngx_http_userid_got_variable(ngx_http_request_t *r,
0228     ngx_http_variable_value_t *v, uintptr_t data)
0229 {
0230     ngx_http_userid_ctx_t   *ctx;
0231     ngx_http_userid_conf_t  *conf;
0232 
0233     conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
0234 
0235     if (conf->enable == NGX_HTTP_USERID_OFF) {
0236         v->not_found = 1;
0237         return NGX_OK;
0238     }
0239 
0240     ctx = ngx_http_userid_get_uid(r->main, conf);
0241 
0242     if (ctx == NULL) {
0243         return NGX_ERROR;
0244     }
0245 
0246     if (ctx->uid_got[3] != 0) {
0247         return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_got);
0248     }
0249 
0250     v->not_found = 1;
0251 
0252     return NGX_OK;
0253 }
0254 
0255 
0256 static ngx_int_t
0257 ngx_http_userid_set_variable(ngx_http_request_t *r,
0258     ngx_http_variable_value_t *v, uintptr_t data)
0259 {
0260     ngx_http_userid_ctx_t   *ctx;
0261     ngx_http_userid_conf_t  *conf;
0262 
0263     conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
0264 
0265     if (conf->enable < NGX_HTTP_USERID_V1) {
0266         v->not_found = 1;
0267         return NGX_OK;
0268     }
0269 
0270     ctx = ngx_http_userid_get_uid(r->main, conf);
0271 
0272     if (ctx == NULL) {
0273         return NGX_ERROR;
0274     }
0275 
0276     if (ngx_http_userid_create_uid(r->main, ctx, conf) != NGX_OK) {
0277         return NGX_ERROR;
0278     }
0279 
0280     if (ctx->uid_set[3] == 0) {
0281         v->not_found = 1;
0282         return NGX_OK;
0283     }
0284 
0285     return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_set);
0286 }
0287 
0288 
0289 static ngx_http_userid_ctx_t *
0290 ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
0291 {
0292     ngx_int_t                n;
0293     ngx_str_t                src, dst;
0294     ngx_table_elt_t        **cookies;
0295     ngx_http_userid_ctx_t   *ctx;
0296 
0297     ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
0298 
0299     if (ctx) {
0300         return ctx;
0301     }
0302 
0303     if (ctx == NULL) {
0304         ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_userid_ctx_t));
0305         if (ctx == NULL) {
0306             return NULL;
0307         }
0308 
0309         ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module);
0310     }
0311 
0312     n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
0313                                           &ctx->cookie);
0314     if (n == NGX_DECLINED) {
0315         return ctx;
0316     }
0317 
0318     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0319                    "uid cookie: \"%V\"", &ctx->cookie);
0320 
0321     if (ctx->cookie.len < 22) {
0322         cookies = r->headers_in.cookies.elts;
0323         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0324                       "client sent too short userid cookie \"%V\"",
0325                       &cookies[n]->value);
0326         return ctx;
0327     }
0328 
0329     src = ctx->cookie;
0330 
0331     /*
0332      * we have to limit the encoded string to 22 characters because
0333      *  1) cookie may be marked by "userid_mark",
0334      *  2) and there are already the millions cookies with a garbage
0335      *     instead of the correct base64 trail "=="
0336      */
0337 
0338     src.len = 22;
0339 
0340     dst.data = (u_char *) ctx->uid_got;
0341 
0342     if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
0343         cookies = r->headers_in.cookies.elts;
0344         ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
0345                       "client sent invalid userid cookie \"%V\"",
0346                       &cookies[n]->value);
0347         return ctx;
0348     }
0349 
0350     ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0351                    "uid: %08XD%08XD%08XD%08XD",
0352                    ctx->uid_got[0], ctx->uid_got[1],
0353                    ctx->uid_got[2], ctx->uid_got[3]);
0354 
0355     return ctx;
0356 }
0357 
0358 
0359 static ngx_int_t
0360 ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
0361     ngx_http_userid_conf_t *conf)
0362 {
0363     u_char           *cookie, *p;
0364     size_t            len;
0365     ngx_str_t         src, dst;
0366     ngx_table_elt_t  *set_cookie, *p3p;
0367 
0368     if (ngx_http_userid_create_uid(r, ctx, conf) != NGX_OK) {
0369         return NGX_ERROR;
0370     }
0371 
0372     if (ctx->uid_set[3] == 0) {
0373         return NGX_OK;
0374     }
0375 
0376     len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
0377 
0378     if (conf->expires) {
0379         len += sizeof(expires) - 1 + 2;
0380     }
0381 
0382     if (conf->domain.len) {
0383         len += conf->domain.len;
0384     }
0385 
0386     cookie = ngx_pnalloc(r->pool, len);
0387     if (cookie == NULL) {
0388         return NGX_ERROR;
0389     }
0390 
0391     p = ngx_copy(cookie, conf->name.data, conf->name.len);
0392     *p++ = '=';
0393 
0394     if (ctx->uid_got[3] == 0 || ctx->reset) {
0395         src.len = 16;
0396         src.data = (u_char *) ctx->uid_set;
0397         dst.data = p;
0398 
0399         ngx_encode_base64(&dst, &src);
0400 
0401         p += dst.len;
0402 
0403         if (conf->mark) {
0404             *(p - 2) = conf->mark;
0405         }
0406 
0407     } else {
0408         p = ngx_cpymem(p, ctx->cookie.data, 22);
0409         *p++ = conf->mark;
0410         *p++ = '=';
0411     }
0412 
0413     if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) {
0414         p = ngx_cpymem(p, expires, sizeof(expires) - 1);
0415 
0416     } else if (conf->expires) {
0417         p = ngx_cpymem(p, expires, sizeof("; expires=") - 1);
0418         p = ngx_http_cookie_time(p, ngx_time() + conf->expires);
0419     }
0420 
0421     p = ngx_copy(p, conf->domain.data, conf->domain.len);
0422 
0423     p = ngx_copy(p, conf->path.data, conf->path.len);
0424 
0425     set_cookie = ngx_list_push(&r->headers_out.headers);
0426     if (set_cookie == NULL) {
0427         return NGX_ERROR;
0428     }
0429 
0430     set_cookie->hash = 1;
0431     ngx_str_set(&set_cookie->key, "Set-Cookie");
0432     set_cookie->value.len = p - cookie;
0433     set_cookie->value.data = cookie;
0434 
0435     ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
0436                    "uid cookie: \"%V\"", &set_cookie->value);
0437 
0438     if (conf->p3p.len == 0) {
0439         return NGX_OK;
0440     }
0441 
0442     p3p = ngx_list_push(&r->headers_out.headers);
0443     if (p3p == NULL) {
0444         return NGX_ERROR;
0445     }
0446 
0447     p3p->hash = 1;
0448     ngx_str_set(&p3p->key, "P3P");
0449     p3p->value = conf->p3p;
0450 
0451     return NGX_OK;
0452 }
0453 
0454 
0455 static ngx_int_t
0456 ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
0457     ngx_http_userid_conf_t *conf)
0458 {
0459     ngx_connection_t           *c;
0460     struct sockaddr_in         *sin;
0461     ngx_http_variable_value_t  *vv;
0462 #if (NGX_HAVE_INET6)
0463     u_char                     *p;
0464     struct sockaddr_in6        *sin6;
0465 #endif
0466 
0467     if (ctx->uid_set[3] != 0) {
0468         return NGX_OK;
0469     }
0470 
0471     if (ctx->uid_got[3] != 0) {
0472 
0473         vv = ngx_http_get_indexed_variable(r, ngx_http_userid_reset_index);
0474 
0475         if (vv == NULL || vv->not_found) {
0476             return NGX_ERROR;
0477         }
0478 
0479         if (vv->len == 0 || (vv->len == 1 && vv->data[0] == '0')) {
0480 
0481             if (conf->mark == '\0'
0482                 || (ctx->cookie.len > 23
0483                     && ctx->cookie.data[22] == conf->mark
0484                     && ctx->cookie.data[23] == '='))
0485             {
0486                 return NGX_OK;
0487             }
0488 
0489             ctx->uid_set[0] = ctx->uid_got[0];
0490             ctx->uid_set[1] = ctx->uid_got[1];
0491             ctx->uid_set[2] = ctx->uid_got[2];
0492             ctx->uid_set[3] = ctx->uid_got[3];
0493 
0494             return NGX_OK;
0495 
0496         } else {
0497             ctx->reset = 1;
0498 
0499             if (vv->len == 3 && ngx_strncmp(vv->data, "log", 3) == 0) {
0500                 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
0501                         "userid cookie \"%V=%08XD%08XD%08XD%08XD\" was reset",
0502                         &conf->name, ctx->uid_got[0], ctx->uid_got[1],
0503                         ctx->uid_got[2], ctx->uid_got[3]);
0504             }
0505         }
0506     }
0507 
0508     /*
0509      * TODO: in the threaded mode the sequencers should be in TLS and their
0510      * ranges should be divided between threads
0511      */
0512 
0513     if (conf->enable == NGX_HTTP_USERID_V1) {
0514         if (conf->service == NGX_CONF_UNSET) {
0515             ctx->uid_set[0] = 0;
0516         } else {
0517             ctx->uid_set[0] = conf->service;
0518         }
0519         ctx->uid_set[1] = (uint32_t) ngx_time();
0520         ctx->uid_set[2] = start_value;
0521         ctx->uid_set[3] = sequencer_v1;
0522         sequencer_v1 += 0x100;
0523 
0524     } else {
0525         if (conf->service == NGX_CONF_UNSET) {
0526 
0527             c = r->connection;
0528 
0529             if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
0530                 return NGX_ERROR;
0531             }
0532 
0533             switch (c->local_sockaddr->sa_family) {
0534 
0535 #if (NGX_HAVE_INET6)
0536             case AF_INET6:
0537                 sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
0538 
0539                 p = (u_char *) &ctx->uid_set[0];
0540 
0541                 *p++ = sin6->sin6_addr.s6_addr[12];
0542                 *p++ = sin6->sin6_addr.s6_addr[13];
0543                 *p++ = sin6->sin6_addr.s6_addr[14];
0544                 *p = sin6->sin6_addr.s6_addr[15];
0545 
0546                 break;
0547 #endif
0548             default: /* AF_INET */
0549                 sin = (struct sockaddr_in *) c->local_sockaddr;
0550                 ctx->uid_set[0] = sin->sin_addr.s_addr;
0551                 break;
0552             }
0553 
0554         } else {
0555             ctx->uid_set[0] = htonl(conf->service);
0556         }
0557 
0558         ctx->uid_set[1] = htonl((uint32_t) ngx_time());
0559         ctx->uid_set[2] = htonl(start_value);
0560         ctx->uid_set[3] = htonl(sequencer_v2);
0561         sequencer_v2 += 0x100;
0562         if (sequencer_v2 < 0x03030302) {
0563             sequencer_v2 = 0x03030302;
0564         }
0565     }
0566 
0567     return NGX_OK;
0568 }
0569 
0570 
0571 static ngx_int_t
0572 ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0573     ngx_str_t *name, uint32_t *uid)
0574 {
0575     v->len = name->len + sizeof("=00001111222233334444555566667777") - 1;
0576     v->data = ngx_pnalloc(r->pool, v->len);
0577     if (v->data == NULL) {
0578         return NGX_ERROR;
0579     }
0580 
0581     v->valid = 1;
0582     v->no_cacheable = 0;
0583     v->not_found = 0;
0584 
0585     ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD",
0586                 name, uid[0], uid[1], uid[2], uid[3]);
0587 
0588     return NGX_OK;
0589 }
0590 
0591 
0592 static ngx_int_t
0593 ngx_http_userid_reset_variable(ngx_http_request_t *r,
0594     ngx_http_variable_value_t *v, uintptr_t data)
0595 {
0596     *v = ngx_http_variable_null_value;
0597 
0598     return NGX_OK;
0599 }
0600 
0601 
0602 static ngx_int_t
0603 ngx_http_userid_add_variables(ngx_conf_t *cf)
0604 {
0605     ngx_int_t             n;
0606     ngx_http_variable_t  *var;
0607 
0608     var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
0609     if (var == NULL) {
0610         return NGX_ERROR;
0611     }
0612 
0613     var->get_handler = ngx_http_userid_got_variable;
0614 
0615     var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
0616     if (var == NULL) {
0617         return NGX_ERROR;
0618     }
0619 
0620     var->get_handler = ngx_http_userid_set_variable;
0621 
0622     var = ngx_http_add_variable(cf, &ngx_http_userid_reset,
0623                                 NGX_HTTP_VAR_CHANGEABLE);
0624     if (var == NULL) {
0625         return NGX_ERROR;
0626     }
0627 
0628     var->get_handler = ngx_http_userid_reset_variable;
0629 
0630     n = ngx_http_get_variable_index(cf, &ngx_http_userid_reset);
0631     if (n == NGX_ERROR) {
0632         return NGX_ERROR;
0633     }
0634 
0635     ngx_http_userid_reset_index = n;
0636 
0637     return NGX_OK;
0638 }
0639 
0640 
0641 static void *
0642 ngx_http_userid_create_conf(ngx_conf_t *cf)
0643 {
0644     ngx_http_userid_conf_t  *conf;
0645 
0646     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t));
0647     if (conf == NULL) {
0648         return NULL;
0649     }
0650 
0651     /*
0652      * set by ngx_pcalloc():
0653      *
0654      *     conf->name = { 0, NULL };
0655      *     conf->domain = { 0, NULL };
0656      *     conf->path = { 0, NULL };
0657      *     conf->p3p = { 0, NULL };
0658      */
0659 
0660     conf->enable = NGX_CONF_UNSET_UINT;
0661     conf->service = NGX_CONF_UNSET;
0662     conf->expires = NGX_CONF_UNSET;
0663     conf->mark = (u_char) '\xFF';
0664 
0665     return conf;
0666 }
0667 
0668 
0669 static char *
0670 ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child)
0671 {
0672     ngx_http_userid_conf_t *prev = parent;
0673     ngx_http_userid_conf_t *conf = child;
0674 
0675     ngx_conf_merge_uint_value(conf->enable, prev->enable,
0676                               NGX_HTTP_USERID_OFF);
0677 
0678     ngx_conf_merge_str_value(conf->name, prev->name, "uid");
0679     ngx_conf_merge_str_value(conf->domain, prev->domain, "");
0680     ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
0681     ngx_conf_merge_str_value(conf->p3p, prev->p3p, "");
0682 
0683     ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET);
0684     ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
0685 
0686     if (conf->mark == (u_char) '\xFF') {
0687         if (prev->mark == (u_char) '\xFF') {
0688             conf->mark = '\0';
0689         } else {
0690             conf->mark = prev->mark;
0691         }
0692     }
0693 
0694     return NGX_CONF_OK;
0695 }
0696 
0697 
0698 static ngx_int_t
0699 ngx_http_userid_init(ngx_conf_t *cf)
0700 {
0701     ngx_http_next_header_filter = ngx_http_top_header_filter;
0702     ngx_http_top_header_filter = ngx_http_userid_filter;
0703 
0704     return NGX_OK;
0705 }
0706 
0707 
0708 static char *
0709 ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data)
0710 {
0711     ngx_str_t  *domain = data;
0712 
0713     u_char  *p, *new;
0714 
0715     if (ngx_strcmp(domain->data, "none") == 0) {
0716         ngx_str_set(domain, "");
0717         return NGX_CONF_OK;
0718     }
0719 
0720     new = ngx_pnalloc(cf->pool, sizeof("; domain=") - 1 + domain->len);
0721     if (new == NULL) {
0722         return NGX_CONF_ERROR;
0723     }
0724 
0725     p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1);
0726     ngx_memcpy(p, domain->data, domain->len);
0727 
0728     domain->len += sizeof("; domain=") - 1;
0729     domain->data = new;
0730 
0731     return NGX_CONF_OK;
0732 }
0733 
0734 
0735 static char *
0736 ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data)
0737 {
0738     ngx_str_t  *path = data;
0739 
0740     u_char  *p, *new;
0741 
0742     new = ngx_pnalloc(cf->pool, sizeof("; path=") - 1 + path->len);
0743     if (new == NULL) {
0744         return NGX_CONF_ERROR;
0745     }
0746 
0747     p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1);
0748     ngx_memcpy(p, path->data, path->len);
0749 
0750     path->len += sizeof("; path=") - 1;
0751     path->data = new;
0752 
0753     return NGX_CONF_OK;
0754 }
0755 
0756 
0757 static char *
0758 ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0759 {
0760     ngx_http_userid_conf_t *ucf = conf;
0761 
0762     ngx_str_t  *value;
0763 
0764     if (ucf->expires != NGX_CONF_UNSET) {
0765         return "is duplicate";
0766     }
0767 
0768     value = cf->args->elts;
0769 
0770     if (ngx_strcmp(value[1].data, "max") == 0) {
0771         ucf->expires = NGX_HTTP_USERID_MAX_EXPIRES;
0772         return NGX_CONF_OK;
0773     }
0774 
0775     if (ngx_strcmp(value[1].data, "off") == 0) {
0776         ucf->expires = 0;
0777         return NGX_CONF_OK;
0778     }
0779 
0780     ucf->expires = ngx_parse_time(&value[1], 1);
0781     if (ucf->expires == (time_t) NGX_ERROR) {
0782         return "invalid value";
0783     }
0784 
0785     return NGX_CONF_OK;
0786 }
0787 
0788 
0789 static char *
0790 ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data)
0791 {
0792     ngx_str_t  *p3p = data;
0793 
0794     if (ngx_strcmp(p3p->data, "none") == 0) {
0795         ngx_str_set(p3p, "");
0796     }
0797 
0798     return NGX_CONF_OK;
0799 }
0800 
0801 
0802 static char *
0803 ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0804 {
0805     ngx_http_userid_conf_t *ucf = conf;
0806 
0807     ngx_str_t  *value;
0808 
0809     if (ucf->mark != (u_char) '\xFF') {
0810         return "is duplicate";
0811     }
0812 
0813     value = cf->args->elts;
0814 
0815     if (ngx_strcmp(value[1].data, "off") == 0) {
0816         ucf->mark = '\0';
0817         return NGX_CONF_OK;
0818     }
0819 
0820     if (value[1].len != 1
0821         || !((value[1].data[0] >= '0' && value[1].data[0] <= '9')
0822               || (value[1].data[0] >= 'A' && value[1].data[0] <= 'Z')
0823               || (value[1].data[0] >= 'a' && value[1].data[0] <= 'z')
0824               || value[1].data[0] == '='))
0825     {
0826         return "value must be \"off\" or a single letter, digit or \"=\"";
0827     }
0828 
0829     ucf->mark = value[1].data[0];
0830 
0831     return NGX_CONF_OK;
0832 }
0833 
0834 
0835 static ngx_int_t
0836 ngx_http_userid_init_worker(ngx_cycle_t *cycle)
0837 {
0838     struct timeval  tp;
0839 
0840     ngx_gettimeofday(&tp);
0841 
0842     /* use the most significant usec part that fits to 16 bits */
0843     start_value = (((uint32_t) tp.tv_usec / 20) << 16) | ngx_pid;
0844 
0845     return NGX_OK;
0846 }