Back to home page

Nginx displayed by LXR

Source navigation ]
Diff markup ]
Identifier search ]
general search ]
 
 
Version: nginx-1.15.11 ]​[ nginx-1.14.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 
0549 #if (NGX_HAVE_UNIX_DOMAIN)
0550             case AF_UNIX:
0551                 ctx->uid_set[0] = 0;
0552                 break;
0553 #endif
0554 
0555             default: /* AF_INET */
0556                 sin = (struct sockaddr_in *) c->local_sockaddr;
0557                 ctx->uid_set[0] = sin->sin_addr.s_addr;
0558                 break;
0559             }
0560 
0561         } else {
0562             ctx->uid_set[0] = htonl(conf->service);
0563         }
0564 
0565         ctx->uid_set[1] = htonl((uint32_t) ngx_time());
0566         ctx->uid_set[2] = htonl(start_value);
0567         ctx->uid_set[3] = htonl(sequencer_v2);
0568         sequencer_v2 += 0x100;
0569         if (sequencer_v2 < 0x03030302) {
0570             sequencer_v2 = 0x03030302;
0571         }
0572     }
0573 
0574     return NGX_OK;
0575 }
0576 
0577 
0578 static ngx_int_t
0579 ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v,
0580     ngx_str_t *name, uint32_t *uid)
0581 {
0582     v->len = name->len + sizeof("=00001111222233334444555566667777") - 1;
0583     v->data = ngx_pnalloc(r->pool, v->len);
0584     if (v->data == NULL) {
0585         return NGX_ERROR;
0586     }
0587 
0588     v->valid = 1;
0589     v->no_cacheable = 0;
0590     v->not_found = 0;
0591 
0592     ngx_sprintf(v->data, "%V=%08XD%08XD%08XD%08XD",
0593                 name, uid[0], uid[1], uid[2], uid[3]);
0594 
0595     return NGX_OK;
0596 }
0597 
0598 
0599 static ngx_int_t
0600 ngx_http_userid_reset_variable(ngx_http_request_t *r,
0601     ngx_http_variable_value_t *v, uintptr_t data)
0602 {
0603     *v = ngx_http_variable_null_value;
0604 
0605     return NGX_OK;
0606 }
0607 
0608 
0609 static ngx_int_t
0610 ngx_http_userid_add_variables(ngx_conf_t *cf)
0611 {
0612     ngx_int_t             n;
0613     ngx_http_variable_t  *var;
0614 
0615     var = ngx_http_add_variable(cf, &ngx_http_userid_got, 0);
0616     if (var == NULL) {
0617         return NGX_ERROR;
0618     }
0619 
0620     var->get_handler = ngx_http_userid_got_variable;
0621 
0622     var = ngx_http_add_variable(cf, &ngx_http_userid_set, 0);
0623     if (var == NULL) {
0624         return NGX_ERROR;
0625     }
0626 
0627     var->get_handler = ngx_http_userid_set_variable;
0628 
0629     var = ngx_http_add_variable(cf, &ngx_http_userid_reset,
0630                                 NGX_HTTP_VAR_CHANGEABLE);
0631     if (var == NULL) {
0632         return NGX_ERROR;
0633     }
0634 
0635     var->get_handler = ngx_http_userid_reset_variable;
0636 
0637     n = ngx_http_get_variable_index(cf, &ngx_http_userid_reset);
0638     if (n == NGX_ERROR) {
0639         return NGX_ERROR;
0640     }
0641 
0642     ngx_http_userid_reset_index = n;
0643 
0644     return NGX_OK;
0645 }
0646 
0647 
0648 static void *
0649 ngx_http_userid_create_conf(ngx_conf_t *cf)
0650 {
0651     ngx_http_userid_conf_t  *conf;
0652 
0653     conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t));
0654     if (conf == NULL) {
0655         return NULL;
0656     }
0657 
0658     /*
0659      * set by ngx_pcalloc():
0660      *
0661      *     conf->name = { 0, NULL };
0662      *     conf->domain = { 0, NULL };
0663      *     conf->path = { 0, NULL };
0664      *     conf->p3p = { 0, NULL };
0665      */
0666 
0667     conf->enable = NGX_CONF_UNSET_UINT;
0668     conf->service = NGX_CONF_UNSET;
0669     conf->expires = NGX_CONF_UNSET;
0670     conf->mark = (u_char) '\xFF';
0671 
0672     return conf;
0673 }
0674 
0675 
0676 static char *
0677 ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child)
0678 {
0679     ngx_http_userid_conf_t *prev = parent;
0680     ngx_http_userid_conf_t *conf = child;
0681 
0682     ngx_conf_merge_uint_value(conf->enable, prev->enable,
0683                               NGX_HTTP_USERID_OFF);
0684 
0685     ngx_conf_merge_str_value(conf->name, prev->name, "uid");
0686     ngx_conf_merge_str_value(conf->domain, prev->domain, "");
0687     ngx_conf_merge_str_value(conf->path, prev->path, "; path=/");
0688     ngx_conf_merge_str_value(conf->p3p, prev->p3p, "");
0689 
0690     ngx_conf_merge_value(conf->service, prev->service, NGX_CONF_UNSET);
0691     ngx_conf_merge_sec_value(conf->expires, prev->expires, 0);
0692 
0693     if (conf->mark == (u_char) '\xFF') {
0694         if (prev->mark == (u_char) '\xFF') {
0695             conf->mark = '\0';
0696         } else {
0697             conf->mark = prev->mark;
0698         }
0699     }
0700 
0701     return NGX_CONF_OK;
0702 }
0703 
0704 
0705 static ngx_int_t
0706 ngx_http_userid_init(ngx_conf_t *cf)
0707 {
0708     ngx_http_next_header_filter = ngx_http_top_header_filter;
0709     ngx_http_top_header_filter = ngx_http_userid_filter;
0710 
0711     return NGX_OK;
0712 }
0713 
0714 
0715 static char *
0716 ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data)
0717 {
0718     ngx_str_t  *domain = data;
0719 
0720     u_char  *p, *new;
0721 
0722     if (ngx_strcmp(domain->data, "none") == 0) {
0723         ngx_str_set(domain, "");
0724         return NGX_CONF_OK;
0725     }
0726 
0727     new = ngx_pnalloc(cf->pool, sizeof("; domain=") - 1 + domain->len);
0728     if (new == NULL) {
0729         return NGX_CONF_ERROR;
0730     }
0731 
0732     p = ngx_cpymem(new, "; domain=", sizeof("; domain=") - 1);
0733     ngx_memcpy(p, domain->data, domain->len);
0734 
0735     domain->len += sizeof("; domain=") - 1;
0736     domain->data = new;
0737 
0738     return NGX_CONF_OK;
0739 }
0740 
0741 
0742 static char *
0743 ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data)
0744 {
0745     ngx_str_t  *path = data;
0746 
0747     u_char  *p, *new;
0748 
0749     new = ngx_pnalloc(cf->pool, sizeof("; path=") - 1 + path->len);
0750     if (new == NULL) {
0751         return NGX_CONF_ERROR;
0752     }
0753 
0754     p = ngx_cpymem(new, "; path=", sizeof("; path=") - 1);
0755     ngx_memcpy(p, path->data, path->len);
0756 
0757     path->len += sizeof("; path=") - 1;
0758     path->data = new;
0759 
0760     return NGX_CONF_OK;
0761 }
0762 
0763 
0764 static char *
0765 ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0766 {
0767     ngx_http_userid_conf_t *ucf = conf;
0768 
0769     ngx_str_t  *value;
0770 
0771     if (ucf->expires != NGX_CONF_UNSET) {
0772         return "is duplicate";
0773     }
0774 
0775     value = cf->args->elts;
0776 
0777     if (ngx_strcmp(value[1].data, "max") == 0) {
0778         ucf->expires = NGX_HTTP_USERID_MAX_EXPIRES;
0779         return NGX_CONF_OK;
0780     }
0781 
0782     if (ngx_strcmp(value[1].data, "off") == 0) {
0783         ucf->expires = 0;
0784         return NGX_CONF_OK;
0785     }
0786 
0787     ucf->expires = ngx_parse_time(&value[1], 1);
0788     if (ucf->expires == (time_t) NGX_ERROR) {
0789         return "invalid value";
0790     }
0791 
0792     return NGX_CONF_OK;
0793 }
0794 
0795 
0796 static char *
0797 ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data)
0798 {
0799     ngx_str_t  *p3p = data;
0800 
0801     if (ngx_strcmp(p3p->data, "none") == 0) {
0802         ngx_str_set(p3p, "");
0803     }
0804 
0805     return NGX_CONF_OK;
0806 }
0807 
0808 
0809 static char *
0810 ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
0811 {
0812     ngx_http_userid_conf_t *ucf = conf;
0813 
0814     ngx_str_t  *value;
0815 
0816     if (ucf->mark != (u_char) '\xFF') {
0817         return "is duplicate";
0818     }
0819 
0820     value = cf->args->elts;
0821 
0822     if (ngx_strcmp(value[1].data, "off") == 0) {
0823         ucf->mark = '\0';
0824         return NGX_CONF_OK;
0825     }
0826 
0827     if (value[1].len != 1
0828         || !((value[1].data[0] >= '0' && value[1].data[0] <= '9')
0829               || (value[1].data[0] >= 'A' && value[1].data[0] <= 'Z')
0830               || (value[1].data[0] >= 'a' && value[1].data[0] <= 'z')
0831               || value[1].data[0] == '='))
0832     {
0833         return "value must be \"off\" or a single letter, digit or \"=\"";
0834     }
0835 
0836     ucf->mark = value[1].data[0];
0837 
0838     return NGX_CONF_OK;
0839 }
0840 
0841 
0842 static ngx_int_t
0843 ngx_http_userid_init_worker(ngx_cycle_t *cycle)
0844 {
0845     struct timeval  tp;
0846 
0847     ngx_gettimeofday(&tp);
0848 
0849     /* use the most significant usec part that fits to 16 bits */
0850     start_value = (((uint32_t) tp.tv_usec / 20) << 16) | ngx_pid;
0851 
0852     return NGX_OK;
0853 }