本文使用nginx-stable-1.12代码。 路径:
src/http/modules/ngxhttpuseridfiltermodule.c
流程图
头文件
-
// nginx配置类 -
#include <ngx_config.h> -
// nginx核心类 -
#include <ngx_core.h> -
// nginx http模块类 -
#include <ngx_http.h>
define常量
-
// off关闭功能 -
#define NGX_HTTP_USERID_OFF 0 -
// 开启log -
#define NGX_HTTP_USERID_LOG 1 -
// v1版本cookie -
#define NGX_HTTP_USERID_V1 2 -
// 开启功能 -
#define NGX_HTTP_USERID_ON 3 -
/* 31 Dec 2037 23:55:55 GMT */ // unix最大时间戳 -
#define NGX_HTTP_USERID_MAX_EXPIRES 2145916555
结构
指令
-
typedef struct { -
ngx_uint_t enable; -
ngx_int_t service; -
ngx_str_t name; -
ngx_str_t domain; -
ngx_str_t path; -
ngx_str_t p3p; -
time_t expires; -
u_char mark; -
} ngx_http_userid_conf_t;
变量
-
typedef struct { -
uint32_t uid_got[4]; -
uint32_t uid_set[4]; -
ngx_str_t cookie; -
ngx_uint_t reset; -
} ngx_http_userid_ctx_t;
函数
-
// 获取uid -
static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r, -
ngx_http_userid_conf_t *conf); -
-
// 变量 -
static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, -
ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid); -
-
// 设置uid -
static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, -
ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); -
-
// 创建uid -
static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r, -
ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf); -
-
// 增加变量 -
static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf); -
-
// init初始化 -
static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf); -
-
// 创建conf -
static void *ngx_http_userid_create_conf(ngx_conf_t *cf); -
-
// 合并conf -
static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, -
void *child); -
-
// domain域 -
static char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data); -
-
// path路径 -
static char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data); -
-
// expires过期时间 -
static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, -
void *conf); -
-
// p3p协议 -
static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data); -
-
// mark -
static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, -
void *conf); -
-
// 初始化worker -
static ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle);
定义命令
-
static ngx_command_t ngx_http_userid_commands[] = {...} -
配置指令 -
-
主要函数和全局常量 -
ngx_string -
ngx_str_t ngx_string(const unsigned char str[]) -
返回ngx_str_t从NULL的终端字符数组。 -
-
offsetof -
宏,该宏用于求结构体中一个成员在该结构体中的偏移量。 -
-
配置指令的作用域: -
NGX_HTTP_MAIN_CONF : http -
NGX_HTTP_SRV_CONF : server -
NGX_HTTP_LOC_CONF : location -
NGX_CONF_TAKE1 -
-
ngx_conf_set_enum_slot 枚举类型
上下文和作用域
-
static ngx_http_module_t ngx_http_userid_filter_module_ctx = {} -
ngx_module_t ngx_http_userid_filter_module = {}
函数
static ngx_int_t ngx_http_userid_filter(ngx_http_request_t *r)
功能:根据请求设置uid。 依赖函数ngx_http_userid_get_uid,ngx_http_userid_set_uid,ngx_http_next_header_filter,ngx_http_get_module_loc_conf。 ngx_http_next_header_filter定义如下:
-
static ngx_http_output_header_filter_pt ngx_http_next_header_filter; -
typedef ngx_int_t (ngx_http_output_header_filter_pt)(ngx_http_request_t *r);
ngx_http_output_header_filter_pt
ngx_http_output_header_filter_pt是指向处理头部的函数指针,每一个过滤模块如果要处理头部,就必须定义一个局部的这种类型的指针和函数。并且这个函数只接受请求对象作为参数。nginx Api, 官方解释如下:这个是一个指向头部过滤模块的回调函数。
ngx_http_get_module_loc_conf
ngx_http_get_module_loc_conf是根据request请求和模块得到location配置。 定义如下:
-
#define ngx_http_get_module_loc_conf(r, module) (r)->loc_conf[module.ctx_index]
nginx Api, 官方解释如下:从请求头对象中获取http location 块配置的宏。
ngx_http_userid_get_uid
static ngx_http_userid_ctxt * ngx_http_userid_get_uid(ngx_http_request_t *r, ngx_http_userid_conf_t *conf) 主要结构体:
-
ngx_http_userid_ctx_t userid指令的变量 -
ngx_http_userid_filter_module userid过滤模块各阶段 -
ngx_pcalloc nginx内存管理函数,从nginx内存池中分配一块对齐的内存。
常量:定义在core/ngx_core.h
-
#define NGX_OK 0 success -
#define NGX_ERROR -1 错误 -
#define NGX_AGAIN -2 重复请求 -
#define NGX_BUSY -3 繁忙 -
#define NGX_DONE -4 完成 -
#define NGX_DECLINED -5 下降 -
#define NGX_ABORT -6 终止
ngx_table_elt_t:为了存储http头部定制的,存储key,value值;定义如下:
-
typedef struct { -
ngx_uint_t hash; -
ngx_str_t key; -
ngx_str_t value; -
u_char *lowcase_key; -
} ngx_table_elt_t;
ngx_http_get_module_ctx ngx_http_set_ctx 定义在http/ngxhttp.h
-
#define ngx_http_get_module_ctx(r, module) (r)->ctx[module.ctx_index] -
#define ngx_http_set_ctx(r, c, module) r->ctx[module.ctx_index] = c;
ngx_http_parse_multi_header_lines
-
按行解析http header头部信息。
ngx_http_userid_set_uid
static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf) ngx_http_userid_create_uid 长度len = conf->name.len + 1 + ngx_base64_encoded_length(16) + conf->path.len + sizeof(expires) + conf->domain.len。 conf->name.data
设置uid等变量,包括cookie的各个字段。
-
ngx_encode_base64 base64编码encode,cookie值会编码。 -
ngx_list_push:链表
ngx_http_userid_got_variable
static ngx_int_t ngx_http_userid_got_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uint_ptr_t data)
获取cookie中的对应变量。
-
ngx_http_userid_variable
ngx_http_userid_variable
static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, ngx_str_t *name, uint_32t *uid)
变量设置,request,name, v, uid_got
ngx_http_userid_set_variable
static ngx_int_t ngx_http_userid_set_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uint_ptr_t data)
变量设置
ngx_http_userid_create_uid
static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r, ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf)
创建uid。
-
sockaddr_in6:ipv6基础库。
ngx_http_userid_reset_variable
static ngx_int_t ngx_http_userid_reset_variable(ngx_http_request_t *r, ngx_http_variable_value_t *v, uint_ptr_t data)
reset变量,重置到初始值或空值。
ngx_http_userid_add_variables
static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf)
新增变量。
-
ngx_http_add_variable -
ngx_http_get_variable_index
ngx_http_userid_create_conf
static void * ngx_http_userid_create_conf(ngx_conf_t *cf)
创建conf。
ngx_http_userid_merge_conf
static char * ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent, void *child)
合并conf。
ngx_http_userid_init
static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf)
初始化ngx_http_next_header_filter和ngx_http_top_header_filter两个指针。
ngx_http_userid_domain
static char * ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data)
设置domain。
ngx_http_userid_path
static char * ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data)
设置path。
ngx_http_userid_expires
static char * ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
设置过期时间。
ngx_http_userid_p3p
static char * ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data)
设置p3p协议相关。
ngx_http_userid_mark
static char * ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
设置mark,在22位cookie的后面有两个==,如果设置了mark,则替换第一个=,如L=。
ngx_http_userid_init_worker
static ngx_int_t ngx_http_userid_init_worker(ngx_cyclet *cycle)
初始化worker。
坑
由于网站有多个域名,且属于不同的主域,servername dongqiudi.com dongqiudi.net dongqiudi.cc。 默认情况我以为设置useriddomain dongqiudi.com, 但是请求dongqiudi.net dongqiudi.cc则无法成功设置cookie。 查阅了很多资料都没有找到解决办法,只能阅读源码。 useriddomain指令不支持多个domain,也不支持正则,也不支持变量。几乎到了崩溃边缘,然后转变思路,尝试用location解决,虽然可以接受,但是确实不够优雅。 上线是可以了,不过还是要寻找更好的解决办法。尝试中发现,可以把useriddomain指令注释掉,浏览器查看cookie中包含了uid,只不过domain不是最短的,而是请求的url中的host,由于我们对domain没有要求,所以终于解决了。
反解
cookie uid反解php程序:
-
<?php -
$str = $_COOKIE['dqduid']; -
$hash = unpack('N*', base64_decode(str_replace(' ', '+', $str))); -
$server_ip = long2ip($hash[1]); -
$time = date("Y-m-d H:i:s", $hash[2]);
总结
userid模块简单来说就是实现了setcookie功能。能够为一些网站pc站或者h5提供userid设置和分析功能,方便数据团队统计uv。使用过程中发现很多不理解,所以去读了源码,由于才疏学浅,理解的不是很明白,所以有不足之处还请朋友们能够指点。