1. 配置格式定義
1.1 配置項
ngx定義了兩種配置項,
簡單,以 ; 結尾
復雜,以 {} 結尾
由於簡單為;結尾,所以可以直接分行寫
1.2 上下文
復雜匹配項有上下文,實現繼承。
2. 指令定義
ngx定義了一些指令,模塊自己可以定義指令。
如 daemon 指令
ngx定義指令對象為
- name 指令名稱
- set 設置執行的回調方法(在解析配置時進行,傳入用戶配置的參數和指令上下文)
- offset 轉換后,配置值在結構體中的存放位置,對於不需要保存值的配置項,offset直接設置為0
- type 定義指令格式(在配置文件中怎么寫)
包含三種類別
- 指令類型:NGX_CONF_FLAGS 表示指令為 布爾類型。NGX_CONF_BLOCK表示為復雜指針類型
- 指令參數個數:NGX_CONF_NOARGS, NGX_CONF_TAKE1, NGX_CONF_TAKE2 ... NGX_CONF_TAKE12 ... NGX_CONF_1MORE ...
- 指令可存在上下文:NGX_MAIN_CONF, NGX_EVENT_CONF, NGX_HTTP_LOC_CONF ...
- conf 主要由 NGX_HTTP_MODULE 類型模塊使用,表示指令在當前配置項的大致位置,取值 NGX_HTTP_MAIN_CONF_OFFSET, NGX_HTTP_SRV_CONF_OFFSET, NGX_HTTP_LOC_CONF_OFFSET,其他模塊基本不使用,直接設置為0.
- post 大多數時候為NULL。
每個模塊把自己的指令 ngx_command_s 構成一個數組,並以 ngx_xxx_commands 形式命名,以ngx_null_command做哨兵。
3. 配置解析
ngx 使用 ngx_conf_parse 解析配置,
ngx_conf_read_token 解析讀取一條指令,並將參數保存到 cf->args 中
ngx_conf_handler 調用 指令的set回調
整個解析流程如下
ngx_conf_read_token 解析方法
4. 配置信息結構組織
整個配置在 cycle->conf_ctx.
ngx 只創建了必須模塊的配置對象,而有些核心模塊不一定會用到,所以對於這些模塊,若配置文件中使用了,才進行創建,如http模塊。
ngx_conf_param ,根據命令行參數初始化conf.ctx
ngx_conf_parse, 根據配置文件初始化 conf.ctx
每個模塊定義自己的創建函數,如ngx_core_module
NGX_CONF_UNSET 表示本變量沒有被用戶設置。
模塊如果有默認值,可以定義init函數,在init函數中給屬性賦默認值
如 ngx_core_module 的init函數
這樣就創建出了如下結構
如下每次 指令set時,都會傳遞本指令的上下文conf,而不同級別的指令的上下文不同cf->ctx
cmd->type == NGX_DIRECT_CONF 時,這個模塊就是核心模塊,所以這時的 cf->ctx 就是 cycle->conf_ctx
所以就可以得到 配置項對象conf,並調用 set 已設置他,如下是可能的情況
有些核心模塊不是 NGX_DRIECT_CONF,所以 conf 為指向 cycle->conf_ctx[i] 的指針。
如此,這些模塊可以自己創建 配置上下文。
http模塊分配,得到如下結構
ngx_http_conf_t 之所以有 main_conf, srv_conf, loc_conf 三個配置數組,是因為 http{}中可以寫 這三種級別的配置。
若 http 上下文中使用了 ngx_http_auth_basic_module 和 ngx_http_charset_filter_module 則,會生成如下配置結構。
在解析http{} 中配置時,會修改 cf->ctx 為http配置塊,
在解析server{}中配置時,會修改 cf->ctx 為server配置塊
可以看出 http{}塊的 main_conf[0] 指向 ngx_http_core_main_conf_t,ngx_http_core_main_conf_t.servers是一個數組,記錄了本http{}塊下所有 server{},
每個表示 server 塊的 ngx_http_conf_ctx_t 的 main_conf_t 又指向自己 http{} 塊。
每個server塊下可以寫 server級別和 location 級別配置項,所以 server上下文實現也有 srv_conf 和 loc_conf。
在進行server{}中配置項解析前,也會修改cf->ctx為 server的 ngx_http_conf_ctx_t.
對於loc配置,使用隊列管理
如上,server上下文的 loc_conf[0] 指向 ngx_http_core_loc_conf_t,ngx_http_core_loc_conf_t.locations 是鏈表節點,讓 server上下文用隊列方式管理所有其下的 location{},而每個 ngx_http_core_loc_conf_t 表示一個location{},ngx_http_core_loc_conf_t.loc_conf 指向其location{}中所有的配置項,loc_conf[0] 又回指 ngx_http_core_loc_conf_t。
而location{}上下文 ngx_http_conf_ctx_t 被加入哈希表中,其main_conf指向包含本location{}的 server 對應的 main_conf, server_conf指向包含本 location{} 的 server_conf。
解析location{}中配置項前,先修改 cf->ctx為 對應的 ngx_http_conf_ctx_t
location{}下可以包含location{},實現方式也是用隊列方式方式管理
當cf->ctx為server 或 location時,ngx_conf_handler的情況
confp指向的配置在前期已經 create了,所以可以直接修改。
cmd->conf的值為,比如
所以 (char *)cf->ctx + cmd->conf 就能找到對應的 loc_conf 或 server_conf 或 main_conf。
再根據模塊的索引號,就能返回需要配置的 模塊配置對象。
5. 配置的繼承
ngx配置繼承的邏輯:如果 本上下文定義了配置項,則優先使用本配置,否則使用上層配置,否則使用默認配置。
119 static char *
120 ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
121 {
233 /* parse inside the http{} block */
234
235 cf->module_type = NGX_HTTP_MODULE;
236 cf->cmd_type = NGX_HTTP_MAIN_CONF;
237 rv = ngx_conf_parse(cf, NULL);
...
248 cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
249 cscfp = cmcf->servers.elts;
250
251 for (m = 0; cf->cycle->modules[m]; m++) {
252 if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
253 continue;
254 }
255
256 module = cf->cycle->modules[m]->ctx;
257 mi = cf->cycle->modules[m]->ctx_index;
258
259 /* init http{} main_conf's */
260
261 if (module->init_main_conf) {
262 rv = module->init_main_conf(cf, ctx->main_conf[mi]);
266 }
267
268 rv = ngx_http_merge_servers(cf, cmcf, module, mi);
272 }
}
優先使用用戶配置值設置配置項,再使用 默認配置值,再進行merge.
559
560 static char *
561 ngx_http_merge_servers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf,
562 ngx_http_module_t *module, ngx_uint_t ctx_index)
563 {
570 cscfp = cmcf->servers.elts;
571 ctx = (ngx_http_conf_ctx_t *) cf->ctx;
572 saved = *ctx;
573 rv = NGX_CONF_OK;
574
575 for (s = 0; s < cmcf->servers.nelts; s++) {
576
577 /* merge the server{}s' srv_conf's */
578
579 ctx->srv_conf = cscfp[s]->ctx->srv_conf;
580
581 if (module->merge_srv_conf) {
582 rv = module->merge_srv_conf(cf, saved.srv_conf[ctx_index],
583 cscfp[s]->ctx->srv_conf[ctx_index]);
587 }
588
589 if (module->merge_loc_conf) {
590
591 /* merge the server{}'s loc_conf */
592
593 ctx->loc_conf = cscfp[s]->ctx->loc_conf;
594
595 rv = module->merge_loc_conf(cf, saved.loc_conf[ctx_index],
596 cscfp[s]->ctx->loc_conf[ctx_index]);
601 /* merge the locations{}' loc_conf's */
602
603 clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
604
605 rv = ngx_http_merge_locations(cf, clcf->locations,
606 cscfp[s]->ctx->loc_conf,
607 module, ctx_index);
611 }
612 }
619 }
620
合並main{}中的server配置項到server{},合並main{}中location配置項到location{},合並server{}中location配置項到location{}。
具體merge邏輯有模塊定義,如