view 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 source


#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;
}