这一部分,我们看看nginx怎样来组织http block,server block和location location的。
1、 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
首先设置一个ngx_http_conf_ctx_t结构,即ctx。
typedef struct {
void **main_conf;
void **srv_conf;
void **loc_conf;
} ngx_http_conf_ctx_t;
在分析这个结构中成员的作用时,先来看这样一个结构:
typedef struct {
ngx_int_t (*preconfiguration)(ngx_conf_t *cf);
ngx_int_t (*postconfiguration)(ngx_conf_t *cf);
void *(*create_main_conf)(ngx_conf_t*cf);
char *(*init_main_conf)(ngx_conf_t *cf, void *conf);
void *(*create_srv_conf)(ngx_conf_t *cf);
char *(*merge_srv_conf)(ngx_conf_t *cf, void *prev, void *conf);
void *(*create_loc_conf)(ngx_conf_t*cf);
char *(*merge_loc_conf)(ngx_conf_t *cf, void *prev, void *conf);
} ngx_http_module_t;
各个module可以根据需要设置这些函数指针。这些函数有他们各自的用途,create开头的主要是创建该module需要使用的结构体等等。
再看ngx_http_conf_ctx_t结构,这个结构体中的三个成员都是二级指针。实际上,各个module中create开头的函数都会创建module的配置结构,将得到的结构指针放到相应的数组中,如create_main_conf返回的指针会放到ctx->main_conf[i]中,create_srv_conf返回的指针会放到ctx->srv_conf[i]中。当然了这里会先对所有属于NGX_HTTP_MODULE的模块进行计数。
接下来,我们会先临时保存一下cf,因为在后面的递归解析时,cf的一些成员会被更改,而当返回的时候,原来的cf还要继续用。
pcf = *cf;
cf->ctx = ctx;
我们看这个preconfiguration,即ngx_http_module_t中的第一个函数指针。它的作用是什么?
当查看ngx_modules数组的时候,会发现下面几个module设置了preconfiguration:
ngx_http_core_preconfiguration (实际上调用了ngx_http_variables_add_core_vars),
ngx_http_upstream_add_variables,
ngx_http_proxy_add_variables,
ngx_http_browser_add_variable
说白了,这四个函数主要是在开始后面的解析之前,设置一些变量,来为后用(主要是在脚本解析编译的时候)。我们看到的是,他们依次设置了这么几个变量(即,全局数组):
ngx_http_core_variables,ngx_http_upstream_vars,ngx_http_proxy_vars,ngx_http_browsers。具体内容大家可以自己去读下代码,这些信息都是后面解析可能会用到的,这也就是preconfiguration中pre前缀的意思了!
接下来这两句告诉我们,下面要解析的内容是只涉及http相关module,而且其配置的指令是直接出现在http block中,而非server或者location,即所谓的MAIN_CONF。
cf->module_type = NGX_HTTP_MODULE;
cf->cmd_type = NGX_HTTP_MAIN_CONF;
当下面这句返回的时候,整个解析就结束了,这也体现了递归的特点!
rv = ngx_conf_parse(cf, NULL);
这里先进到递归过程的内部,出来之后我们再看后面的处理。
进入ngx_conf_parse之后,会遇到“server”,然后会调用ngx_http_core_server处理server block的配置。
2、 ngx_http_core_server(ngx_conf_t *cf, ngx_command_t *cmd, void*dummy)
首先会创建一个ngx_http_conf_ctx_t结构,我们知道http block中可能会配置多个server,这样ngx_http_core_server也就被调用多次,我们后面会看到这些ngx_http_conf_ctx_t,即ctx,在各层之间建立一系列复杂的关系。
看下面这两句,server里面的ctx->main_conf指向http ctx的main_conf,这么做的原因很简单,block 的main_conf在各个server公用的,这里只是继承上层的main_conf配置。
http_ctx = cf->ctx;
ctx->main_conf = http_ctx->main_conf;
接下来会出现跟http block处理中相似的一幕,ctx->srv_conf和ctx->loc_conf分别得到了初始化。这里大家应该意识到location block中肯定也会有相似的一幕,呵呵!
我们看到有这样的一个层次:http->server->location,在每个层次的处理时,都会创建一个ctx(即ngx_http_conf_ctx_t),然后它会继承上层的配置,只处理属于自己层次的东西,如location block中的ctx,srv_conf和main_conf都会继承上层的,而loc_conf则会在当前被设置。
后面会很多次的使用ngx_http_core_module,毕竟接下来的都是http配置的处理。
接下的几句比较好理解,有几点需要强调一下。
cscf->ctx = ctx; //这样在解析server部分的时候,就可以很方便的引用上层和下层的配置。
cmcf->servers; // main_conf中的servers是一个数组,httpblock中配置的各个server,都会作为数组成员放到里面.
后面的处理跟http block中的类似,进入到server{}的里面,继续解析,并将处理location的
配置。在ngx_conf_parse返回之后,若发现没有配置listen,那么nginx会这设置默认的。
先说一下,location的解析是整个配置解析里面最复杂的,下次会单独展开来讲。