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;
}
---------------------
作者:huzilinitachi
来源:CSDN
原文:https://blog.csdn.net/huzilinitachi/article/details/79902950
版权声明:本文为博主原创文章,转载请附上博文链接!
超强干货来袭 云风专访:近40年码龄,通宵达旦的技术人生
总结
以上是生活随笔为你收集整理的nginx处理http(http变量篇)的全部内容,希望文章能够帮你解决所遇到的问题。
如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。