Mercurial > hg > nginx
diff src/http/modules/ngx_http_userid_handler.c @ 408:d6e2b445c1b8
nginx-0.0.10-2004-08-27-19:40:59 import
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Fri, 27 Aug 2004 15:40:59 +0000 |
parents | |
children |
line wrap: on
line diff
new file mode 100644 --- /dev/null +++ b/src/http/modules/ngx_http_userid_handler.c @@ -0,0 +1,421 @@ + +#include <ngx_config.h> +#include <ngx_core.h> +#include <ngx_http.h> + + +#define NGX_HTTP_USERID_OFF 0x0002 +#define NGX_HTTP_USERID_ON 0x0004 +#define NGX_HTTP_USERID_LOGONLY 0x0008 +#define NGX_HTTP_USERID_TIME 0x0010 + + +typedef struct { + ngx_flag_t enable; + + ngx_int_t version; + ngx_int_t service; + + ngx_str_t name; + ngx_str_t domain; + ngx_str_t path; + time_t expires; + + ngx_int_t p3p; + ngx_str_t p3p_string; +} ngx_http_userid_conf_t; + + +typedef struct { + uint32_t uid_got[4]; + uint32_t uid_set[4]; + struct timeval tv; +} ngx_http_userid_ctx_t; + + +static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, + ngx_http_userid_ctx_t *ctx, + ngx_http_userid_conf_t *conf); + +static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, + uintptr_t data); +static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, + uintptr_t data); +static u_char *ngx_http_userid_log_uid_time(ngx_http_request_t *r, u_char *buf, + uintptr_t data); + +static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf); +static void *ngx_http_userid_create_conf(ngx_conf_t *cf); +static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, + void *child); +static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle); + + +static ngx_conf_enum_t ngx_http_userid_mask[] = { + { ngx_string("off"), NGX_HTTP_USERID_OFF }, + { ngx_string("on"), NGX_HTTP_USERID_ON }, + { ngx_string("logonly"), NGX_HTTP_USERID_LOGONLY }, + { ngx_string("time"), NGX_HTTP_USERID_TIME }, + { ngx_null_string, 0 } +}; + + +static ngx_command_t ngx_http_userid_commands[] = { + + { ngx_string("userid"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_ANY, + ngx_conf_set_bitmask_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, enable), + ngx_http_userid_mask}, + + { ngx_string("userid_service"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_num_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, service), + NULL}, + + { ngx_string("userid_name"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, name), + NULL}, + + { ngx_string("userid_domain"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, domain), + NULL}, + + { ngx_string("userid_path"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_str_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, path), + NULL}, + + { ngx_string("userid_expires"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_FLAG, + ngx_conf_set_sec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_userid_conf_t, expires), + NULL}, + + ngx_null_command +}; + + +ngx_http_module_t ngx_http_userid_module_ctx = { + ngx_http_userid_pre_conf, /* pre conf */ + + NULL, /* create main configuration */ + NULL, /* init main configuration */ + + NULL, /* create server configuration */ + NULL, /* merge server configuration */ + + ngx_http_userid_create_conf, /* create location configration */ + ngx_http_userid_merge_conf /* merge location configration */ +}; + + +ngx_module_t ngx_http_userid_module = { + NGX_MODULE, + &ngx_http_userid_module_ctx, /* module context */ + ngx_http_userid_commands, /* module directives */ + NGX_HTTP_MODULE, /* module type */ + ngx_http_userid_init, /* init module */ + NULL /* init process */ +}; + + +static ngx_http_log_op_name_t ngx_http_userid_log_fmt_ops[] = { + { ngx_string("uid_got"), 0, ngx_http_userid_log_uid_got }, + { ngx_string("uid_set"), 0, ngx_http_userid_log_uid_set }, + { ngx_string("uid_time"), TIME_T_LEN + 4, ngx_http_userid_log_uid_time }, + { ngx_null_string, 0, NULL } +}; + + +static ngx_int_t ngx_http_userid_handler(ngx_http_request_t *r) +{ + ngx_int_t rc; + struct timeval tv; + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_module); + + if (conf->enable & NGX_HTTP_USERID_OFF) { + return NGX_OK; + } + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_module); + + if (ctx) { + return NGX_OK; + } + + ngx_http_create_ctx(r, ctx, ngx_http_userid_module, + sizeof(ngx_http_userid_ctx_t), + NGX_HTTP_INTERNAL_SERVER_ERROR); + + if (conf->enable & (NGX_HTTP_USERID_ON|NGX_HTTP_USERID_LOGONLY)) { + rc = ngx_http_userid_get_uid(r, ctx, conf); + + if (rc != NGX_OK) { + return rc; + } + } + + if (conf->enable & NGX_HTTP_USERID_TIME) { + ngx_gettimeofday(&ctx->tv); + } + + return NGX_OK; +} + + +static ngx_int_t ngx_http_userid_get_uid(ngx_http_request_t *r, + ngx_http_userid_ctx_t *ctx, + ngx_http_userid_conf_t *conf) +{ + u_char *start, *last, *end; + uint32_t *uid; + ngx_int_t rc; + ngx_uint_t *cookies, i; + ngx_str_t src, dst; + ngx_table_elt_t *headers; + + headers = r->headers_in.headers.elts; + cookies = r->headers_in.cookies.elts; + + for (i = 0; i < r->headers_in.cookies.nelts; i++) { + ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "cookie: %d:\"%s\"", + cookies[i], + headers[cookies[i]].value.data); + + end = headers[cookies[i]].value.data + headers[cookies[i]].value.len; + + for (start = headers[cookies[i]].value.data; start < end; /* void */) { + + if (conf->name.len >= headers[cookies[i]].value.len + || ngx_strncmp(start, conf->name.data, conf->name.len) != 0) + { + start += conf->name.len; + while (start < end && *start++ != ';') { /* void */ } + + for (/* void */; start < end && *start == ' '; start++) { /**/ } + + continue; + } + + for (start += conf->name.len; start < end && *start == ' '; start++) + { + /* void */ + } + + if (*start != '=') { + break; + } + + for (start++; start < end && *start == ' '; start++) { /* void */ } + + for (last = start; last < end && *last != ';'; last++) { /**/ } + + if (last - start < 22) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent too short userid cookie \"%s\"", + headers[cookies[i]].value.data); + break; + } + + /* + * we have to limit encoded string to 22 characters + * because there are already the millions cookies with a garbage + * instead of the correct base64 trail "==" + */ + + src.len = 22; + src.data = start; + + rc = ngx_decode_base64(r->pool, &src, &dst); + + if (rc == NGX_ABORT) { + return NGX_HTTP_INTERNAL_SERVER_ERROR; + } + + if (rc == NGX_ERROR) { + ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, + "client sent invalid userid cookie \"%s\"", + headers[cookies[i]].value.data); + break; + } + + uid = (uint32_t *) dst.data; + ctx->uid_got[0] = uid[0]; + ctx->uid_got[1] = uid[1]; + ctx->uid_got[2] = uid[2]; + ctx->uid_got[3] = uid[3]; + + ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "uid: %08X%08X%08X%08X", + uid[0], uid[1], uid[2], uid[3]); + + return NGX_OK; + } + } + + return NGX_OK; +} + + +static u_char *ngx_http_userid_log_uid_got(ngx_http_request_t *r, u_char *buf, + uintptr_t data) +{ + ngx_http_userid_ctx_t *ctx; + ngx_http_userid_conf_t *conf; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_module); + + if (ctx == NULL || ctx->uid_got[3] == 0) { + if (buf == NULL) { + return (u_char *) 1; + } + + *buf = '-'; + return buf + 1; + } + + conf = ngx_http_get_module_loc_conf(r, ngx_http_userid_module); + + if (buf == NULL) { + return (u_char *) (conf->name.len + 1 + 32); + } + + buf = ngx_cpymem(buf, conf->name.data, conf->name.len); + + *buf++ = '='; + + return buf + ngx_snprintf((char *) buf, 33, "%08X%08X%08X%08X", + ctx->uid_got[0], ctx->uid_got[1], + ctx->uid_got[2], ctx->uid_got[3]); +} + + +static u_char *ngx_http_userid_log_uid_set(ngx_http_request_t *r, u_char *buf, + uintptr_t data) +{ + if (buf == NULL) { + return (u_char *) 1; + } + + *buf = '-'; + + return buf + 1; +} + + +static u_char *ngx_http_userid_log_uid_time(ngx_http_request_t *r, u_char *buf, + uintptr_t data) +{ + ngx_http_userid_ctx_t *ctx; + + ctx = ngx_http_get_module_ctx(r, ngx_http_userid_module); + + if (ctx == NULL || ctx->tv.tv_sec == 0) { + *buf = '-'; + return buf + 1; + } + + return buf + ngx_snprintf((char *) buf, TIME_T_LEN + 5, + "%ld.%03ld", + ctx->tv.tv_sec, ctx->tv.tv_usec / 1000); +} + + +static ngx_int_t ngx_http_userid_pre_conf(ngx_conf_t *cf) +{ + ngx_http_log_op_name_t *op; + + for (op = ngx_http_userid_log_fmt_ops; op->name.len; op++) { /* void */ } + op->op = NULL; + + op = ngx_http_log_fmt_ops; + + for (op = ngx_http_log_fmt_ops; op->op; op++) { + if (op->name.len == 0) { + op = (ngx_http_log_op_name_t *) op->op; + } + } + + op->op = (ngx_http_log_op_pt) ngx_http_userid_log_fmt_ops; + + return NGX_OK; +} + + +static void *ngx_http_userid_create_conf(ngx_conf_t *cf) +{ + ngx_http_userid_conf_t *conf; + + if (!(conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_userid_conf_t)))) { + return NGX_CONF_ERROR; + } + + /* set by ngx_pcalloc(): + + conf->enable = 0; + + conf->name.len = 0; + conf->name.date = NULL; + conf->domain.len = 0; + conf->domain.date = NULL; + conf->path.len = 0; + conf->path.date = NULL; + + */ + + + return conf; +} + + +static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, + void *child) +{ + ngx_http_userid_conf_t *prev = parent; + ngx_http_userid_conf_t *conf = child; + + ngx_conf_merge_bitmask_value(conf->enable, prev->enable, + (NGX_CONF_BITMASK_SET + |NGX_HTTP_USERID_OFF)); + + ngx_conf_merge_str_value(conf->name, prev->name, "uid"); + ngx_conf_merge_str_value(conf->domain, prev->domain, "."); + ngx_conf_merge_str_value(conf->path, prev->path, "/"); + + return NGX_CONF_OK; +} + + +static ngx_int_t ngx_http_userid_init(ngx_cycle_t *cycle) +{ + ngx_http_handler_pt *h; + ngx_http_core_main_conf_t *cmcf; + + cmcf = ngx_http_cycle_get_module_main_conf(cycle, ngx_http_core_module); + + h = ngx_push_array(&cmcf->phases[NGX_HTTP_MISC_PHASE].handlers); + if (h == NULL) { + return NGX_ERROR; + } + + *h = ngx_http_userid_handler; + + return NGX_OK; +}