http块指令解析以及存储

在配置文件一节中已经说明了可能会在ngx_conf_handler中递归的解析块中的指令,而这些块中的指令的解析则是由Ngx_http_core_module来完成的,也就是说当ngx_http_module模块在解析完main的指令以后,如果遇到了server或者location指令的时候则会启用ngx_http_core_module模块
ngx_http_core_module负责解析接下来的模块,它识别server和location指令,server指令对应得解析函数是ngx_http_core_server,而它的指令类型刚好是ngx_http_block设置的ngx_http_main_conf,而location指令的类型是ngx_http_srv_conf,它对应得函数是ngx_http_core_location
也就是说在上述的ngx_conf_parse函数中会把所有的server块和location块指令的内容全部解析完毕
在ngx_http_core_server和ngx_http_core_location函数中会申请存储配置结构体的空间,并且接续调用ngx_conf_parse函数进行解析

1.解析server块:
刚开始无非就是申请内存空间,并且把ngx_http_conf_ctx_t中的三个指针都安排好,并且依次调用create_conf函数
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}

http_ctx = cf->ctx; // 全局http module的配置
ctx->main_conf = http_ctx->main_conf;

ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void ) ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}

/* the server{}’s loc_conf */

ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void ) ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
//server和location块则是分别申请内存
//接下来依次调用每个模块的create_srv_conf和create_loc_conf创建配置结构体,并且更新数组内容
cscf = ctx->srv_conf[ngx_http_core_module.ctx_index];
cscf->ctx = ctx;

cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];

cscfp = ngx_array_push(&cmcf->servers);
if (cscfp == NULL) {
return NGX_CONF_ERROR;
}

*cscfp = cscf;
//把后面所创建的每一个server块添加到ngx_http_core_module通常create_main_conf_t创建的ngx_http_main_cont_ctx_t中的servers数组中

pcf = *cf; // 保存cf的副本,在解析完server块后恢复
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_SRV_CONF; // 解析NGX_HTTP_SRV_CONF类型的指令,即server块下的指令
这个时候开始解析server块的指令了,
rv = ngx_conf_parse(cf, NULL);//开始解析配置文件
if (rv == NGX_CONF_OK && !cscf->listen) {
ngx_memzero(&lsopt, sizeof(ngx_http_listen_opt_t));

    sin = &lsopt.u.sockaddr_in;  

    sin->sin_family = AF_INET;  
    sin->sin_port = htons(80);  
    sin->sin_port = htons((getuid() == 0) ? 80 : 8000);  
    sin->sin_addr.s_addr = INADDR_ANY;  

    lsopt.socklen = sizeof(struct sockaddr_in);  

    lsopt.backlog = NGX_LISTEN_BACKLOG;  
    lsopt.rcvbuf = -1;  
    lsopt.sndbuf = -1;  
    lsopt.setfib = -1;  
    lsopt.wildcard = 1;  

    (void) ngx_sock_ntop(&lsopt.u.sockaddr, lsopt.addr,  
                         NGX_SOCKADDR_STRLEN, 1);  

    if (ngx_http_add_listen(cf, cscf, &lsopt) != NGX_OK) {  
        return NGX_CONF_ERROR;  
    }  
}  
//用于设置默认的监听套接口,一般是通过listen指令获取,也就是说如果在该快中出现listen的配置项,那就采用对应得函数进行设置,详细见监听socket初始化
如果没有设置listen配置项的话,直接采用默认的80/8080,地址是任何网络接口,最后调用ngx_http_add_listen把监听socket添加进去

2.解析location块
上述在ngx_conf_parse的函数中,如果遇到location指令的话,那么就会调用ngx_http_core_loc函数对Location进行解析,在该函数中又会继续递归调用ngx_conf_parse函数
同样先生成ngx_http_conf_ctx_t的结构体,把里面的三个指针分别指向其他的结构体,而对于create_loc_conf而言,再同样生成一份数组,存储loc级别的配置

clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;
//获取ngx_http_core_loc_conf_t结构体,
value = cf->args->elts;
//获取location行的内容
接下来很长的一段代码负责解析location后面的参数,通过查看他的参数个数决定 它的匹配规则以及是否需要采用正则表达式

if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK)
//负责把当前的location添加到server级别的ngx_http_core_module生成的ngx_http_core_loc_conf_t结构体中的locations队列,后面会依据这个队列把所有的location块组织成静态查找树

save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF; /* 只解析location块内的指令 */

rv = ngx_conf_parse(cf, NULL);
//开始解析location块内的指令

综上所有的函数完成以后,ngx_http_block中的ngx_conf_parse函数才完成了。

猜你喜欢

转载自blog.csdn.net/wellwang1993/article/details/51179084
今日推荐