您的位置:首页 > 运维架构 > Nginx

Nginx配置文件解析之三

2011-11-10 09:42 796 查看
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:没有正则,指类似location ^~ /a { ... } 的location。

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,作者使用一个实例来讲解,更容易理解一些,大家可以一起拿来参考!

http://blog.csdn.net/fengmo_q/article/details/6683377

 

BS: 本人水平有限,分析中可能有一些理解不到位的地方,还请大家多指点!

 

 
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息