Mercurial > hg > nginx-quic
comparison src/http/modules/ngx_http_userid_filter.c @ 409:8ac40cae79f0
nginx-0.0.10-2004-08-29-07:55:41 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Sun, 29 Aug 2004 03:55:41 +0000 |
parents | src/http/modules/ngx_http_userid_handler.c@d6e2b445c1b8 |
children | 48b9ad5ca1fc |
comparison
equal
deleted
inserted
replaced
408:d6e2b445c1b8 | 409:8ac40cae79f0 |
---|---|
1 | |
2 #include <ngx_config.h> | |
3 #include <ngx_core.h> | |
4 #include <ngx_http.h> | |
5 | |
6 | |
7 #define NGX_HTTP_USERID_OFF 0 | |
8 #define NGX_HTTP_USERID_LOG 1 | |
9 #define NGX_HTTP_USERID_V1 2 | |
10 #define NGX_HTTP_USERID_ON 3 | |
11 | |
12 /* 31 Dec 2037 23:55:55 GMT */ | |
13 #define NGX_HTTP_USERID_MAX_EXPIRES 2145916555 | |
14 | |
15 | |
16 typedef struct { | |
17 ngx_flag_t enable; | |
18 | |
19 ngx_int_t service; | |
20 | |
21 ngx_str_t name; | |
22 ngx_str_t domain; | |
23 ngx_str_t path; | |
24 time_t expires; | |
25 | |
26 ngx_int_t p3p; | |
27 ngx_str_t p3p_string; | |
28 } ngx_http_userid_conf_t; | |
29 | |
30 | |
31 typedef struct { | |
32 uint32_t uid_got[4]; | |
33 uint32_t uid_set[4]; | |
34 } ngx_http_userid_ctx_t; | |
35 | |
36 | |
37 static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, | |
38 ngx_http_userid_ctx_t *ctx, | |
39 ngx_http_userid_conf_t *conf); | |
40 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, | |
41 ngx_http_userid_ctx_t *ctx, | |
42 ngx_http_userid_conf_t *conf); | |
43 | |
44 static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, | |
45 uintptr_t data); | |
46 static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, | |
47 uintptr_t data); | |
48 | |
49 static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf); | |
50 static void *ngx_http_userid_create_conf(ngx_conf_t *cf); | |
51 static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, | |
52 void *child); | |
53 static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle); | |
54 | |
55 | |
56 static uint32_t sequencer_v1 = 1; | |
57 static uint32_t sequencer_v2 = 0x03030302; | |
58 | |
59 | |
60 static u_char expires[] = "; expires=Thu, 31-Dec-37 23:55:55 GMT"; | |
61 | |
62 | |
63 static ngx_http_output_header_filter_pt ngx_http_next_header_filter; | |
64 | |
65 | |
66 static ngx_conf_enum_t ngx_http_userid_state[] = { | |
67 { ngx_string("off"), NGX_HTTP_USERID_OFF }, | |
68 { ngx_string("log"), NGX_HTTP_USERID_LOG }, | |
69 { ngx_string("v1"), NGX_HTTP_USERID_V1 }, | |
70 { ngx_string("on"), NGX_HTTP_USERID_ON }, | |
71 { ngx_null_string, 0 } | |
72 }; | |
73 | |
74 | |
75 static ngx_command_t ngx_http_userid_commands[] = { | |
76 | |
77 { ngx_string("userid"), | |
78 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
79 ngx_conf_set_enum_slot, | |
80 NGX_HTTP_LOC_CONF_OFFSET, | |
81 offsetof(ngx_http_userid_conf_t, enable), | |
82 ngx_http_userid_state}, | |
83 | |
84 { ngx_string("userid_service"), | |
85 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
86 ngx_conf_set_num_slot, | |
87 NGX_HTTP_LOC_CONF_OFFSET, | |
88 offsetof(ngx_http_userid_conf_t, service), | |
89 NULL}, | |
90 | |
91 { ngx_string("userid_name"), | |
92 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
93 ngx_conf_set_str_slot, | |
94 NGX_HTTP_LOC_CONF_OFFSET, | |
95 offsetof(ngx_http_userid_conf_t, name), | |
96 NULL}, | |
97 | |
98 { ngx_string("userid_domain"), | |
99 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
100 ngx_conf_set_str_slot, | |
101 NGX_HTTP_LOC_CONF_OFFSET, | |
102 offsetof(ngx_http_userid_conf_t, domain), | |
103 NULL}, | |
104 | |
105 { ngx_string("userid_path"), | |
106 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, | |
107 ngx_conf_set_str_slot, | |
108 NGX_HTTP_LOC_CONF_OFFSET, | |
109 offsetof(ngx_http_userid_conf_t, path), | |
110 NULL}, | |
111 | |
112 { ngx_string("userid_expires"), | |
113 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
114 ngx_conf_set_sec_slot, | |
115 NGX_HTTP_LOC_CONF_OFFSET, | |
116 offsetof(ngx_http_userid_conf_t, expires), | |
117 NULL}, | |
118 | |
119 ngx_null_command | |
120 }; | |
121 | |
122 | |
123 ngx_http_module_t ngx_http_userid_filter_module_ctx = { | |
124 ngx_http_userid_pre_conf, /* pre conf */ | |
125 | |
126 NULL, /* create main configuration */ | |
127 NULL, /* init main configuration */ | |
128 | |
129 NULL, /* create server configuration */ | |
130 NULL, /* merge server configuration */ | |
131 | |
132 ngx_http_userid_create_conf, /* create location configration */ | |
133 ngx_http_userid_merge_conf /* merge location configration */ | |
134 }; | |
135 | |
136 | |
137 ngx_module_t ngx_http_userid_filter_module = { | |
138 NGX_MODULE, | |
139 &ngx_http_userid_filter_module_ctx, /* module context */ | |
140 ngx_http_userid_commands, /* module directives */ | |
141 NGX_HTTP_MODULE, /* module type */ | |
142 ngx_http_userid_init, /* init module */ | |
143 NULL /* init process */ | |
144 }; | |
145 | |
146 | |
147 static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = { | |
148 { ngx_string("uid_got"), 0, ngx_http_userid_log_uid_got }, | |
149 { ngx_string("uid_set"), 0, ngx_http_userid_log_uid_set }, | |
150 { ngx_null_string, 0, NULL } | |
151 }; | |
152 | |
153 | |
154 static ngx_int_t ngx_http_userid_filter(ngx_http_request_t *r) | |
155 { | |
156 ngx_int_t rc; | |
157 ngx_http_userid_ctx_t *ctx; | |
158 ngx_http_userid_conf_t *conf; | |
159 | |
160 conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); | |
161 | |
162 if (conf->enable == NGX_HTTP_USERID_OFF) { | |
163 return ngx_http_next_header_filter(r); | |
164 } | |
165 | |
166 ngx_http_create_ctx(r, ctx, ngx_http_userid_filter_module, | |
167 sizeof(ngx_http_userid_ctx_t), | |
168 NGX_HTTP_INTERNAL_SERVER_ERROR); | |
169 | |
170 rc = ngx_http_userid_get_uid(r, ctx, conf); | |
171 | |
172 if (rc != NGX_OK) { | |
173 return rc; | |
174 } | |
175 | |
176 if (conf->enable == NGX_HTTP_USERID_LOG /* || ctx->uid_got[3] != 0 */) { | |
177 return NGX_OK; | |
178 } | |
179 | |
180 rc = ngx_http_userid_set_uid(r, ctx, conf); | |
181 | |
182 if (rc != NGX_OK) { | |
183 return rc; | |
184 } | |
185 | |
186 return ngx_http_next_header_filter(r); | |
187 } | |
188 | |
189 | |
190 static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, | |
191 ngx_http_userid_ctx_t *ctx, | |
192 ngx_http_userid_conf_t *conf) | |
193 { | |
194 u_char *start, *last, *end; | |
195 ngx_uint_t *cookies, i; | |
196 ngx_str_t src, dst; | |
197 ngx_table_elt_t *headers; | |
198 | |
199 headers = r->headers_in.headers.elts; | |
200 cookies = r->headers_in.cookies.elts; | |
201 | |
202 for (i = 0; i < r->headers_in.cookies.nelts; i++) { | |
203 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
204 "cookie: %d:\"%s\"", | |
205 cookies[i], | |
206 headers[cookies[i]].value.data); | |
207 | |
208 end = headers[cookies[i]].value.data + headers[cookies[i]].value.len; | |
209 | |
210 for (start = headers[cookies[i]].value.data; start < end; /* void */) { | |
211 | |
212 if (conf->name.len >= headers[cookies[i]].value.len | |
213 || ngx_strncmp(start, conf->name.data, conf->name.len) != 0) | |
214 { | |
215 start += conf->name.len; | |
216 while (start < end && *start++ != ';') { /* void */ } | |
217 | |
218 for (/* void */; start < end && *start == ' '; start++) { /**/ } | |
219 | |
220 continue; | |
221 } | |
222 | |
223 for (start += conf->name.len; start < end && *start == ' '; start++) | |
224 { | |
225 /* void */ | |
226 } | |
227 | |
228 if (*start != '=') { | |
229 break; | |
230 } | |
231 | |
232 for (start++; start < end && *start == ' '; start++) { /* void */ } | |
233 | |
234 for (last = start; last < end && *last != ';'; last++) { /**/ } | |
235 | |
236 if (last - start < 22) { | |
237 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
238 "client sent too short userid cookie \"%s\"", | |
239 headers[cookies[i]].value.data); | |
240 break; | |
241 } | |
242 | |
243 /* | |
244 * we have to limit encoded string to 22 characters | |
245 * because there are already the millions cookies with a garbage | |
246 * instead of the correct base64 trail "==" | |
247 */ | |
248 | |
249 src.len = 22; | |
250 src.data = start; | |
251 dst.data = (u_char *) ctx->uid_got; | |
252 | |
253 if (ngx_decode_base64(&src, &dst) == NGX_ERROR) { | |
254 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | |
255 "client sent invalid userid cookie \"%s\"", | |
256 headers[cookies[i]].value.data); | |
257 break; | |
258 } | |
259 | |
260 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
261 "uid: %08X%08X%08X%08X", | |
262 ctx->uid_got[0], ctx->uid_got[1], | |
263 ctx->uid_got[2], ctx->uid_got[3]); | |
264 | |
265 return NGX_OK; | |
266 } | |
267 } | |
268 | |
269 return NGX_OK; | |
270 } | |
271 | |
272 | |
273 static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, | |
274 ngx_http_userid_ctx_t *ctx, | |
275 ngx_http_userid_conf_t *conf) | |
276 | |
277 { | |
278 u_char *cookie, *p; | |
279 size_t len; | |
280 ngx_str_t src, dst; | |
281 ngx_table_elt_t *set_cookie; | |
282 | |
283 /* TODO: mutex for sequencers */ | |
284 | |
285 if (conf->enable == NGX_HTTP_USERID_V1) { | |
286 ctx->uid_set[0] = conf->service; | |
287 ctx->uid_set[1] = ngx_time(); | |
288 ctx->uid_set[2] = ngx_pid; | |
289 ctx->uid_set[3] = sequencer_v1; | |
290 sequencer_v1 += 0x100; | |
291 | |
292 } else { | |
293 ctx->uid_set[0] = htonl(conf->service); | |
294 ctx->uid_set[1] = htonl(ngx_time()); | |
295 ctx->uid_set[2] = htonl(ngx_pid); | |
296 ctx->uid_set[3] = htonl(sequencer_v2); | |
297 sequencer_v2 += 0x100; | |
298 if (sequencer_v2 < 0x03030302) { | |
299 sequencer_v2 = 0x03030302; | |
300 } | |
301 } | |
302 | |
303 len = conf->name.len + 1 + ngx_base64_encoded_length(16) + 1; | |
304 | |
305 if (conf->expires) { | |
306 len += sizeof(expires) - 1 + 2; | |
307 } | |
308 | |
309 if (conf->domain.len > 1) { | |
310 len += sizeof("; domain=") - 1 + conf->domain.len; | |
311 } | |
312 | |
313 if (conf->path.len) { | |
314 len += sizeof("; path=") - 1 + conf->path.len; | |
315 } | |
316 | |
317 if (!(cookie = ngx_palloc(r->pool, len))) { | |
318 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
319 } | |
320 | |
321 p = ngx_cpymem(cookie, conf->name.data, conf->name.len); | |
322 *p++ = '='; | |
323 | |
324 src.len = 16; | |
325 src.data = (u_char *) ctx->uid_set; | |
326 dst.data = p; | |
327 | |
328 ngx_encode_base64(&src, &dst); | |
329 | |
330 p += dst.len; | |
331 | |
332 if (conf->expires == NGX_HTTP_USERID_MAX_EXPIRES) { | |
333 p = ngx_cpymem(p, expires, sizeof(expires) - 1); | |
334 | |
335 } else if (conf->expires) { | |
336 p = ngx_cpymem(p, expires, sizeof("; expires=") - 1); | |
337 p += ngx_http_cookie_time(p, ngx_time() + conf->expires); | |
338 } | |
339 | |
340 if (conf->domain.len > 1) { | |
341 p = ngx_cpymem(p, "; domain=", sizeof("; domain=") - 1); | |
342 p = ngx_cpymem(p, conf->domain.data, conf->domain.len); | |
343 } | |
344 | |
345 if (conf->path.len) { | |
346 p = ngx_cpymem(p, "; path=", sizeof("; path=") - 1); | |
347 p = ngx_cpymem(p, conf->path.data, conf->path.len); | |
348 } | |
349 | |
350 *p = '\0'; | |
351 | |
352 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
353 "uid cookie: \"%s\"", cookie); | |
354 | |
355 set_cookie = ngx_http_add_header(&r->headers_out, ngx_http_headers_out); | |
356 if (set_cookie == NULL) { | |
357 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
358 } | |
359 | |
360 set_cookie->key.len = sizeof("Set-Cookie") - 1; | |
361 set_cookie->key.data = (u_char *) "Set-Cookie"; | |
362 set_cookie->value.len = p - cookie; | |
363 set_cookie->value.data = cookie; | |
364 | |
365 return NGX_OK; | |
366 } | |
367 | |
368 | |
369 static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, | |
370 uintptr_t data) | |
371 { | |
372 ngx_http_userid_ctx_t *ctx; | |
373 ngx_http_userid_conf_t *conf; | |
374 | |
375 ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); | |
376 | |
377 if (ctx == NULL || ctx->uid_got[3] == 0) { | |
378 if (buf == NULL) { | |
379 return (u_char *) 1; | |
380 } | |
381 | |
382 *buf = '-'; | |
383 return buf + 1; | |
384 } | |
385 | |
386 conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); | |
387 | |
388 if (buf == NULL) { | |
389 return (u_char *) (conf->name.len + 1 + 32); | |
390 } | |
391 | |
392 buf = ngx_cpymem(buf, conf->name.data, conf->name.len); | |
393 | |
394 *buf++ = '='; | |
395 | |
396 return buf + ngx_snprintf((char *) buf, 33, "%08X%08X%08X%08X", | |
397 ctx->uid_got[0], ctx->uid_got[1], | |
398 ctx->uid_got[2], ctx->uid_got[3]); | |
399 } | |
400 | |
401 | |
402 static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, | |
403 uintptr_t data) | |
404 { | |
405 ngx_http_userid_ctx_t *ctx; | |
406 ngx_http_userid_conf_t *conf; | |
407 | |
408 ctx = ngx_http_get_module_ctx(r, ngx_http_userid_filter_module); | |
409 | |
410 if (ctx == NULL || ctx->uid_set[3] == 0) { | |
411 if (buf == NULL) { | |
412 return (u_char *) 1; | |
413 } | |
414 | |
415 *buf = '-'; | |
416 return buf + 1; | |
417 } | |
418 | |
419 conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_filter_module); | |
420 | |
421 if (buf == NULL) { | |
422 return (u_char *) (conf->name.len + 1 + 32); | |
423 } | |
424 | |
425 buf = ngx_cpymem(buf, conf->name.data, conf->name.len); | |
426 | |
427 *buf++ = '='; | |
428 | |
429 return buf + ngx_snprintf((char *) buf, 33, "%08X%08X%08X%08X", | |
430 ctx->uid_set[0], ctx->uid_set[1], | |
431 ctx->uid_set[2], ctx->uid_set[3]); | |
432 } | |
433 | |
434 | |
435 static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf) | |
436 { | |
437 ngx_http_log_op_name_t *op; | |
438 | |
439 for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ } | |
440 op->op = NULL; | |
441 | |
442 op = ngx_http_log_fmt_ops; | |
443 | |
444 for (op = ngx_http_log_fmt_ops; op->op; op++) { | |
445 if (op->name.len == 0) { | |
446 op = (ngx_http_log_op_name_t *) op->op; | |
447 } | |
448 } | |
449 | |
450 op->op = (ngx_http_log_op_pt) ngx_http_userid_log_fmt_ops; | |
451 | |
452 return NGX_OK; | |
453 } | |
454 | |
455 | |
456 static void *ngx_http_userid_create_conf(ngx_conf_t *cf) | |
457 { | |
458 ngx_http_userid_conf_t *conf; | |
459 | |
460 if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t)))) { | |
461 return NGX_CONF_ERROR; | |
462 } | |
463 | |
464 /* set by ngx_pcalloc(): | |
465 | |
466 conf->name.len = 0; | |
467 conf->name.date = NULL; | |
468 conf->domain.len = 0; | |
469 conf->domain.date = NULL; | |
470 conf->path.len = 0; | |
471 conf->path.date = NULL; | |
472 | |
473 */ | |
474 | |
475 conf->enable = NGX_CONF_UNSET; | |
476 conf->expires = NGX_CONF_UNSET; | |
477 | |
478 return conf; | |
479 } | |
480 | |
481 | |
482 static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, | |
483 void *child) | |
484 { | |
485 ngx_http_userid_conf_t *prev = parent; | |
486 ngx_http_userid_conf_t *conf = child; | |
487 | |
488 ngx_conf_merge_value(conf->enable, prev->enable, NGX_HTTP_USERID_OFF); | |
489 | |
490 ngx_conf_merge_str_value(conf->name, prev->name, "uid"); | |
491 ngx_conf_merge_str_value(conf->domain, prev->domain, "."); | |
492 ngx_conf_merge_str_value(conf->path, prev->path, "/"); | |
493 | |
494 ngx_conf_merge_sec_value(conf->expires, prev->expires, 0); | |
495 | |
496 return NGX_CONF_OK; | |
497 } | |
498 | |
499 | |
500 static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) | |
501 { | |
502 ngx_http_next_header_filter = ngx_http_top_header_filter; | |
503 ngx_http_top_header_filter = ngx_http_userid_filter; | |
504 | |
505 return NGX_OK; | |
506 } |