1. 程式人生 > >http塊指令解析以及儲存

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函式才完成了。