前面幾章整理了Nginx的事件模組,這一章開始整理HTTP模組。
HTTP模組的初始化工作,都在src/http/nginx_http.c 中的ngx_http_block函數中進行的。
http模組的配置
在看nginx_http_block之前,我們還必須看一下nginx.conf中 HTTP大模組的設定檔,只有理解了HTTP模組的配置,才能更好的理解HTTP模組如何初始化的。
配置如下:
http { include mime.types; default_type application/octet-stream; #charset gb2312; server_names_hash_bucket_size 128; client_header_buffer_size 32k; large_client_header_buffers 4 32k; client_max_body_size 8m; sendfile on; tcp_nopush on; keepalive_timeout 60; tcp_nodelay on; fastcgi_connect_timeout 300; fastcgi_send_timeout 300; fastcgi_read_timeout 300; fastcgi_buffer_size 64k; fastcgi_buffers 4 64k; fastcgi_busy_buffers_size 128k; fastcgi_temp_file_write_size 128k; gzip on; gzip_min_length 1k; gzip_buffers 4 16k; gzip_http_version 1.0; gzip_comp_level 2; gzip_types text/plain application/x-javascript text/css application/xml; gzip_vary on; #limit_zone crawler $binary_remote_addr 10m; server { listen 80; #server_name blog.s135.com; index index.html index.htm index.php; root /home/wwwroot/; #limit_conn crawler 20; location ~ .*\.(php|php5)?$ { #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; } location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$ { expires 30d; } location ~ .*\.(js|css)?$ { expires 1h; } log_format access '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent "$http_referer" ' '"$http_user_agent" $http_x_forwarded_for'; access_log /usr/local/nginx-1.4.7/logs/access.log access; } server { listen 80; server_name status.blog.s135.com; location / { stub_status on; access_log off; } }
從上面的設定檔我們可以看到,HTTP的配置主要分為4層:
1. 最外層的http{} 模組。模組類型:NGX_CORE_MODULE (最外層的核心模組)
2. http核心模組中的main配置:http{include mine type; }。模組類型:NGX_HTTP_MODULE (全域的HTTP模組的配置資訊)
3. http核心模組中的server配置:server{}。模組類型:NGX_HTTP_MODULE (主要是配置Server的資訊)
4. http核心模組中的location本地資訊配置:location{}。模組類型:NGX_HTTP_MODULE (主要一個server對應的本地資源資訊:靜態資源、反向 Proxy連接埠地址、各種語言容器連接埠等)
最外層的http模組,類型NGX_CORE_MODULE,屬於核心模組,核心模組在最開始設定檔初始化的時候,就會調用指令的命令集。所以在核心模組啟動的時候就會調用http的模組配置解析指令函數:ngx_http_block
HTTP核心模組的資料結構
/** * HTTP模組命令集 * HTTP模組也是一個大模組,最外層為: * http { * .... * } * ngx_http_block:該方法就是回呼函數 * HTTP核心模組 */static ngx_command_t ngx_http_commands[] = { { ngx_string("http"), NGX_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_NOARGS, ngx_http_block, 0, 0, NULL }, ngx_null_command};/** *HTTP核心模組上下文 */static ngx_core_module_t ngx_http_module_ctx = { ngx_string("http"), NULL, NULL};/** * HTTP核心模組 結構 * 模組類型:NGX_CORE_MODULE * 通過調用ngx_http_block方法,解析{}中的HTTP模組配置 */ngx_module_t ngx_http_module = { NGX_MODULE_V1, &ngx_http_module_ctx, /* module context */ ngx_http_commands, /* module directives */ NGX_CORE_MODULE, /* module type */ NULL, /* init master */ NULL, /* init module */ NULL, /* init process */ NULL, /* init thread */ NULL, /* exit thread */ NULL, /* exit process */ NULL, /* exit master */ NGX_MODULE_V1_PADDING};
從上面的結構中可以看到http{} 是NGX_CORE_MODULE,在核心模組初始化的時候,會調用ngx_http_commands命令集中的回呼函數,逐個解析核心模組的配置資訊。
而HTTP模組的總入口就是這個http{}命令集的回呼函數:ngx_http_block
如果對設定檔如何解析有遺忘,請回顧《 Nginx源碼分析 - 主流程篇 - 解析設定檔 》
ngx_http_block函數詳解
/** *ngx_http_commands 命令集的回呼函數 *HTTP模組初始化的入口函數 * */static char *ngx_http_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf){ char *rv; ngx_uint_t mi, m, s; ngx_conf_t pcf; ngx_http_module_t *module; ngx_http_conf_ctx_t *ctx; ngx_http_core_loc_conf_t *clcf; ngx_http_core_srv_conf_t **cscfp; ngx_http_core_main_conf_t *cmcf; if (*(ngx_http_conf_ctx_t **) conf) { return "is duplicate"; } /* the main http context */ /* 分配一塊記憶體,存放http配置上下文 */ ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t)); if (ctx == NULL) { return NGX_CONF_ERROR; } *(ngx_http_conf_ctx_t **) conf = ctx; /* count the number of the http modules and set up their indices */ /* 計算http模組個數 */ ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE); /* the http main_conf context, it is the same in the all http contexts */ /** * 最外層的HTTP配置 * http { include mime.types; default_type application/octet-stream; */ ctx->main_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->main_conf == NULL) { return NGX_CONF_ERROR; } /* * the http null srv_conf context, it is used to merge * the server{}s' srv_conf's */ /** * server層的配置 * server { listen 80; #server_name blog.s135.com; index index.html index.htm index.php; root /home/wwwroot/; */ ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->srv_conf == NULL) { return NGX_CONF_ERROR; } /* * the http null loc_conf context, it is used to merge * the server{}s' loc_conf's */ /** * location 層的配置 location ~ .*\.(php|php5)?$ { #fastcgi_pass unix:/tmp/php-cgi.sock; fastcgi_pass 127.0.0.1:9000; fastcgi_index index.php; include fcgi.conf; } */ ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module); if (ctx->loc_conf == NULL) { return NGX_CONF_ERROR; } /* * create the main_conf's, the null srv_conf's, and the null loc_conf's * of the all http modules */ /** * 調用:create_main_conf、create_srv_conf、create_loc_conf * 建立配置 */ for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; mi = cf->cycle->modules[m]->ctx_index; if (module->create_main_conf) { ctx->main_conf[mi] = module->create_main_conf(cf); if (ctx->main_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_srv_conf) { ctx->srv_conf[mi] = module->create_srv_conf(cf); if (ctx->srv_conf[mi] == NULL) { return NGX_CONF_ERROR; } } if (module->create_loc_conf) { ctx->loc_conf[mi] = module->create_loc_conf(cf); if (ctx->loc_conf[mi] == NULL) { return NGX_CONF_ERROR; } } } pcf = *cf; cf->ctx = ctx; /** * preconfiguration 預先初始化配置資訊 */ for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; if (module->preconfiguration) { if (module->preconfiguration(cf) != NGX_OK) { return NGX_CONF_ERROR; } } } /* parse inside the http{} block */ cf->module_type = NGX_HTTP_MODULE; cf->cmd_type = NGX_HTTP_MAIN_CONF; rv = ngx_conf_parse(cf, NULL); if (rv != NGX_CONF_OK) { goto failed; } /* * init http{} main_conf's, merge the server{}s' srv_conf's * and its location{}s' loc_conf's */ /** * 初始化main配置 * 合并 server srv_conf * 合并location loc_conf */ cmcf = ctx->main_conf[ngx_http_core_module.ctx_index]; cscfp = cmcf->servers.elts; for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; mi = cf->cycle->modules[m]->ctx_index; /* init http{} main_conf's */ if (module->init_main_conf) { rv = module->init_main_conf(cf, ctx->main_conf[mi]); if (rv != NGX_CONF_OK) { goto failed; } } rv = ngx_http_merge_servers(cf, cmcf, module, mi); if (rv != NGX_CONF_OK) { goto failed; } } /* create location trees */ /** * 建立 location模組的trees */ 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) { return NGX_CONF_ERROR; } if (ngx_http_init_static_location_trees(cf, clcf) != NGX_OK) { return NGX_CONF_ERROR; } } if (ngx_http_init_phases(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } if (ngx_http_init_headers_in_hash(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } for (m = 0; cf->cycle->modules[m]; m++) { if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) { continue; } module = cf->cycle->modules[m]->ctx; if (module->postconfiguration) { if (module->postconfiguration(cf) != NGX_OK) { return NGX_CONF_ERROR; } } } if (ngx_http_variables_init_vars(cf) != NGX_OK) { return NGX_CONF_ERROR; } /* * http{}'s cf->ctx was needed while the configuration merging * and in postconfiguration process */ *cf = pcf; if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) { return NGX_CONF_ERROR; } /* optimize the lists of ports, addresses and server names */ /* ngx_http_optimize_servers 初始化listen 連接埠號碼 ip地址 伺服器等監聽資訊*/ if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) { return NGX_CONF_ERROR; } return NGX_CONF_OK;failed: *cf = pcf; return rv;}
下一章會詳細講解:
ngx_http_optimize_servers