Nginx的http功能和模块使用广泛,那么Nginx的http框架是如何初始化的呢?http请求的11个处理阶段又是怎么设计的呢?
http框架初始化流程图

结合流程简图和代码描述总体流程
当配置文件nginx.conf配置了http{...}并被解析到时,http框架通过执行ngx_http_block函数开始初始化:
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 */
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;
/*初始化所有HTTP模块的ctx_index序号*/
ngx_http_max_module = ngx_count_modules(cf->cycle, NGX_HTTP_MODULE);
/*分配解析http{}块下main级别配置项时存放HTTP模块结构体指针的3个数组main_conf、srv_conf、loc_conf*/
ctx->main_conf = ngx_pcalloc(cf->pool,
sizeof(void *) * ngx_http_max_module);
if (ctx->main_conf == NULL) {
return NGX_CONF_ERROR;
}
ctx->srv_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->srv_conf == NULL) {
return NGX_CONF_ERROR;
}
ctx->loc_conf = ngx_pcalloc(cf->pool, sizeof(void *) * ngx_http_max_module);
if (ctx->loc_conf == NULL) {
return NGX_CONF_ERROR;
}
/*
* 处理http{}块内的main级别配置时,对每个HTTP模块,都会调用create_(main|srv|loc)_conf等3个方法
*/
for (m = 0; cf->cycle->modules[m]; m++) {
if (cf->cycle->modules[m]->type != NGX_HTTP_MODULE) {
continue; //跳过非http模块
}
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); //main级别
if (ctx->main_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_srv_conf) {
ctx->srv_conf[mi] = module->create_srv_conf(cf); //server级别
if (ctx->srv_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
if (module->create_loc_conf) {
ctx->loc_conf[mi] = module->create_loc_conf(cf); //location级别
if (ctx->loc_conf[mi] == NULL) {
return NGX_CONF_ERROR;
}
}
}
pcf = *cf;
cf->ctx = ctx;
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;
}
}
}
/* 解析http{} main配置 */
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;
}
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;
//调用所有HTTP模块的init_main_conf方法,保存main级别配置
if (module->init_main_conf) {
rv = module->init_main_conf(cf, ctx->main_conf[mi]);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
//合并ngx_modules[m]模块main、srv、loc配置
rv = ngx_http_merge_servers(cf, cmcf, module, mi);
if (rv != NGX_CONF_OK) {
goto failed;
}
}
/* 构造location组成的静态二叉平衡查找树 */
for (s = 0; s < cmcf->servers.nelts; s++) {
clcf = cscfp[s]->ctx->loc_conf[ngx_http_core_module.ctx_index];
//将ngx_http_core_loc_conf_t组成的双向链表按照location匹配字符串进行排序
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;
}
}
/* 初始化可添加处理方法的HTTP阶段的动态数组 */
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;
}
/* 调用所有HTTP模块的postconfiguration方法,使之可以介入HTTP请求处理阶段 */
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;
//根据各个HTTP模块介入的处理方法构造出phase_engine_handlers数组
if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
return NGX_CONF_ERROR;
}
//构造监听端口与server间的关联关系,设置新连接事件的回调方法
if (ngx_http_optimize_servers(cf, cmcf, cmcf->ports) != NGX_OK) {
return NGX_CONF_ERROR;
}
return NGX_CONF_OK;
failed:
*cf = pcf;
return rv;
}
初始化所有HTTP模块的ctx_index序号
- ctx_index表示模块在同类型模块中的索引,比如ngx_http_core_module是HTTP模块(NGX_HTTP_MODULE)的首个模块,那么该模块的ctx_index为0。
分配解析http{}块下main级别配置项时存放HTTP模块结构体指针的3个数组
- 分配main_conf数组用于保存各个HTTP模块在main级别可能创建的xx_main_conf_t结构体
- 分配srv_conf数组用于保存各个HTTP模块在main级别可能创建的xx_srv_conf_t结构体
- 分配loc_conf数组用于保存各个HTTP模块在main级别可能创建的xx_loc_conf_t结构体
- 另外,必须同时创建3个数组。因为对于HTTP模块来说,某个指令有可能同时出现在main、srv、loc级别。实际应用配置项时,具体以那个级别的配置项为准,需要合并处理。
依次调用所有HTTP模块的create_(main|srv|loc)_conf共3个方法
每个HTTP模块可以实现模块上下文ngx_http_module_t
的这3个回调方法,如果实现,则:
- 调用create_main_conf,分配每个HTTP模块main级别的xx_main_conf_t结构体内存,并对字段赋初始值
- 调用create_srv_conf,分配每个HTTP模块main级别的xx_srv_conf_t结构体内存,并对字段赋初始值
- 调用create_loc_conf,分配每个HTTP模块main级别的xx_loc_conf_t结构体内存,并对字段赋初始值
调用所有HTTP模块的preconfiguration方法
每个HTTP模块可以实现模块上下文ngx_http_module_t
的preconfiguration
回调方法,如果实现,则:
- 调用preconfiguration方法, 一般用于添加变量
解析http{}块下的所有main级别配置项
- 交由conf模块解析http{}块下的配置
- 特别的,如果内部碰到server{}块时,则会分配srv_conf、loc_conf数组分别用于保存各个HTTP模块在server级别可能创建的xx_srv_conf_t、xx_loc_conf_t结构体。然后调用create_srv_conf、create_loc_conf分配每个HTTP模块在server级别的xx_(srv|loc)_conf_t结构体内存,并对字段赋初始值
- 特别的,如果内部碰到location{}块时,则会分配loc_conf数组分别用于保存各个HTTP模块在location级别可能创建的xx_loc_conf_t结构体。然后调用create_loc_conf分配每个HTTP模块在location级别的xx_loc_conf_t结构体内存,并对字段赋初始值
- location{}下的配置解析完,则各个HTTP模块在location级别的xxx_loc_conf_t结构体赋值完成
- server{}下的配置解析完,则各个HTTP模块在server级别的xx_(srv|loc)_conf_t结构体赋值完成
- 特别的,如果内部碰到server{}块时,则会分配srv_conf、loc_conf数组分别用于保存各个HTTP模块在server级别可能创建的xx_srv_conf_t、xx_loc_conf_t结构体。然后调用create_srv_conf、create_loc_conf分配每个HTTP模块在server级别的xx_(srv|loc)_conf_t结构体内存,并对字段赋初始值
调用所有HTTP模块的init_main_conf方法
每个HTTP模块可以实现模块上下文ngx_http_module_t
的init_main_conf回调方法, 如果实现,则:
- 配置解析完成后,调用init_main_conf方法,最终确定并保存各个HTTP模块在main级别的xx_main_conf_t配置结构体
合并main、srv、loc级别下server、location相关的配置项
对每一server{}而言,每个HTTP模块可以实现模块上下文ngx_http_module_t
的merge_srv_conf和merge_loc_conf回调方法, 如果实现,则:
- 调用merge_srv_conf和merge_loc_conf方法,最终确定并保存各个HTTP模块在server级别的xx_(srv|loc)_conf_t配置结构体
对于每一个location{}而言,每个HTTP模块可以实现模块上下文ngx_http_module_t
的merge_loc_conf回调方法, 如果实现, 则:
- 调用merge_loc_conf方法,最终确定并保存各个HTTP模块在location级别的xx_loc_conf_t配置结构体
构造location组成的静态二叉平衡查找树
对于每一个server而言,
- 将ngx_http_core_loc_conf_t组成的双向链表按照location匹配字符串进行排序
- 根据已经排序过的的双向链表,构建静态的二叉查找树。这样处理请求时可以加速找到location
初始化可添加处理方法的HTTP阶段的动态数组
- http请求处理的11个阶段,分配数组,用于后续添加模块自定义的handler方法
调用所有HTTP模块的postconfiguration方法使之可以介入HTTP阶段
每个HTTP模块可以实现模块上下文ngx_http_module_t
的postconfiguration
方法,如果实现,则:
- 调用postconfiguration,将handler方法添加到上一步常见的某个阶段(哪个阶段由模块自行决定,但只有7个阶段可以介入)的数组中
根据各个HTTP模块介入的处理方法构造出phase_engine_handlers数组
- 根据前两步构造的的动态数组,调用
ngx_http_init_phase_handlers
函数构造出phase_engine_handlers数组 - 特别的,有四个阶段不允许介入或者介入无效,分别是:
NGX_HTTP_FIND_CONFIG_PHASE
、
NGX_HTTP_POST_REWRITE_PHASE
、NGX_HTTP_POST_ACCESS_PHASE
、
NGX_HTTP_PRECONTENT_PHASE
(旧的Nginx的try_files阶段) - 特别的,
NGX_HTTP_CONTENT_PHASE
阶段,除了常规的postconfiguration介入方式(这种方式影响所有的location)。另外可以直接以ngx_command_t指定location的handler方式介入,只对location有该指令的location生效 - 特别的, 记录http日志(最后一个阶段log)特殊处理,并不会出现在phase_engine_handlers数组中
构造server虚拟主机构成的支持通配符的散列表
ngx_http_server_names
将server虚拟主机和对应的ngx_http_core_srv_conf_t结构体指针哈希化关联起来,这样处理请求时可以快速匹配server
构造监听端口与server间的关联关系,并设置新连接事件的回调方法
- 将监听端口
ngx_http_conf_port_t
和addr地址ngx_http_conf_addr_t
关联 - 进一步,将
ngx_http_conf_addr_t
和server虚拟主机关联。该结构体有3个哈希表结构字段,
分别用于索引完全匹配的sever_name、通配符前置、通配符后置的server虚拟主机结构体ngx_http_core_srv_conf_t
结构体指针 - 设置新连接事件的回调方法:
ngx_http_init_connection
http请求的11个阶段
构造phase_engine_handlers数组
- ngx_http_init_phase_handlers函数在http初始化时调用
//根据各个HTTP模块介入的处理方法构造出phase_engine_handlers数组
static ngx_int_t
ngx_http_init_phase_handlers(ngx_conf_t *cf, ngx_http_core_main_conf_t *cmcf)
{
ngx_int_t j;
ngx_uint_t i, n;
ngx_uint_t find_config_index, use_rewrite, use_access;
ngx_http_handler_pt *h;
ngx_http_phase_handler_t *ph;
ngx_http_phase_handler_pt checker;
cmcf->phase_engine.server_rewrite_index = (ngx_uint_t) -1;
cmcf->phase_engine.location_rewrite_index = (ngx_uint_t) -1;
find_config_index = 0;
use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;
n = 1 /* find config phase */
+ use_rewrite /* post rewrite phase */
+ use_access; /* post access phase */
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { //注意:不包含NGX_HTTP_LOG_PHASE阶段,该阶段另行特殊处理
n += cmcf->phases[i].handlers.nelts; //累加计算总的HTTP阶段处理方法个数
}
ph = ngx_pcalloc(cf->pool,
n * sizeof(ngx_http_phase_handler_t) + sizeof(void *));
if (ph == NULL) {
return NGX_ERROR;
}
cmcf->phase_engine.handlers = ph;
n = 0;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) { //注意: 不包含NGX_HTTP_LOG_PHASE阶段
h = cmcf->phases[i].handlers.elts;
switch (i) {
case NGX_HTTP_SERVER_REWRITE_PHASE:
if (cmcf->phase_engine.server_rewrite_index == (ngx_uint_t) -1) {
cmcf->phase_engine.server_rewrite_index = n;
}
checker = ngx_http_core_rewrite_phase;
break;
case NGX_HTTP_FIND_CONFIG_PHASE:
find_config_index = n;
ph->checker = ngx_http_core_find_config_phase;
n++;
ph++;
continue;
case NGX_HTTP_REWRITE_PHASE:
if (cmcf->phase_engine.location_rewrite_index == (ngx_uint_t) -1) {
cmcf->phase_engine.location_rewrite_index = n;
}
checker = ngx_http_core_rewrite_phase;
break;
case NGX_HTTP_POST_REWRITE_PHASE:
if (use_rewrite) {
ph->checker = ngx_http_core_post_rewrite_phase;
ph->next = find_config_index;
n++;
ph++;
}
continue;
case NGX_HTTP_ACCESS_PHASE:
checker = ngx_http_core_access_phase;
n++;
break;
case NGX_HTTP_POST_ACCESS_PHASE:
if (use_access) {
ph->checker = ngx_http_core_post_access_phase;
ph->next = n;
ph++;
}
continue;
case NGX_HTTP_CONTENT_PHASE:
checker = ngx_http_core_content_phase;
break;
default: //NGX_HTTP_POST_READ_PHASE、NGX_HTTP_PREACCESS_PHASE、NGX_HTTP_PRECONTENT_PHASE
checker = ngx_http_core_generic_phase;
}
n += cmcf->phases[i].handlers.nelts; //跳过本阶段的所有handler, 也即下一阶段的首个handler
//注意:每个HTTP处理阶段中最后加入到handlers[]中的会首先添加到cmcf->phase_engine.handlers
for (j = cmcf->phases[i].handlers.nelts - 1; j >= 0; j--) {
ph->checker = checker;
ph->handler = h[j];
ph->next = n; //下一阶段的首个handler序号
ph++;
}
}
return NGX_OK;
}
checker方法
ngx_http_core_generic_phase
/*
* NGX_HTTP_(POST_READ | PREACCESS | PRECONTENT)_PHASE等阶段的checker方法
*/
ngx_int_t
ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc;
/*
* generic phase checker,
* used by the post read and pre-access phases
*/
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"generic phase: %ui", r->phase_handler);
//调用HTTP模块添加的handler处理方法(由各个HTTP模块的postconfiguration钩子函数添加)
rc = ph->handler(r);
if (rc == NGX_OK) {
r->phase_handler = ph->next; //rc为NGX_OK时,进入下一阶段就行处理, 当前阶段即使有其他处理方法也会跳过
return NGX_AGAIN;
}
if (rc == NGX_DECLINED) {
r->phase_handler++; //下一个处理方法,可能仍是当前阶段,也有可能是下一个阶段的首个处理方法
return NGX_AGAIN;
}
if (rc == NGX_AGAIN || rc == NGX_DONE) {
return NGX_OK; //不更改r->phase_handler的值,当前处理方法有机会再次被调用。但是必须把控制权交还event模块
}
/* rc == NGX_ERROR || rc == NGX_HTTP_... */
ngx_http_finalize_request(r, rc); //返回错误NGX_ERROR或者NGX_HTTP_开头的返回码,则结束请求
return NGX_OK;
}
ngx_http_core_rewrite_phase
/*
* NGX_HTTP_(SERVER_REWRITE | REWRITE)_PHASE等阶段的checker方法
*/
ngx_int_t
ngx_http_core_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"rewrite phase: %ui", r->phase_handler);
rc = ph->handler(r); //执行挂载的handler方法
if (rc == NGX_DECLINED) {
r->phase_handler++; //当前处理方法执行完毕,执行下一个处理方法
return NGX_AGAIN;
}
if (rc == NGX_DONE) {
return NGX_OK; //不更改r->phase_handler的值,当前处理方法有机会再次被调用。但是必须把控制权交还event模块
}
/* NGX_OK, NGX_AGAIN, NGX_ERROR, NGX_HTTP_... */
ngx_http_finalize_request(r, rc); //结束请求
return NGX_OK;
}
ngx_http_core_find_config_phase
/*
* 根据请求的URI寻找匹配的location表达式,不允许用户模块介入。即使介入也无效,因为入参ph未使用
*/
ngx_int_t
ngx_http_core_find_config_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
u_char *p;
size_t len;
ngx_int_t rc;
ngx_http_core_loc_conf_t *clcf;
r->content_handler = NULL;
r->uri_changed = 0;
rc = ngx_http_core_find_location(r);
if (rc == NGX_ERROR) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (!r->internal && clcf->internal) {
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND);
return NGX_OK;
}
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"using configuration \"%s%V\"",
(clcf->noname ? "*" : (clcf->exact_match ? "=" : "")),
&clcf->name);
ngx_http_update_location_config(r);
ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"http cl:%O max:%O",
r->headers_in.content_length_n, clcf->client_max_body_size);
if (r->headers_in.content_length_n != -1
&& !r->discard_body
&& clcf->client_max_body_size
&& clcf->client_max_body_size < r->headers_in.content_length_n)
{
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"client intended to send too large body: %O bytes",
r->headers_in.content_length_n);
r->expect_tested = 1;
(void) ngx_http_discard_request_body(r);
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_ENTITY_TOO_LARGE);
return NGX_OK;
}
if (rc == NGX_DONE) {
ngx_http_clear_location(r);
r->headers_out.location = ngx_list_push(&r->headers_out.headers);
if (r->headers_out.location == NULL) {
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
r->headers_out.location->hash = 1;
ngx_str_set(&r->headers_out.location->key, "Location");
if (r->args.len == 0) {
r->headers_out.location->value = clcf->name;
} else {
len = clcf->name.len + 1 + r->args.len;
p = ngx_pnalloc(r->pool, len);
if (p == NULL) {
ngx_http_clear_location(r);
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
r->headers_out.location->value.len = len;
r->headers_out.location->value.data = p;
p = ngx_cpymem(p, clcf->name.data, clcf->name.len);
*p++ = '?';
ngx_memcpy(p, r->args.data, r->args.len);
}
ngx_http_finalize_request(r, NGX_HTTP_MOVED_PERMANENTLY);
return NGX_OK;
}
r->phase_handler++; //下一阶段
return NGX_AGAIN;
}
ngx_http_core_post_rewrite_phase
/*
* NGX_HTTP_POST_REWRITE_PHASE阶段的checker方法
*/
ngx_int_t
ngx_http_core_post_rewrite_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
ngx_http_core_srv_conf_t *cscf;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"post rewrite phase: %ui", r->phase_handler);
if (!r->uri_changed) {
r->phase_handler++;
return NGX_AGAIN;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"uri changes: %d", r->uri_changes);
/*
* gcc before 3.3 compiles the broken code for
* if (r->uri_changes-- == 0)
* if the r->uri_changes is defined as
* unsigned uri_changes:4
*/
r->uri_changes--;
if (r->uri_changes == 0) { //url改写次数超限,结束请求
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"rewrite or internal redirection cycle "
"while processing \"%V\"", &r->uri);
ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
return NGX_OK;
}
r->phase_handler = ph->next;
cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
r->loc_conf = cscf->ctx->loc_conf;
return NGX_AGAIN;
}
ngx_http_core_access_phase
/*
* NGX_HTTP_ACCESS_PHASE阶段的checker方法
*/
ngx_int_t
ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)
{
ngx_int_t rc;
ngx_http_core_loc_conf_t *clcf;
if (r != r->main) { //子请求
r->phase_handler = ph->next; //跳到下一个阶段
return NGX_AGAIN;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"access phase: %ui", r->phase_handler);
rc = ph->handler(r); //执行模块挂载的handler方法
if (rc == NGX_DECLINED) {
r->phase_handler++; //下一个处理方法
return NGX_AGAIN;
}
if (rc == NGX_AGAIN || rc == NGX_DONE) {
return NGX_OK; //不更改r->phase_handler的值,当前处理方法有机会再次被调用。但是必须把控制权交还event模块
}
clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {
if (rc == NGX_OK) {
r->phase_handler++; //satisfy all, 则执行下一个handler方法
return NGX_AGAIN;
}
} else { //satisfy any
if (rc == NGX_OK) {
r->access_code = 0;
if (r->headers_out.www_authenticate) {
r->headers_out.www_authenticate->hash = 0;
}
r->phase_handler = ph->next; //satisfy any, 则跳到下一个阶段
return NGX_AGAIN;
}
if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) {
if (r->access_code != NGX_HTTP_UNAUTHORIZED) {
r->access_code = rc;
}
r->phase_handler++; //下一个handler方法
return NGX_AGAIN;
}
}
/* rc == NGX_ERROR || rc == NGX_HTTP_... */
ngx_http_finalize_request(r, rc); //结束请求
return NGX_OK;
}
ngx_http_core_post_access_phase
/*
* NGX_HTTP_POST_ACCESS_PHASE阶段的checker方法, 入参ph未使用,即不允许介入
*/
ngx_int_t
ngx_http_core_post_access_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
ngx_int_t access_code;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"post access phase: %ui", r->phase_handler);
access_code = r->access_code;
if (access_code) { //access_code非0,表明没有访问权限
if (access_code == NGX_HTTP_FORBIDDEN) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"access forbidden by rule");
}
r->access_code = 0;
ngx_http_finalize_request(r, access_code);
return NGX_OK;
}
r->phase_handler++;
return NGX_AGAIN;
}
ngx_http_core_content_phase
/*
* NGX_HTTP_CONTENT_PHASE阶段的checker方法
*/
ngx_int_t
ngx_http_core_content_phase(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph)
{
size_t root;
ngx_int_t rc;
ngx_str_t path;
if (r->content_handler) { //介入的特殊方式: 某location特有的handler方法, 不影响其他location
r->write_event_handler = ngx_http_request_empty_handler;
ngx_http_finalize_request(r, r->content_handler(r));
return NGX_OK;
}
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
"content phase: %ui", r->phase_handler);
rc = ph->handler(r); //执行postconfiguration钩子函数添加的handler方法
if (rc != NGX_DECLINED) {
ngx_http_finalize_request(r, rc);
return NGX_OK;
}
/* rc == NGX_DECLINED */
ph++;
if (ph->checker) {
r->phase_handler++; //下一个handler方法
return NGX_AGAIN;
}
/* no content handler was found */
if (r->uri.data[r->uri.len - 1] == '/') {
if (ngx_http_map_uri_to_path(r, &path, &root, 0) != NULL) {
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
"directory index of \"%s\" is forbidden", path.data);
}
ngx_http_finalize_request(r, NGX_HTTP_FORBIDDEN);
return NGX_OK;
}
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, "no handler found");
ngx_http_finalize_request(r, NGX_HTTP_NOT_FOUND); //404
return NGX_OK;
}
处理请求经过10个阶段
/*
* 10个阶段处理HTTP请求
*/
void
ngx_http_core_run_phases(ngx_http_request_t *r)
{
ngx_int_t rc;
ngx_http_phase_handler_t *ph;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
ph = cmcf->phase_engine.handlers;
while (ph[r->phase_handler].checker) {
rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
if (rc == NGX_OK) {
return;
}
}
}
记录http日志阶段特殊处理
/*
* 记录访问日志。log阶段的handler链并不是在ngx_http_core_run_phases函数中执行, 它只需在请求处理逻辑结束后才执行一次
*/
static void
ngx_http_log_request(ngx_http_request_t *r)
{
ngx_uint_t i, n;
ngx_http_handler_pt *log_handler;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
log_handler = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.elts;
n = cmcf->phases[NGX_HTTP_LOG_PHASE].handlers.nelts;
for (i = 0; i < n; i++) {
log_handler[i](r);
}
}