nginx處理http(http變數篇)
阿新 • • 發佈:2018-11-20
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
版權宣告:本文為博主原創文章,轉載請附上博文連結!