[nginx源码分析]location划分

整个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




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值