nginx处理http(http变量篇)

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 
版权声明:本文为博主原创文章,转载请附上博文链接!

猜你喜欢

转载自blog.csdn.net/ai2000ai/article/details/84070875