-
Notifications
You must be signed in to change notification settings - Fork 1
http phase handler module
paulran edited this page Apr 21, 2016
·
2 revisions
ngx_module_t ngx_http_xxx_module = { ..., &ngx_http_xxx_module_ctx, ... };
ngx_http_module_t ngx_http_xxx_module_ctx = { ..., ngx_http_xxx_init, ... };
static ngx_int_t ngx_http_xxx_handler(ngx_http_request_t *r);
typedef enum {
NGX_HTTP_POST_READ_PHASE = 0,
NGX_HTTP_SERVER_REWRITE_PHASE, // ngx_http_core_rewrite_phase, ngx_http_rewrite_module and ngx_http_rewrite_handler
NGX_HTTP_FIND_CONFIG_PHASE, // ngx_http_core_find_config_phase
NGX_HTTP_REWRITE_PHASE, // ngx_http_core_rewrite_phase, ngx_http_rewrite_module and ngx_http_rewrite_handler
NGX_HTTP_POST_REWRITE_PHASE, // ngx_http_core_post_rewrite_phase
NGX_HTTP_PREACCESS_PHASE, // (ngx_http_limit_conn_module and ngx_http_limit_conn_handler) or (ngx_http_limit_req_module and ngx_http_limit_req_handler)
NGX_HTTP_ACCESS_PHASE, // ngx_http_core_access_phase, (ngx_http_access_module and ngx_http_access_handler) or (ngx_http_auth_basic_module and ngx_http_auth_basic_handler)
NGX_HTTP_POST_ACCESS_PHASE, // ngx_http_core_post_access_phase
NGX_HTTP_TRY_FILES_PHASE, // ngx_http_core_try_files_phase
NGX_HTTP_CONTENT_PHASE, // ngx_http_core_content_phase, (ngx_http_static_module and ngx_http_static_handler) or (ngx_http_index_module and ngx_http_index_handler) or (ngx_http_autoindex_module and ngx_http_autoindex_handler)
NGX_HTTP_LOG_PHASE // ngx_http_log_module and ngx_http_log_handler
} ngx_http_phases;
/* 注意 ngx_http_handler_pt 和 ngx_http_phase_handler_pt 的区别:前者为 handler,后者为 checker。
* 注意 ngx_http_phase_handler_t 和 ngx_http_phase_handler_pt 的区别:前者为 struct,后者为函数指针。
*/
typedef ngx_int_t (*ngx_http_handler_pt)(ngx_http_request_t *r);
typedef struct ngx_http_phase_handler_s ngx_http_phase_handler_t;
typedef ngx_int_t (*ngx_http_phase_handler_pt)(ngx_http_request_t *r,
ngx_http_phase_handler_t *ph);
struct ngx_http_phase_handler_s {
ngx_http_phase_handler_pt checker;
ngx_http_handler_pt handler;
ngx_uint_t next;
};
typedef struct {
ngx_http_phase_handler_t *handlers;
ngx_uint_t server_rewrite_index;
ngx_uint_t location_rewrite_index;
} ngx_http_phase_engine_t;
/* 每一个 phase 都对应有一个 ngx_http_phase_t,即表示一个 phase 可以有多个 handler。
*/
typedef struct {
ngx_array_t handlers; // 存储 ngx_http_handler_pt*
} ngx_http_phase_t;
static ngx_int_t ngx_http_xxx_init(ngx_conf_t *cf)
{
ngx_http_handler_pt *h;
ngx_http_core_main_conf_t *cmcf;
cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module);
/* 将 phase 与 handler 绑定:某个 http phase handler 是固定与一个或多个 phase 绑定,在这个 init 函数中写死。 */
h = ngx_array_push(&cmcf->phases[NGX_HTTP_XXX_PHASE].handlers); // ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
if (h == NULL) {
return NGX_ERROR;
}
*h = ngx_http_xxx_handler;
return NGX_OK;
}
ngx_int_t ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph); // default phase
ngx_int_t ngx_http_core_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_find_config_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_rewrite_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_post_access_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_try_files_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
ngx_int_t ngx_http_core_content_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph);
typedef struct {
... ...
ngx_http_phase_engine_t phase_engine;
... ...
ngx_http_phase_t phases[NGX_HTTP_LOG_PHASE + 1];
} ngx_http_core_main_conf_t;
/* init 调用顺序:先 http phase handler module 的 ngx_http_xxx_init,再调用 ngx_http_init_phase_handlers。
* ngx_http_core_main_conf_t *cmcf;
* cmcf->phase_engine.handlers, saving ngx_http_phase_handler_t *ph.
* cmcf->phases[i].handlers, ngx_array_t, saving ngx_http_handler_pt *h[], ph->handler = h[j].
*/
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 = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;
for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
n += cmcf->phases[i].handlers.nelts;
}
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++) {
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_TRY_FILES_PHASE:
if (cmcf->try_files) {
ph->checker = ngx_http_core_try_files_phase;
n++;
ph++;
}
continue;
case NGX_HTTP_CONTENT_PHASE:
checker = ngx_http_core_content_phase;
break;
default:
checker = ngx_http_core_generic_phase;
}
n += cmcf->phases[i].handlers.nelts;
/* 同一个 phase,cmcf->phases[i].handlers 可能有多个 ngx_http_handler_pt 。*/
for (j = cmcf->phases[i].handlers.nelts - 1; j >=0; j--) {
ph->checker = checker;
ph->handler = h[j];
ph->next = n;
ph++;
}
}
return NGX_OK;
}
初始化后的结果示例:
cmcf->phase_engine.handlers = {
/* ngx_http_phase_handler_pt checker, ngx_http_handler_pt handler, ngx_uint_t next */
/* 0 */ { ngx_http_core_rewrite_phase, ngx_http_rewrite_handler, 1 },
/* 1 */ { ngx_http_core_find_config_phase, 0, 0 },
/* 2 */ { ngx_http_core_rewrite_phase, ngx_http_rewrite_handler, 3 },
/* 3 */ { ngx_http_core_post_rewrite_phase, 0, 1 },
/* 4 */ { ngx_http_core_generic_phase, ngx_http_limit_req_handler, 6 },
/* 5 */ { ngx_http_core_generic_phase, ngx_http_limit_conn_handler, 6 },
/* 6 */ { ngx_http_core_access_phase, ngx_http_access_handler, 9 },
/* 7 */ { ngx_http_core_access_phase, ngx_http_auth_basic_handler, 9 },
/* 8 */ { ngx_http_core_post_access_phase, 0, 9 }
/* 9 */ { ngx_http_core_content_phase, ngx_http_index_handler, 12 },
/* 10 */ { ngx_http_core_content_phase, ngx_http_autoindex_handler, 12 },
/* 11 */ { ngx_http_core_content_phase, ngx_http_static_handler, 12 }
}
cmcf->phase_engine.server_rewrite_index = 0;
cmcf->phase_engine.location_rewrite_index = 2; // 在设置 ngx_http_request_t 的 phase_handler 的起始值时被使用
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;
}
}
}
/*****************************************************************************************/
// notes 1.
r->phase_handler, 为 ngx_int_t 型变量,值为 C 类型数组 cmcf->phase_engine.handlers 的下标索引。
// notes 2.
checker, 即 ngx_http_core_xxxx_phase() :
{
ph++; r->phase_handler++; return NGX_AGAIN; => xxx_phase()从小到大一步一步执行。
or
r->phase_handler = ph->next; return NGX_AGAIN;
or
return NGX_OK;
}
// notes 3.
&ph[r->phase_handler], 即 ngx_http_phase_handler_t *ph,为结构体指针。
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) {
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); // call the phase handler
if (rc != NGX_DECLINED) {
ngx_http_finalize_request(r, rc);
return NGX_OK;
}
/* rc == NGX_DECLINED */
ph++;
if (ph->checker) {
r->phase_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);
return NGX_OK;
}