我们继续分析ngx_http_block函数的代码,指令解析完,继续执行各子模块的钩子函数。
/*
* init http{} main_conf's, merge the server{}s' srv_conf's
* and its location{}s' loc_conf's
*/
// 取出ngx_http_core_module在http上下文的main配置
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
// server指令的管理结构
cscfp = cmcf->servers.elts;
for (m = 0; ngx_modules[m]; m++) {
if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
continue;
}
module = ngx_modules[m]->ctx;
mi = ngx_modules[m]->ctx_index;
/* init http{} main_conf's */
// ngx_conf_parse没有赋值的字段在这进行初始化
if (module->init_main_conf) {
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
}
// http上下文下所有的server指令对应的结构体数组
for (s = 0; s < cmcf->servers.nelts; s++) {
/* merge the server{}s' srv_conf's */
if (module->merge_srv_conf) {
// 合并http层和server层配置
rv = module->merge_srv_conf(cf,
// 子模块在http上下文的srv_conf配置,内容由子模块创建
ctx->srv_conf[mi],
/*
cscfp[s]指向server上下文中的ngx_http_core_srv_conf_t结构体,
通过反向指针找到server指令创建的上下文,再找出某个模块的的srv_conf
*/
cscfp[s]->ctx->srv_conf[mi]);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
}
if (module->merge_loc_conf) {
/* merge the server{}'s loc_conf */
// 合并http层和非嵌套的location层的配置
rv = module->merge_loc_conf(cf,
ctx->loc_conf[mi],
cscfp[s]->ctx->loc_conf[mi]);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
/* merge the locations{}' loc_conf's */
/*
合并server和非嵌套location的配置、非嵌套location和嵌套location的配置,
&cscfp[s]->locations:server下的所有非嵌套location
cscfp[s]->ctx->loc_conf,server层各模块关于location的配置
*/
rv = ngx_http_merge_locations(cf, &cscfp[s]->locations,
cscfp[s]->ctx->loc_conf,
module, mi);
if (rv != NGX_CONF_OK) {
*cf = pcf;
return rv;
}
}
}
}
1 init_main_conf 只有charset模块实现了init_main_conf函数。
static char *ngx_http_charset_init_main_conf(ngx_conf_t *cf, void *conf)
{
ngx_http_charset_main_conf_t *mcf = conf;
ngx_uint_t i, n;
ngx_http_charset_t *charset;
ngx_http_charset_tables_t *tables;
tables = mcf->tables.elts;
charset = mcf->charsets.elts;
// 遍历charset数组
for (i = 0; i < mcf->charsets.nelts; i++) {
if (!charset[i].server) {
continue;
}
charset[i].tables = ngx_pcalloc(cf->pool,
sizeof(char *) * mcf->charsets.nelts);
if (charset[i].tables == NULL) {
return NGX_CONF_ERROR;
}
for (n = 0; n < mcf->tables.nelts; n++) {
if ((ngx_int_t) i == tables[n].src) {
charset[i].tables[tables[n].dst] = tables[n].src2dst;
continue;
}
if ((ngx_int_t) i == tables[n].dst) {
charset[i].tables[tables[n].src] = tables[n].dst2src;
}
}
}
//校验
for (i = 0; i < mcf->charsets.nelts; i++) {
if (!charset[i].server) {
continue;
}
for (n = 0; n < mcf->charsets.nelts; n++) {
if (i == n) {
continue;
}
if (charset[i].tables[n]) {
continue;
}
ngx_log_error(NGX_LOG_EMERG, cf->log, 0,
" no \"charset_map\" between the charsets "
"\"%s\" and \"%s\"",
charset[i].name.data, charset[n].name.data);
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
在这里插入图片描述
2 merge_srv_conf 我们继续看一下各个模块的merge_srv_conf函数。 http_core模块
static char *ngx_http_core_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child)
{
ngx_http_core_srv_conf_t *prev = parent;
ngx_http_core_srv_conf_t *conf = child;
ngx_http_listen_t *l;
ngx_http_server_name_t *n;
ngx_http_core_main_conf_t *cmcf;
/* TODO: it does not merge, it inits only */
// 如果该server没有配置listen指令,则设置默认值
if (conf->listen.nelts == 0) {
ngx_test_null(l, ngx_push_array(&conf->listen), NGX_CONF_ERROR);
// 任何地址进来的连接都可以
l->addr = INADDR_ANY;
#if (WIN32)
l->port = 80;
#else
/* STUB: getuid() should be cached */
// 等于0说明是root
l->port = (getuid() == 0) ? 80 : 8000;
#endif
l->family = AF_INET;
}
// 没有配置servername,则取本机主机名
if (conf->server_names.nelts == 0) {
ngx_test_null(n, ngx_push_array(&conf->server_names), NGX_CONF_ERROR);
ngx_test_null(n->name.data, ngx_palloc(cf->pool, NGX_MAXHOSTNAMELEN),
NGX_CONF_ERROR);
// 获取主机名
if (gethostname((char *) n->name.data, NGX_MAXHOSTNAMELEN) == -1) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, ngx_errno,
"gethostname() failed");
return NGX_CONF_ERROR;
}
n->name.len = ngx_strlen(n->name.data);
// 该servername对应的server配置
n->core_srv_conf = conf;
#if 0
ctx = (ngx_http_conf_ctx_t *)
cf->cycle->conf_ctx[ngx_http_module.index];
cmcf = ctx->main_conf[ngx_http_core_module.ctx_index];
#endif
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
if (cmcf->max_server_name_len < n->name.len) {
cmcf->max_server_name_len = n->name.len;
}
}
/*
如果第一个参数没有值,则取第二个参数的,如果第二个参数也没有值,
则取第三个参数的,即子类没有值,则取父类的,父类也没有值,则取默认的
*/
ngx_conf_merge_size_value(conf->connection_pool_size,
prev->connection_pool_size, 256);
ngx_conf_merge_msec_value(conf->post_accept_timeout,
prev->post_accept_timeout, 60000);
ngx_conf_merge_size_value(conf->request_pool_size,
prev->request_pool_size, 4096);
ngx_conf_merge_msec_value(conf->client_header_timeout,
prev->client_header_timeout, 60000);
ngx_conf_merge_size_value(conf->client_header_buffer_size,
prev->client_header_buffer_size, 1024);
ngx_conf_merge_bufs_value(conf->large_client_header_buffers,
prev->large_client_header_buffers,
4, ngx_pagesize);
if (conf->large_client_header_buffers.size < conf->connection_pool_size) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"large_client_header_buffers\" size must be "
"equal to or bigger than \"connection_pool_size\"");
return NGX_CONF_ERROR;
}
ngx_conf_merge_unsigned_value(conf->restrict_host_names,
prev->restrict_host_names, 0);
return NGX_CONF_OK;
}
rewrite模块
static char *ngx_http_rewrite_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child)
{
ngx_http_rewrite_srv_conf_t *prev = parent;
ngx_http_rewrite_srv_conf_t *conf = child;
ngx_conf_merge_value(conf->log, prev->log, 0);
return NGX_CONF_OK;
}
ssl模块
static char *ngx_http_ssl_merge_srv_conf(ngx_conf_t *cf,
void *parent, void *child)
{
ngx_http_ssl_srv_conf_t *prev = parent;
ngx_http_ssl_srv_conf_t *conf = child;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
if (conf->enable == 0) {
return NGX_CONF_OK;
}
// server上下文里没有配置证书和私钥则取http上下文的
ngx_conf_merge_str_value(conf->certificate, prev->certificate,
NGX_DEFLAUT_CERTIFICATE);
ngx_conf_merge_str_value(conf->certificate_key, prev->certificate_key,
NGX_DEFLAUT_CERTIFICATE_KEY);
/* TODO: configure methods */
conf->ssl_ctx = SSL_CTX_new(SSLv23_server_method());
if (conf->ssl_ctx == NULL) {
ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0, "SSL_CTX_new() failed");
return NGX_CONF_ERROR;
}
// 加载用户证书
if (SSL_CTX_use_certificate_file(conf->ssl_ctx,
(char *) conf->certificate.data,
SSL_FILETYPE_PEM) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
"SSL_CTX_use_certificate_file(\"%s\") failed",
conf->certificate.data);
return NGX_CONF_ERROR;
}
// 加载用户私钥
if (SSL_CTX_use_PrivateKey_file(conf->ssl_ctx,
(char *) conf->certificate_key.data,
SSL_FILETYPE_PEM) == 0) {
ngx_ssl_error(NGX_LOG_EMERG, cf->log, 0,
"SSL_CTX_use_PrivateKey_file(\"%s\") failed",
conf->certificate_key.data);
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
}
3 merge_loc_conf access模块
static char *ngx_http_access_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child)
{
ngx_http_access_loc_conf_t *prev = parent;
ngx_http_access_loc_conf_t *conf = child;
// 如果location里的配置为空,则取父级的配置
if (conf->rules == NULL) {
conf->rules = prev->rules;
}
return NGX_CONF_OK;
}
charset模块
static char *ngx_http_charset_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child)
{
ngx_http_charset_loc_conf_t *prev = parent;
ngx_http_charset_loc_conf_t *conf = child;
ngx_conf_merge_value(conf->enable, prev->enable, 0);
ngx_conf_merge_value(conf->autodetect, prev->autodetect, 0);
if (conf->source_charset == NGX_CONF_UNSET) {
conf->source_charset = prev->source_charset;
}
ngx_conf_merge_value(conf->default_charset, prev->default_charset,
conf->source_charset);
return NGX_CONF_OK;
}
http_core模块
static char *ngx_http_core_merge_loc_conf(ngx_conf_t *cf,
void *parent, void *child)
{
ngx_http_core_loc_conf_t *prev = parent;
ngx_http_core_loc_conf_t *conf = child;
int i, key;
ngx_http_type_t *t;
ngx_conf_merge_str_value(conf->root, prev->root, "html");
if (ngx_conf_full_name(cf->cycle, &conf->root) == NGX_ERROR) {
return NGX_CONF_ERROR;
}
// 子层没有配置types
if (conf->types == NULL) {
// 父层也没有配置
if (prev->types) {
conf->types = prev->types;
} else {
// 取默认的
ngx_test_null(conf->types,
ngx_palloc(cf->pool, NGX_HTTP_TYPES_HASH_PRIME
* sizeof(ngx_array_t)),
NGX_CONF_ERROR);
// 初始化分配的数组
for (i = 0; i < NGX_HTTP_TYPES_HASH_PRIME; i++) {
ngx_init_array(conf->types[i], cf->pool,
5, sizeof(ngx_http_type_t), NGX_CONF_ERROR);
}
// 遍历默认配置
for (i = 0; default_types[i].exten.len; i++) {
/*
#define ngx_http_types_hash_key(key, ext) \
{ \
u_int n; \
for (key = 0, n = 0; n < ext.len; n++) { \
key += ext.data[n]; \
} \
key %= NGX_HTTP_TYPES_HASH_PRIME; \
}
*/
// 用宏算出数组索引,如果索引一样说明extern一样,则覆盖,这里假设了不会存在html和lmth这样type
ngx_http_types_hash_key(key, default_types[i].exten);
ngx_test_null(t, ngx_push_array(&conf->types[key]),
NGX_CONF_ERROR);
t->exten.len = default_types[i].exten.len;
t->exten.data = default_types[i].exten.data;
t->type.len = default_types[i].type.len;
t->type.data = default_types[i].type.data;
}
}
}
if (conf->err_log == NULL) {
if (prev->err_log) {
conf->err_log = prev->err_log;
} else {
conf->err_log = cf->cycle->new_log;
}
}
if (conf->error_pages == NULL && prev->error_pages) {
conf->error_pages = prev->error_pages;
}
ngx_conf_merge_str_value(conf->default_type,
prev->default_type, "text/plain");
ngx_conf_merge_size_value(conf->client_max_body_size,
prev->client_max_body_size, 1 * 1024 * 1024);
ngx_conf_merge_size_value(conf->client_body_buffer_size,
prev->client_body_buffer_size,
(size_t) 2 * ngx_pagesize);
ngx_conf_merge_msec_value(conf->client_body_timeout,
prev->client_body_timeout, 60000);
ngx_conf_merge_value(conf->sendfile, prev->sendfile, 0);
ngx_conf_merge_value(conf->tcp_nopush, prev->tcp_nopush, 0);
ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000);
ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0);
ngx_conf_merge_size_value(conf->postpone_output, prev->postpone_output,
1460);
ngx_conf_merge_size_value(conf->limit_rate, prev->limit_rate, 0);
ngx_conf_merge_msec_value(conf->keepalive_timeout,
prev->keepalive_timeout, 75000);
ngx_conf_merge_sec_value(conf->keepalive_header,
prev->keepalive_header, 0);
ngx_conf_merge_msec_value(conf->lingering_time,
prev->lingering_time, 30000);
ngx_conf_merge_msec_value(conf->lingering_timeout,
prev->lingering_timeout, 5000);
ngx_conf_merge_value(conf->reset_timedout_connection,
prev->reset_timedout_connection, 0);
ngx_conf_merge_value(conf->msie_padding, prev->msie_padding, 1);
if (conf->open_files == NULL) {
conf->open_files = prev->open_files;
}
return NGX_CONF_OK;
}
其余模块就不一一列举,大致的逻辑都是一样的,就是子层的配置没有值则取父层的,父层也没有值则取默认的。
4 ngx_http_merge_locations
static char *ngx_http_merge_locations(ngx_conf_t *cf,
ngx_array_t *locations,
void **loc_conf,
ngx_http_module_t *module,
ngx_uint_t ctx_index)
{
char *rv;
ngx_uint_t i;
ngx_http_core_loc_conf_t **clcfp;
clcfp = /* (ngx_http_core_loc_conf_t **) */ locations->elts;
// 遍历父层的location
for (i = 0; i < locations->nelts; i++) {
/*
先合并server和非嵌套location层的配置
loc_conf[ctx_index]:server层的location配置,
clcfp[i]->loc_conf[ctx_index]:location层各模块的配置
*/
rv = module->merge_loc_conf(cf, loc_conf[ctx_index],
clcfp[i]->loc_conf[ctx_index]);
if (rv != NGX_CONF_OK) {
return rv;
}
/*
再合并嵌套location和非嵌套location的配置,
&clcfp[i]->locations:各模块关于嵌套的lcaotion,
clcfp[i]->loc_conf:各模块和关于非嵌套location的配置
*/
rv = ngx_http_merge_locations(cf, &clcfp[i]->locations,
clcfp[i]->loc_conf, module, ctx_index);
if (rv != NGX_CONF_OK) {
return rv;
}
}
return NGX_CONF_OK;
}
http模块初始化到这,内存视图差不多是下图所示。http、server、location都有类似的结构,一个配置最后存储在哪个位置取决于他在哪个上下文中。
这里没有描述