【nginx流程分析之读取配置文件location模块】
继承上一篇看一下,location命令所在的地方.核心模块仍然是ngx_http_core_commands
然后看一下ngx_http_core_location 这个方法和变量。
变量
先看看location对应的结构体,如图
ngx_http_core_loc_conf_s
struct ngx_http_core_loc_conf_s {
ngx_str_t name; /* location name */
#if (NGX_PCRE)
ngx_http_regex_t *regex;
#endif
unsigned noname:1; /* "if () {}" block or limit_except */
unsigned lmt_excpt:1;
unsigned named:1;
unsigned exact_match:1;
unsigned noregex:1;
unsigned auto_redirect:1;
#if (NGX_HTTP_GZIP)
unsigned gzip_disable_msie6:2;
unsigned gzip_disable_degradation:2;
#endif
ngx_http_location_tree_node_t *static_locations;
#if (NGX_PCRE)
ngx_http_core_loc_conf_t **regex_locations;
#endif
/* pointer to the modules' loc_conf */
void **loc_conf;
uint32_t limit_except;
void **limit_except_loc_conf;
ngx_http_handler_pt handler;
/* location name length for inclusive location with inherited alias */
size_t alias;
ngx_str_t root; /* root, alias */
ngx_str_t post_action;
ngx_array_t *root_lengths;
ngx_array_t *root_values;
ngx_array_t *types;
ngx_hash_t types_hash;
ngx_str_t default_type;
off_t client_max_body_size; /* client_max_body_size */
off_t directio; /* directio */
off_t directio_alignment; /* directio_alignment */
size_t client_body_buffer_size; /* client_body_buffer_size */
size_t send_lowat; /* send_lowat */
size_t postpone_output; /* postpone_output */
size_t limit_rate; /* limit_rate */
size_t limit_rate_after; /* limit_rate_after */
size_t sendfile_max_chunk; /* sendfile_max_chunk */
size_t read_ahead; /* read_ahead */
size_t subrequest_output_buffer_size;
/* subrequest_output_buffer_size */
ngx_msec_t client_body_timeout; /* client_body_timeout */
ngx_msec_t send_timeout; /* send_timeout */
ngx_msec_t keepalive_timeout; /* keepalive_timeout */
ngx_msec_t lingering_time; /* lingering_time */
ngx_msec_t lingering_timeout; /* lingering_timeout */
ngx_msec_t resolver_timeout; /* resolver_timeout */
ngx_resolver_t *resolver; /* resolver */
time_t keepalive_header; /* keepalive_timeout */
ngx_uint_t keepalive_requests; /* keepalive_requests */
ngx_uint_t keepalive_disable; /* keepalive_disable */
ngx_uint_t satisfy; /* satisfy */
ngx_uint_t lingering_close; /* lingering_close */
ngx_uint_t if_modified_since; /* if_modified_since */
ngx_uint_t max_ranges; /* max_ranges */
ngx_uint_t client_body_in_file_only; /* client_body_in_file_only */
ngx_flag_t client_body_in_single_buffer;
/* client_body_in_singe_buffer */
ngx_flag_t internal; /* internal */
ngx_flag_t sendfile; /* sendfile */
ngx_flag_t aio; /* aio */
ngx_flag_t aio_write; /* aio_write */
ngx_flag_t tcp_nopush; /* tcp_nopush */
ngx_flag_t tcp_nodelay; /* tcp_nodelay */
ngx_flag_t reset_timedout_connection; /* reset_timedout_connection */
ngx_flag_t absolute_redirect; /* absolute_redirect */
ngx_flag_t server_name_in_redirect; /* server_name_in_redirect */
ngx_flag_t port_in_redirect; /* port_in_redirect */
ngx_flag_t msie_padding; /* msie_padding */
ngx_flag_t msie_refresh; /* msie_refresh */
ngx_flag_t log_not_found; /* log_not_found */
ngx_flag_t log_subrequest; /* log_subrequest */
ngx_flag_t recursive_error_pages; /* recursive_error_pages */
ngx_uint_t server_tokens; /* server_tokens */
ngx_flag_t chunked_transfer_encoding; /* chunked_transfer_encoding */
ngx_flag_t etag; /* etag */
#if (NGX_HTTP_GZIP)
ngx_flag_t gzip_vary; /* gzip_vary */
ngx_uint_t gzip_http_version; /* gzip_http_version */
ngx_uint_t gzip_proxied; /* gzip_proxied */
#if (NGX_PCRE)
ngx_array_t *gzip_disable; /* gzip_disable */
#endif
#endif
#if (NGX_THREADS || NGX_COMPAT)
ngx_thread_pool_t *thread_pool;
ngx_http_complex_value_t *thread_pool_value;
#endif
#if (NGX_HAVE_OPENAT)
ngx_uint_t disable_symlinks; /* disable_symlinks */
ngx_http_complex_value_t *disable_symlinks_from;
#endif
ngx_array_t *error_pages; /* error_page */
ngx_path_t *client_body_temp_path; /* client_body_temp_path */
ngx_open_file_cache_t *open_file_cache;
time_t open_file_cache_valid;
ngx_uint_t open_file_cache_min_uses;
ngx_flag_t open_file_cache_errors;
ngx_flag_t open_file_cache_events;
ngx_log_t *error_log;
ngx_uint_t types_hash_max_size;
ngx_uint_t types_hash_bucket_size;
ngx_queue_t *locations;
#if 0
ngx_http_core_loc_conf_t *prev_location;
#endif
};
流程分析
看一下location对应的解析命令的地方:
可以看出来分析location具体的方法是ngx_http_core_location,然后就是分析一下ngx_http_core_location的具体的方法了。
static char *
ngx_http_core_location(ngx_conf_t *cf, ngx_command_t *cmd, void *dummy)
{
char *rv;
u_char *mod;
size_t len;
ngx_str_t *value, *name;
ngx_uint_t i;
ngx_conf_t save;
ngx_http_module_t *module;
ngx_http_conf_ctx_t *ctx, *pctx;
ngx_http_core_loc_conf_t *clcf, *pclcf;
//分配当前的location的上下文
ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_conf_ctx_t));
if (ctx == NULL) {
return NGX_CONF_ERROR;
}
//复制临时的上下文
pctx = cf->ctx;
ctx->main_conf = pctx->main_conf;
ctx->srv_conf = pctx->srv_conf;
//重新分配loc_conf
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
for (i = 0; cf->cycle->modules[i]; i++) {
if (cf->cycle->modules[i]->type != NGX_HTTP_MODULE) {
continue;
}
module = cf->cycle->modules[i]->ctx;
/*
调用每个模块的create_loc_conf方法
*/
if (module->create_loc_conf) {
ctx->loc_conf[cf->cycle->modules[i]->ctx_index] =
module->create_loc_conf(cf);
if (ctx->loc_conf[cf->cycle->modules[i]->ctx_index] == NULL) {
return NGX_CONF_ERROR;
}
}
}
//获取核心模块的loc_conf
clcf = ctx->loc_conf[ngx_http_core_module.ctx_index];
clcf->loc_conf = ctx->loc_conf;
value = cf->args->elts;
//
if (cf->args->nelts == 3) {
len = value[1].len;
mod = value[1].data;
name = &value[2];
if (len == 1 && mod[0] == '=') {
clcf->name = *name;
clcf->exact_match = 1;
} else if (len == 2 && mod[0] == '^' && mod[1] == '~') {
clcf->name = *name;
clcf->noregex = 1;
} else if (len == 1 && mod[0] == '~') {
if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else if (len == 2 && mod[0] == '~' && mod[1] == '*') {
if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"invalid location modifier \"%V\"", &value[1]);
return NGX_CONF_ERROR;
}
} else {
name = &value[1];
//name->data[0] = /
if (name->data[0] == '=') {
clcf->name.len = name->len - 1;
clcf->name.data = name->data + 1;
clcf->exact_match = 1;
} else if (name->data[0] == '^' && name->data[1] == '~') {
clcf->name.len = name->len - 2;
clcf->name.data = name->data + 2;
clcf->noregex = 1;
} else if (name->data[0] == '~') {
name->len--;
name->data++;
if (name->data[0] == '*') {
name->len--;
name->data++;
if (ngx_http_core_regex_location(cf, clcf, name, 1) != NGX_OK) {
return NGX_CONF_ERROR;
}
} else {
if (ngx_http_core_regex_location(cf, clcf, name, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
} else {
clcf->name = *name;
if (name->data[0] == '@') {
clcf->named = 1;
}
}
}
pclcf = pctx->loc_conf[ngx_http_core_module.ctx_index];
// printf("ngx_http_core_location cmd_type:%lu name:%s\n",cf->cmd_type,name->data);
if (cf->cmd_type == NGX_HTTP_LOC_CONF) {
/* nested location */
#if 0
clcf->prev_location = pclcf;
#endif
if (pclcf->exact_match) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" cannot be inside "
"the exact location \"%V\"",
&clcf->name, &pclcf->name);
return NGX_CONF_ERROR;
}
if (pclcf->named) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" cannot be inside "
"the named location \"%V\"",
&clcf->name, &pclcf->name);
return NGX_CONF_ERROR;
}
if (clcf->named) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"named location \"%V\" can be "
"on the server level only",
&clcf->name);
return NGX_CONF_ERROR;
}
len = pclcf->name.len;
#if (NGX_PCRE)
if (clcf->regex == NULL
&& ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#else
if (ngx_filename_cmp(clcf->name.data, pclcf->name.data, len) != 0)
#endif
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"location \"%V\" is outside location \"%V\"",
&clcf->name, &pclcf->name);
return NGX_CONF_ERROR;
}
}
//添加的server的loc_conf的locations
if (ngx_http_add_location(cf, &pclcf->locations, clcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
save = *cf;
cf->ctx = ctx;
cf->cmd_type = NGX_HTTP_LOC_CONF;
//继续解析 剩下的配置
//root 和 index
rv = ngx_conf_parse(cf, NULL);
//进行还原
*cf = save;
return rv;
}
然后接下来就是 root 和 index对应的命令了
root
这个命令仍然是在ngx_http_core_module中,然后对应的解析是
然后看一下ngx_http_core_root这个方法。
static char *
ngx_http_core_root(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_core_loc_conf_t *clcf = conf;
ngx_str_t *value;
ngx_int_t alias;
ngx_uint_t n;
ngx_http_script_compile_t sc;
//alias 为 0
alias = (cmd->name.len == sizeof("alias") - 1) ? 1 : 0;
//clcf->root.data 为 null
if (clcf->root.data) {
if ((clcf->alias != 0) == alias) {
return "is duplicate";
}
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"\"%V\" directive is duplicate, "
"\"%s\" directive was specified earlier",
&cmd->name, clcf->alias ? "alias" : "root");
return NGX_CONF_ERROR;
}
if (clcf->named && alias) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the \"alias\" directive cannot be used "
"inside the named location");
return NGX_CONF_ERROR;
}
//value 为html
value = cf->args->elts;
if (ngx_strstr(value[1].data, "$document_root")
|| ngx_strstr(value[1].data, "${document_root}"))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the $document_root variable cannot be used "
"in the \"%V\" directive",
&cmd->name);
return NGX_CONF_ERROR;
}
if (ngx_strstr(value[1].data, "$realpath_root")
|| ngx_strstr(value[1].data, "${realpath_root}"))
{
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"the $realpath_root variable cannot be used "
"in the \"%V\" directive",
&cmd->name);
return NGX_CONF_ERROR;
}
clcf->alias = alias ? clcf->name.len : 0;
clcf->root = value[1];
if (!alias && clcf->root.len > 0
&& clcf->root.data[clcf->root.len - 1] == '/')
{
clcf->root.len--;
}
//clcf->root.data[0] = h
if (clcf->root.data[0] != '$') {
//将clcf->root 从html更改为/usr/local/nginx/html
if (ngx_conf_full_name(cf->cycle, &clcf->root, 0) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
n = ngx_http_script_variables_count(&clcf->root);
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.variables = n;
#if (NGX_PCRE)
if (alias && clcf->regex) {
clcf->alias = NGX_MAX_SIZE_T_VALUE;
n = 1;
}
#endif
// printf("ngx_http_core_root value[1]:%s clcf->root:%s n:%lu\n",value[1].data,clcf->root.data,n);
//n 为0跳过
if (n) {
sc.cf = cf;
sc.source = &clcf->root;
sc.lengths = &clcf->root_lengths;
sc.values = &clcf->root_values;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}
index
还是一样看一下index命令对应的具体分析.
这一次index对应的模块不再是 ngx_http_core_module 而是 ngx_http_index_module,然后命令对应的方法是ngx_http_index_set_index。
然后看一下具体的代码分析:
static char *
ngx_http_index_set_index(ngx_conf_t *cf, ngx_command_t *cmd, void *conf)
{
ngx_http_index_loc_conf_t *ilcf = conf;
ngx_str_t *value;
ngx_uint_t i, n;
ngx_http_index_t *index;
ngx_http_script_compile_t sc;
//判断是否初始化了indices
if (ilcf->indices == NULL) {
ilcf->indices = ngx_array_create(cf->pool, 2, sizeof(ngx_http_index_t));
if (ilcf->indices == NULL) {
return NGX_CONF_ERROR;
}
}
//获取变量的值
value = cf->args->elts;
//value.data 分别是 index.html 和 index.htm
for (i = 1; i < cf->args->nelts; i++) {
if (value[i].data[0] == '/' && i != cf->args->nelts - 1) {
ngx_conf_log_error(NGX_LOG_WARN, cf, 0,
"only the last index in \"index\" directive "
"should be absolute");
}
if (value[i].len == 0) {
ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
"index \"%V\" in \"index\" directive is invalid",
&value[1]);
return NGX_CONF_ERROR;
}
//从indices的数组中读取
index = ngx_array_push(ilcf->indices);
if (index == NULL) {
return NGX_CONF_ERROR;
}
index->name.len = value[i].len;
index->name.data = value[i].data;
index->lengths = NULL;
index->values = NULL;
//没有设置变量因此 n=0
n = ngx_http_script_variables_count(&value[i]);
if (n == 0) {
if (ilcf->max_index_len < index->name.len) {
ilcf->max_index_len = index->name.len;
}
if (index->name.data[0] == '/') {
continue;
}
/* include the terminating '\0' to the length to use ngx_memcpy() */
index->name.len++;
continue;
}
ngx_memzero(&sc, sizeof(ngx_http_script_compile_t));
sc.cf = cf;
sc.source = &value[i];
sc.lengths = &index->lengths;
sc.values = &index->values;
sc.variables = n;
sc.complete_lengths = 1;
sc.complete_values = 1;
if (ngx_http_script_compile(&sc) != NGX_OK) {
return NGX_CONF_ERROR;
}
}
return NGX_CONF_OK;
}