1e18a033bSKonstantin Ananyev
2e18a033bSKonstantin Ananyev/*
3e18a033bSKonstantin Ananyev * Copyright (C) Igor Sysoev
4e18a033bSKonstantin Ananyev * Copyright (C) Nginx, Inc.
5e18a033bSKonstantin Ananyev */
6e18a033bSKonstantin Ananyev
7e18a033bSKonstantin Ananyev
8e18a033bSKonstantin Ananyev#include <ngx_config.h>
9e18a033bSKonstantin Ananyev#include <ngx_core.h>
10e18a033bSKonstantin Ananyev#include <ngx_http.h>
11e18a033bSKonstantin Ananyev
12e18a033bSKonstantin Ananyev
13e18a033bSKonstantin Ananyev#define NGX_HTTP_USERID_OFF   0
14e18a033bSKonstantin Ananyev#define NGX_HTTP_USERID_LOG   1
15e18a033bSKonstantin Ananyev#define NGX_HTTP_USERID_V1    2
16e18a033bSKonstantin Ananyev#define NGX_HTTP_USERID_ON    3
17e18a033bSKonstantin Ananyev
18e18a033bSKonstantin Ananyev/* 31 Dec 2037 23:55:55 GMT */
19e18a033bSKonstantin Ananyev#define NGX_HTTP_USERID_MAX_EXPIRES  2145916555
20e18a033bSKonstantin Ananyev
21e18a033bSKonstantin Ananyev
22e18a033bSKonstantin Ananyevtypedef struct {
23e18a033bSKonstantin Ananyev    ngx_uint_t  enable;
24e18a033bSKonstantin Ananyev
25e18a033bSKonstantin Ananyev    ngx_int_t   service;
26e18a033bSKonstantin Ananyev
27e18a033bSKonstantin Ananyev    ngx_str_t   name;
28e18a033bSKonstantin Ananyev    ngx_str_t   domain;
29e18a033bSKonstantin Ananyev    ngx_str_t   path;
30e18a033bSKonstantin Ananyev    ngx_str_t   p3p;
31e18a033bSKonstantin Ananyev
32e18a033bSKonstantin Ananyev    time_t      expires;
33e18a033bSKonstantin Ananyev
34e18a033bSKonstantin Ananyev    u_char      mark;
35e18a033bSKonstantin Ananyev} ngx_http_userid_conf_t;
36e18a033bSKonstantin Ananyev
37e18a033bSKonstantin Ananyev
38e18a033bSKonstantin Ananyevtypedef struct {
39e18a033bSKonstantin Ananyev    uint32_t    uid_got[4];
40e18a033bSKonstantin Ananyev    uint32_t    uid_set[4];
41e18a033bSKonstantin Ananyev    ngx_str_t   cookie;
42e18a033bSKonstantin Ananyev    ngx_uint_t  reset;
43e18a033bSKonstantin Ananyev} ngx_http_userid_ctx_t;
44e18a033bSKonstantin Ananyev
45e18a033bSKonstantin Ananyev
46e18a033bSKonstantin Ananyevstatic ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r,
47e18a033bSKonstantin Ananyev    ngx_http_userid_conf_t *conf);
48e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r,
49e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid);
50e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,
51e18a033bSKonstantin Ananyev    ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
52e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r,
53e18a033bSKonstantin Ananyev    ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);
54e18a033bSKonstantin Ananyev
55e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf);
56e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_userid_init(ngx_conf_t *cf);
57e18a033bSKonstantin Ananyevstatic void *ngx_http_userid_create_conf(ngx_conf_t *cf);
58e18a033bSKonstantin Ananyevstatic char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent,
59e18a033bSKonstantin Ananyev    void *child);
60e18a033bSKonstantin Ananyevstatic char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data);
61e18a033bSKonstantin Ananyevstatic char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data);
62e18a033bSKonstantin Ananyevstatic char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd,
63e18a033bSKonstantin Ananyev    void *conf);
64e18a033bSKonstantin Ananyevstatic char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data);
65e18a033bSKonstantin Ananyevstatic char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd,
66e18a033bSKonstantin Ananyev    void *conf);
67e18a033bSKonstantin Ananyevstatic ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle);
68e18a033bSKonstantin Ananyev
69e18a033bSKonstantin Ananyev
70e18a033bSKonstantin Ananyev
71e18a033bSKonstantin Ananyevstatic uint32_t  start_value;
72e18a033bSKonstantin Ananyevstatic uint32_t  sequencer_v1 = 1;
73e18a033bSKonstantin Ananyevstatic uint32_t  sequencer_v2 = 0x03030302;
74e18a033bSKonstantin Ananyev
75e18a033bSKonstantin Ananyev
76e18a033bSKonstantin Ananyevstatic u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55 GMT";
77e18a033bSKonstantin Ananyev
78e18a033bSKonstantin Ananyev
79e18a033bSKonstantin Ananyevstatic ngx_http_output_header_filter_pt  ngx_http_next_header_filter;
80e18a033bSKonstantin Ananyev
81e18a033bSKonstantin Ananyev
82e18a033bSKonstantin Ananyevstatic ngx_conf_enum_t  ngx_http_userid_state[] = {
83e18a033bSKonstantin Ananyev    { ngx_string("off"), NGX_HTTP_USERID_OFF },
84e18a033bSKonstantin Ananyev    { ngx_string("log"), NGX_HTTP_USERID_LOG },
85e18a033bSKonstantin Ananyev    { ngx_string("v1"), NGX_HTTP_USERID_V1 },
86e18a033bSKonstantin Ananyev    { ngx_string("on"), NGX_HTTP_USERID_ON },
87e18a033bSKonstantin Ananyev    { ngx_null_string, 0 }
88e18a033bSKonstantin Ananyev};
89e18a033bSKonstantin Ananyev
90e18a033bSKonstantin Ananyev
91e18a033bSKonstantin Ananyevstatic ngx_conf_post_handler_pt  ngx_http_userid_domain_p =
92e18a033bSKonstantin Ananyev    ngx_http_userid_domain;
93e18a033bSKonstantin Ananyevstatic ngx_conf_post_handler_pt  ngx_http_userid_path_p = ngx_http_userid_path;
94e18a033bSKonstantin Ananyevstatic ngx_conf_post_handler_pt  ngx_http_userid_p3p_p = ngx_http_userid_p3p;
95e18a033bSKonstantin Ananyev
96e18a033bSKonstantin Ananyev
97e18a033bSKonstantin Ananyevstatic ngx_command_t  ngx_http_userid_commands[] = {
98e18a033bSKonstantin Ananyev
99e18a033bSKonstantin Ananyev    { ngx_string("userid"),
100e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
101e18a033bSKonstantin Ananyev      ngx_conf_set_enum_slot,
102e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
103e18a033bSKonstantin Ananyev      offsetof(ngx_http_userid_conf_t, enable),
104e18a033bSKonstantin Ananyev      ngx_http_userid_state },
105e18a033bSKonstantin Ananyev
106e18a033bSKonstantin Ananyev    { ngx_string("userid_service"),
107e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
108e18a033bSKonstantin Ananyev      ngx_conf_set_num_slot,
109e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
110e18a033bSKonstantin Ananyev      offsetof(ngx_http_userid_conf_t, service),
111e18a033bSKonstantin Ananyev      NULL },
112e18a033bSKonstantin Ananyev
113e18a033bSKonstantin Ananyev    { ngx_string("userid_name"),
114e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
115e18a033bSKonstantin Ananyev      ngx_conf_set_str_slot,
116e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
117e18a033bSKonstantin Ananyev      offsetof(ngx_http_userid_conf_t, name),
118e18a033bSKonstantin Ananyev      NULL },
119e18a033bSKonstantin Ananyev
120e18a033bSKonstantin Ananyev    { ngx_string("userid_domain"),
121e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
122e18a033bSKonstantin Ananyev      ngx_conf_set_str_slot,
123e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
124e18a033bSKonstantin Ananyev      offsetof(ngx_http_userid_conf_t, domain),
125e18a033bSKonstantin Ananyev      &ngx_http_userid_domain_p },
126e18a033bSKonstantin Ananyev
127e18a033bSKonstantin Ananyev    { ngx_string("userid_path"),
128e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
129e18a033bSKonstantin Ananyev      ngx_conf_set_str_slot,
130e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
131e18a033bSKonstantin Ananyev      offsetof(ngx_http_userid_conf_t, path),
132e18a033bSKonstantin Ananyev      &ngx_http_userid_path_p },
133e18a033bSKonstantin Ananyev
134e18a033bSKonstantin Ananyev    { ngx_string("userid_expires"),
135e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
136e18a033bSKonstantin Ananyev      ngx_http_userid_expires,
137e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
138e18a033bSKonstantin Ananyev      0,
139e18a033bSKonstantin Ananyev      NULL },
140e18a033bSKonstantin Ananyev
141e18a033bSKonstantin Ananyev    { ngx_string("userid_p3p"),
142e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
143e18a033bSKonstantin Ananyev      ngx_conf_set_str_slot,
144e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
145e18a033bSKonstantin Ananyev      offsetof(ngx_http_userid_conf_t, p3p),
146e18a033bSKonstantin Ananyev      &ngx_http_userid_p3p_p },
147e18a033bSKonstantin Ananyev
148e18a033bSKonstantin Ananyev    { ngx_string("userid_mark"),
149e18a033bSKonstantin Ananyev      NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1,
150e18a033bSKonstantin Ananyev      ngx_http_userid_mark,
151e18a033bSKonstantin Ananyev      NGX_HTTP_LOC_CONF_OFFSET,
152e18a033bSKonstantin Ananyev      0,
153e18a033bSKonstantin Ananyev      NULL },
154e18a033bSKonstantin Ananyev
155e18a033bSKonstantin Ananyev      ngx_null_command
156e18a033bSKonstantin Ananyev};
157e18a033bSKonstantin Ananyev
158e18a033bSKonstantin Ananyev
159e18a033bSKonstantin Ananyevstatic ngx_http_module_t  ngx_http_userid_filter_module_ctx = {
160e18a033bSKonstantin Ananyev    ngx_http_userid_add_variables,         /* preconfiguration */
161e18a033bSKonstantin Ananyev    ngx_http_userid_init,                  /* postconfiguration */
162e18a033bSKonstantin Ananyev
163e18a033bSKonstantin Ananyev    NULL,                                  /* create main configuration */
164e18a033bSKonstantin Ananyev    NULL,                                  /* init main configuration */
165e18a033bSKonstantin Ananyev
166e18a033bSKonstantin Ananyev    NULL,                                  /* create server configuration */
167e18a033bSKonstantin Ananyev    NULL,                                  /* merge server configuration */
168e18a033bSKonstantin Ananyev
169e18a033bSKonstantin Ananyev    ngx_http_userid_create_conf,           /* create location configuration */
170e18a033bSKonstantin Ananyev    ngx_http_userid_merge_conf             /* merge location configuration */
171e18a033bSKonstantin Ananyev};
172e18a033bSKonstantin Ananyev
173e18a033bSKonstantin Ananyev
174e18a033bSKonstantin Ananyevngx_module_t  ngx_http_userid_filter_module = {
175e18a033bSKonstantin Ananyev    NGX_MODULE_V1,
176e18a033bSKonstantin Ananyev    &ngx_http_userid_filter_module_ctx,    /* module context */
177e18a033bSKonstantin Ananyev    ngx_http_userid_commands,              /* module directives */
178e18a033bSKonstantin Ananyev    NGX_HTTP_MODULE,                       /* module type */
179e18a033bSKonstantin Ananyev    NULL,                                  /* init master */
180e18a033bSKonstantin Ananyev    NULL,                                  /* init module */
181e18a033bSKonstantin Ananyev    ngx_http_userid_init_worker,           /* init process */
182e18a033bSKonstantin Ananyev    NULL,                                  /* init thread */
183e18a033bSKonstantin Ananyev    NULL,                                  /* exit thread */
184e18a033bSKonstantin Ananyev    NULL,                                  /* exit process */
185e18a033bSKonstantin Ananyev    NULL,                                  /* exit master */
186e18a033bSKonstantin Ananyev    NGX_MODULE_V1_PADDING
187e18a033bSKonstantin Ananyev};
188e18a033bSKonstantin Ananyev
189e18a033bSKonstantin Ananyev
190e18a033bSKonstantin Ananyevstatic ngx_str_t   ngx_http_userid_got = ngx_string("uid_got");
191e18a033bSKonstantin Ananyevstatic ngx_str_t   ngx_http_userid_set = ngx_string("uid_set");
192e18a033bSKonstantin Ananyevstatic ngx_str_t   ngx_http_userid_reset = ngx_string("uid_reset");
193e18a033bSKonstantin Ananyevstatic ngx_uint_t  ngx_http_userid_reset_index;
194e18a033bSKonstantin Ananyev
195e18a033bSKonstantin Ananyev
196e18a033bSKonstantin Ananyevstatic ngx_int_t
197e18a033bSKonstantin Ananyevngx_http_userid_filter(ngx_http_request_t *r)
198e18a033bSKonstantin Ananyev{
199e18a033bSKonstantin Ananyev    ngx_http_userid_ctx_t   *ctx;
200e18a033bSKonstantin Ananyev    ngx_http_userid_conf_t  *conf;
201e18a033bSKonstantin Ananyev
202e18a033bSKonstantin Ananyev    if (r != r->main) {
203e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
204e18a033bSKonstantin Ananyev    }
205e18a033bSKonstantin Ananyev
206e18a033bSKonstantin Ananyev    conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module);
207e18a033bSKonstantin Ananyev
208e18a033bSKonstantin Ananyev    if (conf->enable < NGX_HTTP_USERID_V1) {
209e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
210e18a033bSKonstantin Ananyev    }
211e18a033bSKonstantin Ananyev
212e18a033bSKonstantin Ananyev    ctx = ngx_http_userid_get_uid(r, conf);
213e18a033bSKonstantin Ananyev
214e18a033bSKonstantin Ananyev    if (ctx == NULL) {
215e18a033bSKonstantin Ananyev        return NGX_ERROR;
216e18a033bSKonstantin Ananyev    }
217e18a033bSKonstantin Ananyev
218e18a033bSKonstantin Ananyev    if (ngx_http_userid_set_uid(r, ctx, conf) == NGX_OK) {
219e18a033bSKonstantin Ananyev        return ngx_http_next_header_filter(r);
220e18a033bSKonstantin Ananyev    }
221e18a033bSKonstantin Ananyev
222e18a033bSKonstantin Ananyev    return NGX_ERROR;
223e18a033bSKonstantin Ananyev}
224e18a033bSKonstantin Ananyev
225e18a033bSKonstantin Ananyev
226e18a033bSKonstantin Ananyevstatic ngx_int_t
227e18a033bSKonstantin Ananyevngx_http_userid_got_variable(ngx_http_request_t *r,
228e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
229e18a033bSKonstantin Ananyev{
230e18a033bSKonstantin Ananyev    ngx_http_userid_ctx_t   *ctx;
231e18a033bSKonstantin Ananyev    ngx_http_userid_conf_t  *conf;
232e18a033bSKonstantin Ananyev
233e18a033bSKonstantin Ananyev    conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
234e18a033bSKonstantin Ananyev
235e18a033bSKonstantin Ananyev    if (conf->enable == NGX_HTTP_USERID_OFF) {
236e18a033bSKonstantin Ananyev        v->not_found = 1;
237e18a033bSKonstantin Ananyev        return NGX_OK;
238e18a033bSKonstantin Ananyev    }
239e18a033bSKonstantin Ananyev
240e18a033bSKonstantin Ananyev    ctx = ngx_http_userid_get_uid(r->main, conf);
241e18a033bSKonstantin Ananyev
242e18a033bSKonstantin Ananyev    if (ctx == NULL) {
243e18a033bSKonstantin Ananyev        return NGX_ERROR;
244e18a033bSKonstantin Ananyev    }
245e18a033bSKonstantin Ananyev
246e18a033bSKonstantin Ananyev    if (ctx->uid_got[3] != 0) {
247e18a033bSKonstantin Ananyev        return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_got);
248e18a033bSKonstantin Ananyev    }
249e18a033bSKonstantin Ananyev
250e18a033bSKonstantin Ananyev    v->not_found = 1;
251e18a033bSKonstantin Ananyev
252e18a033bSKonstantin Ananyev    return NGX_OK;
253e18a033bSKonstantin Ananyev}
254e18a033bSKonstantin Ananyev
255e18a033bSKonstantin Ananyev
256e18a033bSKonstantin Ananyevstatic ngx_int_t
257e18a033bSKonstantin Ananyevngx_http_userid_set_variable(ngx_http_request_t *r,
258e18a033bSKonstantin Ananyev    ngx_http_variable_value_t *v, uintptr_t data)
259e18a033bSKonstantin Ananyev{
260e18a033bSKonstantin Ananyev    ngx_http_userid_ctx_t   *ctx;
261e18a033bSKonstantin Ananyev    ngx_http_userid_conf_t  *conf;
262e18a033bSKonstantin Ananyev
263e18a033bSKonstantin Ananyev    conf = ngx_http_get_module_loc_conf(r->main, ngx_http_userid_filter_module);
264e18a033bSKonstantin Ananyev
265e18a033bSKonstantin Ananyev    if (conf->enable < NGX_HTTP_USERID_V1) {
266e18a033bSKonstantin Ananyev        v->not_found = 1;
267e18a033bSKonstantin Ananyev        return NGX_OK;
268e18a033bSKonstantin Ananyev    }
269e18a033bSKonstantin Ananyev
270e18a033bSKonstantin Ananyev    ctx = ngx_http_userid_get_uid(r->main, conf);
271e18a033bSKonstantin Ananyev
272e18a033bSKonstantin Ananyev    if (ctx == NULL) {
273e18a033bSKonstantin Ananyev        return NGX_ERROR;
274e18a033bSKonstantin Ananyev    }
275e18a033bSKonstantin Ananyev
276e18a033bSKonstantin Ananyev    if (ngx_http_userid_create_uid(r->main, ctx, conf) != NGX_OK) {
277e18a033bSKonstantin Ananyev        return NGX_ERROR;
278e18a033bSKonstantin Ananyev    }
279e18a033bSKonstantin Ananyev
280e18a033bSKonstantin Ananyev    if (ctx->uid_set[3] == 0) {
281e18a033bSKonstantin Ananyev        v->not_found = 1;
282e18a033bSKonstantin Ananyev        return NGX_OK;
283e18a033bSKonstantin Ananyev    }
284e18a033bSKonstantin Ananyev
285e18a033bSKonstantin Ananyev    return ngx_http_userid_variable(r->main, v, &conf->name, ctx->uid_set);
286e18a033bSKonstantin Ananyev}
287e18a033bSKonstantin Ananyev
288e18a033bSKonstantin Ananyev
289e18a033bSKonstantin Ananyevstatic ngx_http_userid_ctx_t *
290e18a033bSKonstantin Ananyevngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf)
291e18a033bSKonstantin Ananyev{
292e18a033bSKonstantin Ananyev    ngx_int_t                n;
293e18a033bSKonstantin Ananyev    ngx_str_t                src, dst;
294e18a033bSKonstantin Ananyev    ngx_table_elt_t        **cookies;
295e18a033bSKonstantin Ananyev    ngx_http_userid_ctx_t   *ctx;
296e18a033bSKonstantin Ananyev
297e18a033bSKonstantin Ananyev    ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module);
298e18a033bSKonstantin Ananyev
299e18a033bSKonstantin Ananyev    if (ctx) {
300e18a033bSKonstantin Ananyev        return ctx;
301e18a033bSKonstantin Ananyev    }
302e18a033bSKonstantin Ananyev
303e18a033bSKonstantin Ananyev    if (ctx == NULL) {
304e18a033bSKonstantin Ananyev        ctx = ngx_pcalloc(r->pool, sizeof(ngx_http_userid_ctx_t));
305e18a033bSKonstantin Ananyev        if (ctx == NULL) {
306e18a033bSKonstantin Ananyev            return NULL;
307e18a033bSKonstantin Ananyev        }
308e18a033bSKonstantin Ananyev
309e18a033bSKonstantin Ananyev        ngx_http_set_ctx(r, ctx, ngx_http_userid_filter_module);
310e18a033bSKonstantin Ananyev    }
311e18a033bSKonstantin Ananyev
312e18a033bSKonstantin Ananyev    n = ngx_http_parse_multi_header_lines(&r->headers_in.cookies, &conf->name,
313e18a033bSKonstantin Ananyev                                          &ctx->cookie);
314e18a033bSKonstantin Ananyev    if (n == NGX_DECLINED) {
315e18a033bSKonstantin Ananyev        return ctx;
316e18a033bSKonstantin Ananyev    }
317e18a033bSKonstantin Ananyev
318e18a033bSKonstantin Ananyev    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
319e18a033bSKonstantin Ananyev                   "uid cookie: \"%V\"", &ctx->cookie);
320e18a033bSKonstantin Ananyev
321e18a033bSKonstantin Ananyev    if (ctx->cookie.len < 22) {
322e18a033bSKonstantin Ananyev        cookies = r->headers_in.cookies.elts;
323e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
324e18a033bSKonstantin Ananyev                      "client sent too short userid cookie \"%V\"",
325e18a033bSKonstantin Ananyev                      &cookies[n]->value);
326e18a033bSKonstantin Ananyev        return ctx;
327e18a033bSKonstantin Ananyev    }
328e18a033bSKonstantin Ananyev
329e18a033bSKonstantin Ananyev    src = ctx->cookie;
330e18a033bSKonstantin Ananyev
331e18a033bSKonstantin Ananyev    /*
332e18a033bSKonstantin Ananyev     * we have to limit the encoded string to 22 characters because
333e18a033bSKonstantin Ananyev     *  1) cookie may be marked by "userid_mark",
334e18a033bSKonstantin Ananyev     *  2) and there are already the millions cookies with a garbage
335e18a033bSKonstantin Ananyev     *     instead of the correct base64 trail "=="
336e18a033bSKonstantin Ananyev     */
337e18a033bSKonstantin Ananyev
338e18a033bSKonstantin Ananyev    src.len = 22;
339e18a033bSKonstantin Ananyev
340e18a033bSKonstantin Ananyev    dst.data = (u_char *) ctx->uid_got;
341e18a033bSKonstantin Ananyev
342e18a033bSKonstantin Ananyev    if (ngx_decode_base64(&dst, &src) == NGX_ERROR) {
343e18a033bSKonstantin Ananyev        cookies = r->headers_in.cookies.elts;
344e18a033bSKonstantin Ananyev        ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
345e18a033bSKonstantin Ananyev                      "client sent invalid userid cookie \"%V\"",
346e18a033bSKonstantin Ananyev                      &cookies[n]->value);
347e18a033bSKonstantin Ananyev        return ctx;
348e18a033bSKonstantin Ananyev    }
349e18a033bSKonstantin Ananyev
350e18a033bSKonstantin Ananyev    ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
351e18a033bSKonstantin Ananyev                   "uid: %08XD%08XD%08XD%08XD",
352e18a033bSKonstantin Ananyev                   ctx->uid_got[0], ctx->uid_got[1],
353e18a033bSKonstantin Ananyev                   ctx->uid_got[2], ctx->uid_got[3]);
354e18a033bSKonstantin Ananyev
355e18a033bSKonstantin Ananyev    return ctx;
356e18a033bSKonstantin Ananyev}
357e18a033bSKonstantin Ananyev
358e18a033bSKonstantin Ananyev
359e18a033bSKonstantin Ananyevstatic ngx_int_t
360e18a033bSKonstantin Ananyevngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx,
361e18a033bSKonstantin Ananyev    ngx_http_userid_conf_t *conf)
362e18a033bSKonstantin Ananyev{
363e18a033bSKonstantin Ananyev    u_char           *cookie, *p;
364e18a033bSKonstantin Ananyev    size_t            len;
365e18a033bSKonstantin Ananyev    ngx_str_t         src, dst;
366e18a033bSKonstantin Ananyev    ngx_table_elt_t  *set_cookie, *p3p;
367e18a033bSKonstantin Ananyev
368e18a033bSKonstantin Ananyev    if (ngx_http_userid_create_uid(r, ctx, conf) != NGX_OK) {
369e18a033bSKonstantin Ananyev        return NGX_ERROR;
370e18a033bSKonstantin Ananyev    }
371e18a033bSKonstantin Ananyev
372e18a033bSKonstantin Ananyev    if (ctx->uid_set[3] == 0) {
373e18a033bSKonstantin Ananyev        return NGX_OK;
374e18a033bSKonstantin Ananyev    }
375e18a033bSKonstantin Ananyev
376e18a033bSKonstantin Ananyev    len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len;
377e18a033bSKonstantin Ananyev
378e18a033bSKonstantin Ananyev    if (conf->expires) {
379e18a033bSKonstantin Ananyev        len += sizeof(expires) - 1 + 2;
380e18a033bSKonstantin Ananyev    }
381e18a033bSKonstantin Ananyev
382e18a033bSKonstantin Ananyev    if (conf->domain.len) {
383e18a033bSKonstantin Ananyev        len += conf->domain.len;
384e18a033bSKonstantin Ananyev    }
385e18a033bSKonstantin Ananyev
386e18a033bSKonstantin Ananyev    cookie = ngx_pnalloc(r->pool, len);
387e18a033bSKonstantin Ananyev    if (cookie == NULL) {
388e18a033bSKonstantin Ananyev        return NGX_ERROR;
389e18a033bSKonstantin Ananyev    }
390e18a033bSKonstantin Ananyev
391e18a033bSKonstantin Ananyev    p = ngx_copy(cookie, conf->name.data, conf->name.len);
392e18a033bSKonstantin Ananyev    *p++ = '=';
393e18a033bSKonstantin Ananyev
394e18a033bSKonstantin Ananyev    if (ctx->uid_got[3] == 0 || ctx->reset) {
395e18a033bSKonstantin Ananyev        src.len = 16;
396e18a033bSKonstantin Ananyev        src.data = (u_char *) ctx->uid_set;
397e18a033bSKonstantin Ananyev        dst.data = p;
398e18a033bSKonstantin Ananyev
399e18a033bSKonstantin Ananyev        ngx_encode_base64(&dst, &src);
400e18a033bSKonstantin Ananyev
401e18a033bSKonstantin Ananyev        p += dst.len;
402e18a033bSKonstantin Ananyev
403e18a033bSKonstantin Ananyev        if (conf->mark) {
404e18a033bSKonstantin Ananyev            *(p - 2) = conf->mark;
405e18a033bSKonstantin Ananyev        }
406e18a033bSKonstantin Ananyev
407e18a033bSKonstantin Ananyev    } else {
408e18a033bSKonstantin Ananyev        p = ngx_cpymem(p, ctx->cookie.data, 22);
409e18a033bSKonstantin Ananyev        *p++ = conf->mark;
410e18a033bSKonstantin Ananyev        *p++ = '=';
411e18a033bSKonstantin Ananyev    }
412e18a033bSKonstantin Ananyev
413e18a033bSKonstantin Ananyev    if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) {
414e18a033bSKonstantin Ananyev        p = ngx_cpymem(p, expires, sizeof(expires) - 1);
415