本文使用nginx-stable-1.12代码。 路径:

src/http/modules/ngxhttpuseridfiltermodule.c

流程图

[源码阅读]ngx_http_userid_module模块源码分析

头文件

 
  1. // nginx配置类

  2. #include <ngx_config.h>

  3. // nginx核心类

  4. #include <ngx_core.h>

  5. // nginx http模块类

  6. #include <ngx_http.h>


define常量

 
  1. // off关闭功能

  2. #define NGX_HTTP_USERID_OFF   0

  3. // 开启log

  4. #define NGX_HTTP_USERID_LOG   1

  5. // v1版本cookie

  6. #define NGX_HTTP_USERID_V1    2

  7. // 开启功能

  8. #define NGX_HTTP_USERID_ON    3

  9. /* 31 Dec 2037 23:55:55 GMT */ // unix最大时间戳

  10. #define NGX_HTTP_USERID_MAX_EXPIRES  2145916555


结构

指令

 
  1. typedef struct {

  2.    ngx_uint_t  enable;

  3.    ngx_int_t   service;

  4.    ngx_str_t   name;

  5.    ngx_str_t   domain;

  6.    ngx_str_t   path;

  7.    ngx_str_t   p3p;

  8.    time_t      expires;

  9.    u_char      mark;

  10. } ngx_http_userid_conf_t;


变量

 
  1. typedef struct {

  2.    uint32_t    uid_got[4];

  3.    uint32_t    uid_set[4];

  4.    ngx_str_t   cookie;

  5.    ngx_uint_t  reset;

  6. } ngx_http_userid_ctx_t;


函数

 
  1. // 获取uid

  2. static ngx_http_userid_ctx_t *ngx_http_userid_get_uid(ngx_http_request_t *r,

  3.    ngx_http_userid_conf_t *conf);

  4.  

  5. // 变量

  6. static ngx_int_t ngx_http_userid_variable(ngx_http_request_t *r,

  7.    ngx_http_variable_value_t *v, ngx_str_t *name, uint32_t *uid);

  8.  

  9. // 设置uid

  10. static ngx_int_t ngx_http_userid_set_uid(ngx_http_request_t *r,

  11.    ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);

  12.  

  13. // 创建uid

  14. static ngx_int_t ngx_http_userid_create_uid(ngx_http_request_t *r,

  15.    ngx_http_userid_ctx_t *ctx, ngx_http_userid_conf_t *conf);

  16.  

  17. // 增加变量

  18. static ngx_int_t ngx_http_userid_add_variables(ngx_conf_t *cf);

  19.  

  20. // init初始化

  21. static ngx_int_t ngx_http_userid_init(ngx_conf_t *cf);

  22.  

  23. // 创建conf

  24. static void *ngx_http_userid_create_conf(ngx_conf_t *cf);

  25.  

  26. // 合并conf

  27. static char *ngx_http_userid_merge_conf(ngx_conf_t *cf, void *parent,

  28.    void *child);

  29.  

  30. // domain域

  31. static char *ngx_http_userid_domain(ngx_conf_t *cf, void *post, void *data);

  32.  

  33. // path路径

  34. static char *ngx_http_userid_path(ngx_conf_t *cf, void *post, void *data);

  35.  

  36. // expires过期时间

  37. static char *ngx_http_userid_expires(ngx_conf_t *cf, ngx_command_t *cmd,

  38.    void *conf);

  39.  

  40. // p3p协议

  41. static char *ngx_http_userid_p3p(ngx_conf_t *cf, void *post, void *data);

  42.  

  43. // mark

  44. static char *ngx_http_userid_mark(ngx_conf_t *cf, ngx_command_t *cmd,

  45.    void *conf);

  46.  

  47. // 初始化worker

  48. static ngx_int_t ngx_http_userid_init_worker(ngx_cycle_t *cycle);


定义命令

 
  1. static ngx_command_t  ngx_http_userid_commands[] = {...}

  2. 配置指令

  3.  

  4. 主要函数和全局常量

  5. ngx_string

  6. ngx_str_t ngx_string(const unsigned char str[])

  7. 返回ngx_str_t从NULL的终端字符数组。

  8.  

  9. offsetof

  10. 宏,该宏用于求结构体中一个成员在该结构体中的偏移量。

  11.  

  12. 配置指令的作用域:

  13. NGX_HTTP_MAIN_CONF : http

  14. NGX_HTTP_SRV_CONF : server

  15. NGX_HTTP_LOC_CONF : location

  16. NGX_CONF_TAKE1

  17.  

  18. ngx_conf_set_enum_slot 枚举类型


上下文和作用域

 
  1. static ngx_http_module_t  ngx_http_userid_filter_module_ctx = {}

  2. 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定义如下:

 
  1. static ngx_http_output_header_filter_pt ngx_http_next_header_filter;

  2. 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配置。 定义如下:

 
  1. #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) 主要结构体:

 
  1. ngx_http_userid_ctx_t  userid指令的变量

  2. ngx_http_userid_filter_module   userid过滤模块各阶段

  3. ngx_pcalloc   nginx内存管理函数,从nginx内存池中分配一块对齐的内存。

常量:定义在core/ngx_core.h

 
  1. #define  NGX_OK          0      success

  2. #define  NGX_ERROR      -1      错误

  3. #define  NGX_AGAIN      -2      重复请求

  4. #define  NGX_BUSY       -3      繁忙

  5. #define  NGX_DONE       -4      完成

  6. #define  NGX_DECLINED   -5      下降

  7. #define  NGX_ABORT      -6      终止

ngx_table_elt_t:为了存储http头部定制的,存储key,value值;定义如下:

 
  1. typedef struct {

  2.    ngx_uint_t        hash;

  3.    ngx_str_t         key;

  4.    ngx_str_t         value;

  5.    u_char           *lowcase_key;

  6. } ngx_table_elt_t;

ngx_http_get_module_ctx ngx_http_set_ctx 定义在http/ngxhttp.h

 
  1. #define ngx_http_get_module_ctx(r, module)  (r)->ctx[module.ctx_index]

  2. #define ngx_http_set_ctx(r, c, module)      r->ctx[module.ctx_index] = c;


ngx_http_parse_multi_header_lines

 
  1. 按行解析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的各个字段。

 
  1. ngx_encode_base64 base64编码encode,cookie值会编码。

  2. 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中的对应变量。

 
  1. 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。

 
  1. 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)

新增变量。

 
  1. ngx_http_add_variable

  2. 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程序:

 
  1. <?php

  2.    $str = $_COOKIE['dqduid'];

  3.    $hash = unpack('N*', base64_decode(str_replace(' ',  '+', $str)));

  4.    $server_ip = long2ip($hash[1]);

  5.    $time = date("Y-m-d H:i:s", $hash[2]);


总结

userid模块简单来说就是实现了setcookie功能。能够为一些网站pc站或者h5提供userid设置和分析功能,方便数据团队统计uv。使用过程中发现很多不理解,所以去读了源码,由于才疏学浅,理解的不是很明白,所以有不足之处还请朋友们能够指点。

相关文章: