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->len == 0 || (vv->len == 1 && vv->data[0] == '0')) {
0476 
0477             if (conf->mark == '\0'
0478                 || (ctx->cookie.len > 23
0479                     && ctx->cookie.data[22] == conf->mark
0480                     && ctx->cookie.data[23] == '='))
0481             {
0482                 return NGX_OK;
0483             }
0484 
0485             ctx->uid_set[0] = ctx->uid_got[0];
0486             ctx->uid_set[1] = ctx->uid_got[1];
0487             ctx->uid_set[2] = ctx->uid_got[2];
0488             ctx->uid_set[3] = ctx->uid_got[3];
0489 
0490             return NGX_OK;
0491 
0492         } else {
0493             ctx->reset = 1;
0494 
0495             if (vv->len == 3 && ngx_strncmp(vv->data, "log", 3) == 0) {
0496                 ngx_log_error(NGX_LOG_NOTICE, r->connection->log, 0,
0497                         "userid cookie \"%V=%08XD%08XD%08XD%08XD\" was reset",
0498                         &conf->name, ctx->uid_got[0], ctx->uid_got[1],
0499                         ctx->uid_got[2], ctx->uid_got[3]);
0500             }
0501         }
0502     }
0503 
0504     /*
0505      * TODO: in the threaded mode the sequencers should be in TLS and their
0506      * ranges should be divided between threads
0507      */
0508 
0509     if (conf->enable == NGX_HTTP_USERID_V1) {
0510         if (conf->service == NGX_CONF_UNSET) {
0511             ctx->uid_set[0] = 0;
0512         } else {
0513             ctx->uid_set[0] = conf->service;
0514         }
0515         ctx->uid_set[1] = (uint32_t) ngx_time();
0516         ctx->uid_set[2] = start_value;
0517         ctx->uid_set[3] = sequencer_v1;
0518         sequencer_v1 += 0x100;
0519 
0520     } else {
0521         if (conf->service == NGX_CONF_UNSET) {
0522 
0523             c = r->connection;
0524 
0525             if (ngx_connection_local_sockaddr(c, NULL, 0) != NGX_OK) {
0526                 return NGX_ERROR;
0527             }
0528 
0529             switch (c->local_sockaddr->sa_family) {
0530 
0531 #if (NGX_HAVE_INET6)
0532             case AF_INET6:
0533                 sin6 = (struct sockaddr_in6 *) c->local_sockaddr;
0534 
0535                 p = (u_char *) &ctx->uid_set[0];
0536 
0537                 *p++ = sin6->sin6_addr.s6_addr[12];
0538                 *p++ = sin6->sin6_addr.s6_addr[13];
0539                 *p++ = sin6->sin6_addr.s6_addr[14];
0540                 *p = sin6->sin6_addr.s6_addr[15];
0541 
0542                 break;
0543 #endif
0544             default: /* AF_INET */
0545                 sin = (struct sockaddr_in *) c->local_sockaddr;
0546                 ctx->uid_set[0] = sin->sin_addr.s_addr;
0547                 break;
0548             }
0549 
0550         } else {
0551             ctx->uid_set[0] = htonl(conf->service);
0552         }
0553 
0554         ctx->uid_set[1] = htonl((uint32_t) ngx_time());
0555         ctx->uid_set[2] = htonl(start_value);
0556         ctx->uid_set[3] = htonl(sequencer_v2);
0557         sequencer_v2 += 0x100;
0558         if (sequencer_v2 < 0x03030302) {
0559             sequencer_v2 = 0x03030302;
0560         }
0561     }
0562 
0563     return NGX_OK;
0564 }
0565 
0566 
0567 static ngx_int_t
0568 ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0569     ngx_str_t *name, uint32_t *uid)
0570 {
0571     v->len = name->len + sizeof("=00001111222233334444555566667777") - 1;
0572     v->data = ngx_pnalloc(r->pool, v->len);
0573     if (v->data == NULL) {
0574         return NGX_ERROR;
0575     }
0576 
0577     v->valid = 1;
0578     v->no_cacheable = 0;
0579     v->not_found = 0;
0580 
0581     ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD",
0582                 name, uid[0], uid[1], uid[2], uid[3]);
0583 
0584     return NGX_OK;
0585 }
0586 
0587 
0588 static ngx_int_t
0589 ngx_http_userid_reset_variable(ngx_http_request_t *r,
0590     ngx_http_variable_value_t *v, uintptr_t data)
0591 {
0592     *v = ngx_http_variable_null_value;
0593 
0594     return NGX_OK;
0595 }
0596 
0597 
0598 static ngx_int_t
0599 ngx_http_userid_add_variables(ngx_conf_t *cf)
0600 {
0601     ngx_int_t             n;
0602     ngx_http_variable_t  *var;
0603 
0604     var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
0605     if (var == NULL) {
0606         return NGX_ERROR;
0607     }
0608 
0609     var->get_handler = ngx_http_userid_got_variable;
0610 
0611     var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
0612     if (var == NULL) {
0613         return NGX_ERROR;
0614     }
0615 
0616     var->get_handler = ngx_http_userid_set_variable;
0617 
0618     var = ngx_http_add_variable(cf, &ngx_http_userid_reset,
0619                                 NGX_HTTP_VAR_CHANGEABLE);
0620     if (var == NULL) {
0621         return NGX_ERROR;
0622     }
0623 
0624     var->get_handler = ngx_http_userid_reset_variable;
0625 
0626     n = ngx_http_get_variable_index(cf, &ngx_http_userid_reset);
0627     if (n == NGX_ERROR) {
0628         return NGX_ERROR;
0629     }
0630 
0631     ngx_http_userid_reset_index = n;
0632 
0633     return NGX_OK;
0634 }
0635 
0636 
0637 static void *
0638 ngx_http_userid_create_conf(ngx_conf_t *cf)
0639 {
0640     ngx_http_userid_conf_t  *conf;
0641 
0642     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t));
0643     if (conf == NULL) {
0644         return NULL;
0645     }
0646 
0647     /*
0648      * set by ngx_pcalloc():
0649      *
0650      *     conf->name = { 0, NULL };
0651      *     conf->domain = { 0, NULL };
0652      *     conf->path = { 0, NULL };
0653      *     conf->p3p = { 0, NULL };
0654      */
0655 
0656     conf->enable = NGX_CONF_UNSET_UINT;
0657     conf->service = NGX_CONF_UNSET;
0658     conf->expires = NGX_CONF_UNSET;
0659     conf->mark = (u_char) '\xFF';
0660 
0661     return conf;
0662 }
0663 
0664 
0665 static char *
0666 ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child)
0667 {
0668     ngx_http_userid_conf_t *prev = parent;
0669     ngx_http_userid_conf_t *conf = child;
0670 
0671     ngx_conf_merge_uint_value(conf->enable, prev->enable,
0672                               NGX_HTTP_USERID_OFF);
0673 
0674     ngx_conf_merge_str_value(conf->name, prev->name, "uid");
0675     ngx_conf_merge_str_value(conf->domain, prev->domain, "");
0676     ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
0677     ngx_conf_merge_str_value(conf->p3p, prev->p3p, "");
0678 
0679     ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET);
0680     ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
0681 
0682     if (conf->mark == (u_char) '\xFF') {
0683         if (prev->mark == (u_char) '\xFF') {
0684             conf->mark = '\0';
0685         } else {
0686             conf->mark = prev->mark;
0687         }
0688     }
0689 
0690     return NGX_CONF_OK;
0691 }
0692 
0693 
0694 static ngx_int_t
0695 ngx_http_userid_init(ngx_conf_t *cf)
0696 {
0697     ngx_http_next_header_filter = ngx_http_top_header_filter;
0698     ngx_http_top_header_filter = ngx_http_userid_filter;
0699 
0700     return NGX_OK;
0701 }
0702 
0703 
0704 static char *
0705 ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data)
0706 {
0707     ngx_str_t  *domain = data;
0708 
0709     u_char  *p, *new;
0710 
0711     if (ngx_strcmp(domain->data, "none") == 0) {
0712         ngx_str_set(domain, "");
0713         return NGX_CONF_OK;
0714     }
0715 
0716     new = ngx_pnalloc(cf->pool, sizeof("; domain=") - 1 + domain->len);
0717     if (new == NULL) {
0718         return NGX_CONF_ERROR;
0719     }
0720 
0721     p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1);
0722     ngx_memcpy(p, domain->data, domain->len);
0723 
0724     domain->len += sizeof("; domain=") - 1;
0725     domain->data = new;
0726 
0727     return NGX_CONF_OK;
0728 }
0729 
0730 
0731 static char *
0732 ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data)
0733 {
0734     ngx_str_t  *path = data;
0735 
0736     u_char  *p, *new;
0737 
0738     new = ngx_pnalloc(cf->pool, sizeof("; path=") - 1 + path->len);
0739     if (new == NULL) {
0740         return NGX_CONF_ERROR;
0741     }
0742 
0743     p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1);
0744     ngx_memcpy(p, path->data, path->len);
0745 
0746     path->len += sizeof("; path=") - 1;
0747     path->data = new;
0748 
0749     return NGX_CONF_OK;
0750 }
0751 
0752 
0753 static char *
0754 ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0755 {
0756     ngx_http_userid_conf_t *ucf = conf;
0757 
0758     ngx_str_t  *value;
0759 
0760     if (ucf->expires != NGX_CONF_UNSET) {
0761         return "is duplicate";
0762     }
0763 
0764     value = cf->args->elts;
0765 
0766     if (ngx_strcmp(value[1].data, "max") == 0) {
0767         ucf->expires = NGX_HTTP_USERID_MAX_EXPIRES;
0768         return NGX_CONF_OK;
0769     }
0770 
0771     if (ngx_strcmp(value[1].data, "off") == 0) {
0772         ucf->expires = 0;
0773         return NGX_CONF_OK;
0774     }
0775 
0776     ucf->expires = ngx_parse_time(&value[1], 1);
0777     if (ucf->expires == (time_t) NGX_ERROR) {
0778         return "invalid value";
0779     }
0780 
0781     return NGX_CONF_OK;
0782 }
0783 
0784 
0785 static char *
0786 ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data)
0787 {
0788     ngx_str_t  *p3p = data;
0789 
0790     if (ngx_strcmp(p3p->data, "none") == 0) {
0791         ngx_str_set(p3p, "");
0792     }
0793 
0794     return NGX_CONF_OK;
0795 }
0796 
0797 
0798 static char *
0799 ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0800 {
0801     ngx_http_userid_conf_t *ucf = conf;
0802 
0803     ngx_str_t  *value;
0804 
0805     if (ucf->mark != (u_char) '\xFF') {
0806         return "is duplicate";
0807     }
0808 
0809     value = cf->args->elts;
0810 
0811     if (ngx_strcmp(value[1].data, "off") == 0) {
0812         ucf->mark = '\0';
0813         return NGX_CONF_OK;
0814     }
0815 
0816     if (value[1].len != 1
0817         || !((value[1].data[0] >= '0' && value[1].data[0] <= '9')
0818               || (value[1].data[0] >= 'A' && value[1].data[0] <= 'Z')
0819               || (value[1].data[0] >= 'a' && value[1].data[0] <= 'z')
0820               || value[1].data[0] == '='))
0821     {
0822         return "value must be \"off\" or a single letter, digit or \"=\"";
0823     }
0824 
0825     ucf->mark = value[1].data[0];
0826 
0827     return NGX_CONF_OK;
0828 }
0829 
0830 
0831 static ngx_int_t
0832 ngx_http_userid_init_worker(ngx_cycle_t *cycle)
0833 {
0834     struct timeval  tp;
0835 
0836     ngx_gettimeofday(&tp);
0837 
0838     /* use the most significant usec part that fits to 16 bits */
0839     start_value = (((uint32_t) tp.tv_usec / 20) << 16) | ngx_pid;
0840 
0841     return NGX_OK;
0842 }