1. 程式人生 > >nginx處理http(http變數篇)

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 
版權宣告:本文為博主原創文章,轉載請附上博文連結!