1.ngx_http_core_location(ngx_conf_t*cf, ngx_command_t *cmd, void *dummy)
通过前面的分析,location部分的解析跟http和server是同样的道理。
来看下面两句:
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;
ctx是在解析该location时生成的ngx_http_conf_ctx_t,自然它的main_conf和srv_conf都会继承上层,而在本层重新设置loc_conf,这里我们看到,在location的解析中
ngx_http_core_loc_conf_t结构(即clcf)的loc_conf成员会保存所有其他module的location配置,用到的时候引用方便。
这里还有几个要说一下的:
clcf->exact_match:类似 location = / {},所谓准确匹配。
clcf->noregex:没有正则,但不要求准确匹配,如/usr可以跟/usr/local算匹配
clcf->named:以’@’开头的,如location @test {}
clcf->noname:nginx会把if 指令配置也看做一个location,即noname类型。
location中出现‘~’的,就认为是有正则的配置了,就会调用ngx_http_core_regex_location
来处理,注意一点的是,这个函数的第三个参数是大小写标记,一般“~”是忽略大小写处理的,而“~*”是要考虑大小写的。
函数中会调用ngx_http_regex_compile来对正则表达式做处理,使用是PCRE库,具体的接口和原理,大家可以去PCRE官网去找一下。这个函数的一个重点在于它会把正则中出现的$1,$2…等,提取出代表的字符串作为一个” 参数”,放到全局的参数表中,供后面使用。关于nginx中的变量和脚本特性,会在配置解析这块分析完之后,做专门分析。
继续看:
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
这里是拿到上层的location(若有的话),来验证内嵌的location配置语法是否合法。
如果上层的location是准确配置的(即exact_match)或者带“@”的(named),那么不允许内嵌location,还有内嵌的location不能为named,即带“@”的。如果这些检查通过,那么还要求内嵌的location 路径要跟上层的路径有公共前缀。
如:
location /usr/ {
location /usr/local/ {
}
}
来看这个函数:ngx_http_add_location
它涉及一个ngx_http_location_queue_t的结构, 即lq。一个location的配置,即代码里的clcf会通过这个结构保存,如果当前的location没有嵌套,那么它就是exact的,放在这个结构的exact,嵌套的放到结构的inclusive中。
看这一句:ngx_queue_insert_tail(*locations,&lq->queue);
大家应该明白它的意图,那就是内嵌在一个location中的各个location配置,会组成一个双向queue,挂在上层的配置结构locations成员里(即queue头),如pclcf->locations。
从server配置的角度看,每遇到一个location,都会建立一个双向queue,没有内嵌的,也就只有它自己罢了。
location部分就做了这些事情,因为整个处理是一个递归过程,所以我们看看当解析完location,回到http处理时,还会做些什么。
回到函数ngx_http_block,我们前面说过了,当ngx_http_block中ngx_conf_parse返回的时候,意味着下层的server和locatio都已解析整理完毕了。好了,我们把最后的任务拿出来看下:
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
cscfp = cmcf->servers.elts;
for (s = 0; s < cmcf->servers.nelts; s++) {
clcf =cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
if(ngx_http_init_locations(cf, cscfp[s], clcf) != NGX_OK) {
returnNGX_CONF_ERROR;
}
if(ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
就是这样一个for循环,那么它到底做了什么?
cscfp是http block中各个server的配置信息,以数组的形式保存在main_conf的servers成员里。
这一句:clcf =cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
我们拿到http_core_module在各个srv_conf,即cscfp[s],并从中获得loc_conf,即clcf,这两个结构作为ngx_http_init_locations的第二和第三个参数传入,有一点需要记住的是,clcf中的locations成员(即queue头),包含了该server下的所有location。
我们进入ngx_http_init_locations函数。
首先对locationqueue进行排序,即ngx_queue_sort,排序的规则可以读一下ngx_http_cmp_locations函数。
排列完成之后的顺序大致为:regex,named,noname等,而且每个相同类型可能含有多个,如r1,r2,r3,n1,n2,n3,nm1,nm2,这样可以把相同类型的归为一类,代码中则通过regex和r来记录regex类型的开始位置和个数,name和n记录named类型的起始位置和个数。类型分离时,使用ngx_queue_split按照从后往前的方式,先分离noname(没有像后面两个那样集中管理),在分离named(保存到cscf->named_locations),最后分离regex(保存到pclcf->regex_locations= clcfp),分离这些另类之后,我们处理那些普通的location,普通的location大家应该知道是指的哪些,nginx称为static location。
从ngx_http_init_locations返回后,我们看到接下来的处理,之前我们已经把一个server下面的locations做了处理,包括切割和分类,下面的ngx_http_init_static_location_trees函数就会将那些普通的location,即staticlocation,进行树化(一种三叉树)处理,之所以要做这样的处理,是为了在处理http请求时能高效的搜索的匹配的location配置。
我们知道的一点是,这些staticlocation放在了一个queue中,里面每个节点可能还会挂有内嵌的location,所以ngx_http_init_static_location_trees会在他们内嵌的location里被递归调用,所以我们明白了无内嵌location的建树过程,基本上就知道是个什么结果是个什么样子了。
在处理中,会先调用ngx_http_join_exact_locations函数来做一些预处理,主要是去重,去重的标准,代码里体现的很明确,这里就不说了。
接下来调用ngx_http_create_locations_list,这个函数的作用是这样的:
在开始的这个locationqueue中,有一些是有相同路径前缀的,自然他们在排序的时候也是会挨在一起的,ngx_http_create_locations_list会将跟某个location有相同前缀的location,从原来的queue上取下,挂在该location的list成员下,这样在主queue上的location都是具有相互不同name的location了。举个例子:
主链:/a ->/ab -> /abc-> /b ->/bc -> /bcd-> /c -> /cd-> /cde
处理之后:
/a ->/b -> /c
| | |
/ab /bc/cd
| | |
/abc /bcd/cde
好了最后我们调用ngx_http_create_locations_tree来完成这个三叉树的创建。
主要说下大概的过程吧,像这种算法的分析,讲起来会很啰嗦,这里只是提个纲,大家还是得自己看。
1.在一个queue中取中间位置(算法大家可以借鉴),分成两部分
2.左边的部分,递归调用ngx_http_create_locations_tree,生成left树
3.右边的部分,递归调用ngx_http_create_locations_tree,生成right树
4.中间位置的location,通过它的list,通过递归调用ngx_http_create_locations_tree,生成tree树(可以认为是中树)。
大家可以想象一下,这样的一个过程结束时候的情景,呵呵!差不多就是这样了。
关于location的解析和管理,可以进一步参考下面的blog,作者使用一个实例来讲解,更容易理解一些,大家可以一起拿来参考!
BS: 本人水平有限,分析中可能有一些理解不到位的地方,还请大家多指点!