nginx http变量定义
struct ngx_http_variable_s {
ngx_str_t name; //变量名
ngx_http_set_variable_pt set_handler; //设置变量函数
ngx_http_get_variable_pt get_handler; //获取变量函数
uintptr_t data; //变量中的数据
ngx_uint_t flags; //变量标志
ngx_uint_t index; //变量索引值
}
正则变量
typedef struct {
ngx_uint_t capture;
ngx_int_t index;
} ngx_http_regex_variable_t
typedef struct {
ngx_regex_t *regex; //正则表达式
ngx_uint_t ncaptures; //俘获的正则变量数量
ngx_http_regex_variable_t *variables; //正则变量表
ngx_uint_t nvariables; //正则变量数量
ngx_str_t name; //正则变量名
} ngx_http_regex_t
typedef struct {
ngx_http_regex_t *regex; //正则表达式
void *value; //正则值
} ngx_http_map_regex_t
正则字典
typedef struct {
ngx_hash_combined_t hash; //hash表
#if (NGX_PCRE)
ngx_http_map_regex_t *regex; //正则表
ngx_uint_t nregex; //元素数量
#endif
} ngx_http_map_t
变量值定义
typedef struct {
unsigned len:28; //变量的长度
unsigned valid:1; //valid 表示变量是否有效的标记
unsigned no_cacheable:1; //表示变量可否缓存
unsigned not_found:1; //表示没找到变量的值
unsigned escape:1; //变量中是否有空格
u_char *data; //变量数据
} ngx_variable_value_t
nginx变量类型
NGX_HTTP_VAR_CHANGEABLE //可变变量
NGX_HTTP_VAR_NOCACHEABLE //不可变变量
NGX_HTTP_VAR_INDEXED
NGX_HTTP_VAR_NOHASH
NGX_HTTP_VAR_PREFIX
nginx http变量原理及使用
1.添加http变量(普通变量)
ngx_http_variable_t *
ngx_http_add_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
{
...
if (name->len == 0) {
/*变量名为空,认定无效同时返回错误*/
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid variable name \"$\"");
return NULL;
}
if (flags & NGX_HTTP_VAR_PREFIX) {
/*flags为前缀标记 加入到前缀变量中*/
return ngx_http_add_prefix_variable(cf, name, flags);
}
/*获取main作用域的配置*/
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
/*main作用域配置的变量表*/
key = cmcf->variables_keys->keys.elts;
for (i = 0; i < cmcf->variables_keys->keys.nelts; i++) {
if (name->len != key[i].key.len
|| ngx_strncasecmp(name->data, key[i].key.data, name->len) != 0)
{ /*不在main作用域的变量表中*/
continue;
}
/*获取变量的key值*/
v = key[i].value;
if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
/*变量带有changeable标记 判定变量出现了重复 随即返回空值*/
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the duplicate \"%V\" variable", name);
return NULL;
}
/*清除掉flags中的weak标记*/
v->flags &= flags | ~NGX_HTTP_VAR_WEAK;
return v;
}
/*分配变量内存*/
v = ngx_palloc(cf->pool, sizeof(ngx_http_variable_t));
if (v == NULL) {
/*可用内存不足 返回空值*/
return NULL;
}
/*拷贝变量名*/
v->name.len = name->len;
v->name.data = ngx_pnalloc(cf->pool, name->len);
if (v->name.data == NULL) {
return NULL;
}
//变量名小写处理
ngx_strlow(v->name.data, name->data, name->len);
/*变量成员初始化*/
v->set_handler = NULL;
v->get_handler = NULL;
v->data = 0;
v->flags = flags;
v->index = 0;
/*将变量添加到 variable_keys集合中*/
rc = ngx_hash_add_key(cmcf->variables_keys, &v->name, v, 0);
if (rc == NGX_ERROR) {
/*添加失败 返回空值*/
return NULL;
}
if (rc == NGX_BUSY) {
/*变量名与variables_keys集合中的变量出现了重复*/
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"conflicting variable name \"%V\"", name);
return NULL;
}
/*返回新增的变量*/
return v;
}
2.添加prefix[前缀]变量
static ngx_http_variable_t *
ngx_http_add_prefix_variable(ngx_conf_t *cf, ngx_str_t *name, ngx_uint_t flags)
{
...
//得到前缀变量表
v = cmcf->prefix_variables.elts;
for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
if (name->len != v[i].name.len
|| ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
{ /*没找到 跳过*/
continue;
}
v = &v[i];
if (!(v->flags & NGX_HTTP_VAR_CHANGEABLE)) {
/*同普通变量处理*/
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the duplicate \"%V\" variable", name);
return NULL;
}
v->flags &= flags | ~NGX_HTTP_VAR_WEAK;
return v;
}
/*添加到prefix_variables变量表中*/
v = ngx_array_push(&cmcf->prefix_variables);
if (v == NULL) {
return NULL;
}
v->name.len = name->len;
v->name.data = ngx_pnalloc(cf->pool, name->len);
if (v->name.data == NULL) {
return NULL;
}
ngx_strlow(v->name.data, name->data, name->len);
/*变量初始化*/
v->set_handler = NULL;
v->get_handler = NULL;
v->data = 0;
v->flags = flags;
v->index = 0;
return v;
}
3.通过变量名获取变量的index索引值
ngx_int_t
ngx_http_get_variable_index(ngx_conf_t *cf, ngx_str_t *name)
{
if (name->len == 0) {
/*传入的变量名是空的 返回错误*/
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid variable name \"$\"");
return NGX_ERROR;
}
/*得到main作用域的变量表*/
v = cmcf->variables.elts;
if (v == NULL) {
/*发现变量表为空 则创建一个变量表 默认有4个元素*/
if (ngx_array_init(&cmcf->variables, cf->pool, 4,
sizeof(ngx_http_variable_t))
!= NGX_OK)
{
return NGX_ERROR;
}
} else {
/*变量表存在 则在变量表中进行查找*/
for (i = 0; i < cmcf->variables.nelts; i++) {
if (name->len != v[i].name.len
|| ngx_strncasecmp(name->data, v[i].name.data, name->len) != 0)
{ /*变量名不匹配 跳过*/
continue;
}
//找到了变量
return i;
}
}
/*发现变量表中没有这个变量 则将变量加入到变量表中*/
v = ngx_array_push(&cmcf->variables);
if (v == NULL) {
//添加失败 则返回错误
return NGX_ERROR;
}
/*拷贝变量名称到变量表中*/
v->name.len = name->len;
v->name.data = ngx_pnalloc(cf->pool, name->len);
if (v->name.data == NULL) {
return NGX_ERROR;
}
ngx_strlow(v->name.data, name->data, name->len);
//初始化变量
v->set_handler = NULL;
v->get_handler = NULL;
v->data = 0;
v->flags = 0;
v->index = cmcf->variables.nelts - 1;
//返回变量的索引值(即在变量数组中的序号)
return v->index;
}
3.通过变量的索引值获取变量值
ngx_http_variable_value_t *
ngx_http_get_indexed_variable(ngx_http_request_t *r, ngx_uint_t index)
{
if (cmcf->variables.nelts <= index) {
/*使用的索引值超过了数组的范围 返回空值*/
ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
"unknown variable index: %ui", index);
return NULL;
}
if (r->variables[index].not_found || r->variables[index].valid) {
/*变量not_found或者valid为真 直接返回变量值*/
return &r->variables[index];
}
/*获取配置的变量数组*/
v = cmcf->variables.elts;
if (ngx_http_variable_depth == 0) {
/*如果变量的深度为0 表明变量的值正在进行刷新 返回空值*/
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"cycle while evaluating variable \"%V\"",
&v[index].name);
return NULL;
}
/*减少一次变量深度*/
ngx_http_variable_depth--;
if (v[index].get_handler(r, &r->variables[index], v[index].data)
== NGX_OK)
{ /*获取变量ok 增加一次变量深度*/
ngx_http_variable_depth++;
if (v[index].flags & NGX_HTTP_VAR_NOCACHEABLE) {
/*变量本身是nocacheable标记 则重新加上 (以防在get函数中被修改)*/
r->variables[index].no_cacheable = 1;
}
/*返回变量*/
return &r->variables[index];
}
/*获取变量出错 */
//增加一次变量深度
ngx_http_variable_depth++;
/*
valid设置为假 not_found设置为真
valid表明变量无效 not_found表示没找到变量的值
在下次调用中能复用还未刷新的变量值*/
r->variables[index].valid = 0;
r->variables[index].not_found = 1;
return NULL;
}
4.获取刷新的变量值
ngx_http_variable_value_t *
ngx_http_get_flushed_variable(ngx_http_request_t *r, ngx_uint_t index)
{
/*通过index索引找到变量值*/
v = &r->variables[index];
if (v->valid || v->not_found) {
/*变量值是valid有效的或者是not_found标记 */
if (!v->no_cacheable) {
/*如果变量值可以缓存 返回变量值*/
return v;
}
/*重置 valid和not_found标记 以通过get函数获取变量 即刷新变量的作用*/
v->valid = 0;
v->not_found = 0;
}
/*通过3中的函数来取得变量的值*/
return ngx_http_get_indexed_variable(r, index);
}
5.通过变量名及key值取得变量值
ngx_http_variable_value_t *
ngx_http_get_variable(ngx_http_request_t *r, ngx_str_t *name, ngx_uint_t key)
{
...
/*在配置的变量表中取得变量 这儿使用hash值和名字来取得变量的*/
v = ngx_hash_find(&cmcf->variables_hash, key, name->data, name->len);
if (v) {
/*找到了变量 */
if (v->flags & NGX_HTTP_VAR_INDEXED) {
return ngx_http_get_flushed_variable(r, v->index);
}
/*发现变量的深度为0 注意变量深度是全局静态变量 针对所有请求而言
意味着变量正在进行“刷新” 此时返回空值*/
if (ngx_http_variable_depth == 0) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"cycle while evaluating variable \"%V\"", name);
return NULL;
}
/*减少变量深度*/
ngx_http_variable_depth--;
/*为变量值分配空间*/
vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
/*通过变量绑定的get函数计算得到变量的值*/
if (vv && v->get_handler(r, vv, v->data) == NGX_OK) {
//成功获得变量 增加一次变量深度
ngx_http_variable_depth++;
return vv;
}
//出错 增加一次变量深度并且返回空值
ngx_http_variable_depth++;
return NULL;
}
/*为变量值分配空间*/
vv = ngx_palloc(r->pool, sizeof(ngx_http_variable_value_t));
if (vv == NULL) {
/*分配出错 返回空值*/
return NULL;
}
len = 0;
/*在variables_hash中没有找到变量 则从prefix_variables变量表中查找*/
v = cmcf->prefix_variables.elts;
n = cmcf->prefix_variables.nelts;
for (i = 0; i < cmcf->prefix_variables.nelts; i++) {
if (name->len >= v[i].name.len && name->len > len
&& ngx_strncmp(name->data, v[i].name.data, v[i].name.len) == 0)
{ /*查找到变量 取得变量名的长度和索引值*/
len = v[i].name.len;
n = i;
}
}
/*索引值在prefix_variables变量表的范围之内 则通过绑定的get函数取得变量值*/
if (n != cmcf->prefix_variables.nelts) {
if (v[n].get_handler(r, vv, (uintptr_t) name) == NGX_OK) {
return vv;
}
/*获取变量出错 返回空值*/
return NULL;
}
/*没有找到变量 not_found为真 返回变量值*/
vv->not_found = 1;
return vv;
}
6.获取http请求的变量
static ngx_int_t
ngx_http_variable_request(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_str_t *s;
/*通过成员在ngx_http_request_t结构中的偏移计算得到成员的地址*/
s = (ngx_str_t *) ((char *) r + data);
if (s->data) {
/*成员有数据 得到数据*/
v->len = s->len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = s->data;
} else {
//成员中没有数据 进行not_found标记
v->not_found = 1;
}
return NGX_OK;
}
7.获取http_request_t成员中的“大小”类型的变量
static ngx_int_t
ngx_http_variable_request_get_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
size_t *sp;
/*通过结构体的偏移得到 地址*/
sp = (size_t *) ((char *) r + data);
/*为变量值分配空间*/
v->data = ngx_pnalloc(r->pool, NGX_SIZE_T_LEN);
if (v->data == NULL) {
//分配失败 返回错误
return NGX_ERROR;
}
/*拷贝数据到 变量值中*/
v->len = ngx_sprintf(v->data, "%uz", *sp) - v->data;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
return NGX_OK;
}
8.通过变量值设置http_request_t中的长度成员值
static void
ngx_http_variable_request_set_size(ngx_http_request_t *r,
ngx_http_variable_value_t *v, uintptr_t data)
{
...
//得到变量的长度及数据信息
val.len = v->len;
val.data = v->data;
/*解析字符串得到“长度”大小*/
s = ngx_parse_size(&val);
if (s == NGX_ERROR) {
/*解析失败 报错*/
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"invalid size \"%V\"", &val);
return;
}
/*取得位于结构体中的地址*/
sp = (ssize_t *) ((char *) r + data);
/* *引用取得值 并进行设置 内存地址无变化*/
*sp = s;
return;
}
9.获得http头变量的值
static ngx_int_t
ngx_http_variable_header(ngx_http_request_t *r, ngx_http_variable_value_t *v,
uintptr_t data)
{
ngx_table_elt_t *h;
/*通过结构体中的成员的偏移得到 hash表的元素*/
h = *(ngx_table_elt_t **) ((char *) r + data);
if (h) {
/*存在 则取得元素的值 并设置到变量中*/
v->len = h->value.len;
v->valid = 1;
v->no_cacheable = 0;
v->not_found = 0;
v->data = h->value.data;
} else {
/*不存在 进行not_found标记*/
v->not_found = 1;
}
return NGX_OK;
}
10.添加ngx_http_core_module中的变量
ngx_int_t
ngx_http_variables_add_core_vars(ngx_conf_t *cf)
{
...
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
/*为ngx_http_core_module的变量分配空间*/
cmcf->variables_keys = ngx_pcalloc(cf->temp_pool,
sizeof(ngx_hash_keys_arrays_t));
if (cmcf->variables_keys == NULL) {
/*分配失败 返回错误*/
return NGX_ERROR;
}
/*内存池设置*/
cmcf->variables_keys->pool = cf->pool;
cmcf->variables_keys->temp_pool = cf->pool;
/*初始化variables_keys hash表*/
if (ngx_hash_keys_array_init(cmcf->variables_keys, NGX_HASH_SMALL)
!= NGX_OK)
{
return NGX_ERROR;
}
/*初始化prefix_variables数组*/
if (ngx_array_init(&cmcf->prefix_variables, cf->pool, 8,
sizeof(ngx_http_variable_t))
!= NGX_OK)
{
return NGX_ERROR;
}
/*添加http core变量 注意cv取得的是指针数组*/
for (cv = ngx_http_core_variables; cv->name.len; cv++) {
v = ngx_http_add_variable(cf, &cv->name, cv->flags);
if (v == NULL) {
/*变量添加失败 返回错误*/
return NGX_ERROR;
}
/*设置变量值*/
*v = *cv;
}
return NGX_OK;
}
初始化配置的变量
ngx_int_t
ngx_http_variables_init_vars(ngx_conf_t *cf)
{
...
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
/*取得core_module的变量数组*/
v = cmcf->variables.elts;
/*取得prefix_variables变量数组*/
pv = cmcf->prefix_variables.elts;
/*取得variables_keys数组*/
key = cmcf->variables_keys->keys.elts;
for (i = 0; i < cmcf->variables.nelts; i++) {
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
av = key[n].value;
if (v[i].name.len == key[n].key.len
&& ngx_strncmp(v[i].name.data, key[n].key.data, v[i].name.len)
/*在variables hash表中找到了变量*/
== 0)
{
/*设置变量的get函数 及回调参数*/
v[i].get_handler = av->get_handler;
v[i].data = av->data;
/*将变量标记为 INDEXED*/
av->flags |= NGX_HTTP_VAR_INDEXED;
/*设置变量的flags标记*/
v[i].flags = av->flags;
//设置变量的索引值
av->index = i;
/*
变量没有设置get函数或者变量为weak标记(即不通过get进行获取)
跳出循环
*/
if (av->get_handler == NULL
|| (av->flags & NGX_HTTP_VAR_WEAK))
{
break;
}
goto next;
}
}
/*
在variables_keys hash表中没有找到变量
在prefix_variables表中查找变量
*/
len = 0;
av = NULL;
for (n = 0; n < cmcf->prefix_variables.nelts; n++) {
if (v[i].name.len >= pv[n].name.len && v[i].name.len > len
&& ngx_strncmp(v[i].name.data, pv[n].name.data, pv[n].name.len)
== 0)
{ /*找到了变量 取得变量和变量名的长度*/
av = &pv[n];
len = pv[n].name.len;
}
}
if (av) {
/*变量存在 设置变量的get函数及回调参数以及flags*/
v[i].get_handler = av->get_handler;
v[i].data = (uintptr_t) &v[i].name;
v[i].flags = av->flags;
/*完成*/
goto next;
}
if (v[i].get_handler == NULL) {
/*发现没有get函数 报错并且返回错误*/
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
"unknown \"%V\" variable", &v[i].name);
return NGX_ERROR;
}
next:
continue;
}
for (n = 0; n < cmcf->variables_keys->keys.nelts; n++) {
av = key[n].value;
if (av->flags & NGX_HTTP_VAR_NOHASH) {
/*对于不使用hash进行索引查找的变量 将key值置为空值*/
key[n].key.data = NULL;
}
}
/*hash表进行初始化*/
hash.hash = &cmcf->variables_hash;
hash.key = ngx_hash_key;
hash.max_size = cmcf->variables_hash_max_size;
hash.bucket_size = cmcf->variables_hash_bucket_size;
hash.name = "variables_hash";
hash.pool = cf->pool;
hash.temp_pool = NULL;
/*将vaiables_keys数据拷贝到 hash表中*/
if (ngx_hash_init(&hash, cmcf->variables_keys->keys.elts,
cmcf->variables_keys->keys.nelts)
!= NGX_OK)
{
return NGX_ERROR;
}
/*将variables_keys hash表赋值为空 并且返回*/
cmcf->variables_keys = NULL;
return NGX_OK;
}