[nginx源码分析]location划分

来源:互联网 发布:apt get 修改源码 编辑:程序博客网 时间:2024/04/29 03:38

整个ngx_http_block中的ngx_conf_parse配置解析完成,,后面主要对配置文件进行优化。

优化可以分为以下:

1 配置作用域合并

2 location划分

3 http header回调初始化hash

4 初始化http收包回调函数

5 server中的server_name形成hash

先对location类型概述:

Syntax:location [ = | ~ | ~* | ^~ ] uri { ...} location = / {#matches the query /only    [ configuration A ]}location / {#match any query ,since all queries begin with /, but regular#expression and any longer conventional blocks will be #match first    [ configuration B ]}location ^~ /images/ {#matches any query beginning with /image/ and halts searching #so regular expressions will not be checked    [ configuration C ]}location ~* \.(gif|jpg|jpeg)$ {# matches any request ending in gif,jpg, or jpeg .however, all # requests to be /images/ directory with be handled by config c    [ configuration D ]}

从location语法中可以看到,基本可以分为4类locaiton

1 只包含一个url的是前缀匹配,即以这个指定字符为前缀的请求地址都能与它匹配上,比如请求地址”/document.html”, 以字符串”/”为前缀,所以能与配置B匹配上(当然,最终的匹配结果是否就是配置B,还需要看其他location配置,因为nginx采用的是最佳匹配)

2 如果加上=表示绝对匹配,则表示绝对匹配location,在上面的示例,只有当前处理请求的uri完全匹配字符串”/”(即不能多一个字符,也不能少一个字符)时,才被定位并使用对应的相关配置A

3 正则匹配location是由限定符” ~ ”(区分大小写)或“~*“(不区分大小写)指定的,此时给出的uri是一个正则表达式,请求地址满足该正则表达式的就能匹配上。

4 由限定符”^~”指定的location也是前缀匹配location,不过它暗示了在实际进行location定位时不用搜索正则匹配locaiton

5 还有另外两种地址分别称之为命名location和未命名locaiton,命名locaiton仅用于server内部跳转,看如下中rewrite就是命名location。

location@rewrite{

         rewrite^/wiki/search(.*)$/search.php?search=$1 last;

}

 

其中在配置解析的时候(往前翻), 已经解析过location是保存在server上下文的loc_conf的locations 链表中。

下面的分析师对链表中的几点进行修剪。

函数是ngx_http_init_locations

首先是对server下的location进行排序,调用的函数是ngx_queue_sort,因为locations本身就是一个双向链表,然后该函数是典型的插入排序,比较函数是ngx_http_cmp_locations

ngx_queue_sort(locations,ngx_http_cmp_locations)

比较函数ngx_http_cmp_locations的算法原则是:

1 首先是如果比较的额两个节点中插入的是未命名的,那么把该节点加入到后面,如果比较的两个节点都是未命名的,那么保持原定次序。

2 如果插入的两个节点中,插入的是命名的location,那么把该节点加入到后面,如果比较的两个节点都是命名的,那么比较location名称,按照字母序进行排序。

3 如果两个比较节点中,插入的是正则location,那么就把插入即诶的那加入到后面,如果比较的两个节点都是正则,那么就按照原定次序,即保持用户在配置文件里书序的先后顺序。

所以插入的降序是未命名、命名、正则、前缀匹配|绝对匹配。

static ngx_int_t  ngx_http_cmp_locations(const ngx_queue_t *one, const ngx_queue_t *two)  {      ngx_int_t                   rc;      ngx_http_core_loc_conf_t   *first, *second;      ngx_http_location_queue_t  *lq1, *lq2;        lq1 = (ngx_http_location_queue_t *) one;      lq2 = (ngx_http_location_queue_t *) two;        first = lq1->exact ? lq1->exact : lq1->inclusive;                                                                                                                                                                                        second = lq2->exact ? lq2->exact : lq2->inclusive;        if (first->noname && !second->noname) {          /* shift no named locations to the end */          return 1;      }        if (!first->noname && second->noname) {          /* shift no named locations to the end */          return -1;      }        if (first->noname || second->noname) {          /* do not sort no named locations */          return 0;      }        if (first->named && !second->named) {          /* shift named locations to the end */          return 1;      }        if (!first->named && second->named) {          /* shift named locations to the end */          return -1;      }        if (first->named && second->named) {          return ngx_strcmp(first->name.data, second->name.data);      }    #if (NGX_PCRE)        if (first->regex && !second->regex) {          /* shift the regex matches to the end */          return 1;      }        if (!first->regex && second->regex) {          /* shift the regex matches to the end */          return -1;      }        if (first->regex || second->regex) {          /* do not sort the regex matches */          return 0;      }    #endif        rc = ngx_strcmp(first->name.data, second->name.data);        if (rc == 0 && !first->exact_match && second->exact_match) {          /* an exact match must be before the same inclusive one */          return 1;      }        return rc;  }

排序完后进行location切分。location排序完,整个list的结构是:

前缀匹配|绝对匹配--->正则匹配--->命名--> 未命名

切分就是遍历整个locationslist,然后找到正则匹配开始,命名匹配开始处

//这层循环主要是遍历整个locations链表找到regex的起始位置和named的起始位置

 for (q = ngx_queue_head(locations);           q != ngx_queue_sentinel(locations);                        //遍历每一个location           q = ngx_queue_next(q))      {          lq = (ngx_http_location_queue_t *) q;            clcf = lq->exact ? lq->exact : lq->inclusive;            if (ngx_http_init_locations(cf, NULL, clcf) != NGX_OK) {    //这里是一个递归,如果存在location下面还有locations的话还会进行递归调用              return NGX_ERROR;          }    #if (NGX_PCRE)            if (clcf->regex) {              r++;                if (regex == NULL) {                  regex = q;              }                continue;          }    #endif            if (clcf->named) {              n++;                if (named == NULL) {                  named = q;              }                continue;          }            if (clcf->noname) {              break;          }      }

其他切分就不细说了,代码很easy,然后location就剩下前缀匹配和绝对匹配了。

 

然后对前缀匹配进行优化,函数是ngx_http_init_static_location_trees




0 0