nginx phase_handler

nginx对于一个请求的处理分了很多个phase,我们可以根据自己的需求添加模块到期望的phase

phase相关的所有函数都是保存在cmcf的phase_engine.handlers里面的,所有r都会使用



nginx的phase有:
typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,

    NGX_HTTP_SERVER_REWRITE_PHASE,

    NGX_HTTP_FIND_CONFIG_PHASE,

    NGX_HTTP_REWRITE_PHASE,
    NGX_HTTP_POST_REWRITE_PHASE,
    NGX_HTTP_PREACCESS_PHASE,
    NGX_HTTP_ACCESS_PHASE,
    NGX_HTTP_POST_ACCESS_PHASE,
    NGX_HTTP_TRY_FILES_PHASE,
    NGX_HTTP_CONTENT_PHASE,
    NGX_HTTP_LOG_PHASE
} ngx_http_phases;


在http的处理函数 ngx_http_block里面,
会有如下代码:
if (ngx_http_init_phases(cf, cmcf) != NGX_OK) 
{
        return NGX_CONF_ERROR;
}
if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK)
{
        return NGX_CONF_ERROR;
}
ngx_http_init_phases函数的执行流程为:
该函数主要是对cmcf->phases[各个phase].handlers申请空间
if (ngx_array_init(&cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers,
                       cf->pool, 1, sizeof(ngx_http_handler_pt))
        != NGX_OK)
    {
        return NGX_ERROR;
    }


中间会调用每个模块的postconfiguration,该函数会把当前模块的处理函数加入到对应的
cmcf->phases[NGX_HTTP_POST_READ_PHASE].handlers里面
每个handler是一个ngx_array_t类型,里面的elts是ngx_http_handler_pt类型


比如:
h = ngx_array_push(&cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers);
*h = ngx_http_auth_request_with_args_handler;


ngx_http_init_phase_handlers函数执行流程为:
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;
接下来遍历所有的phase,然后把里面包含的函数个数加起来,
但是n初始化方式为:n = use_rewrite + use_access + cmcf->try_files + 1,为什么会多几个?暂时还没有想明白


分配n个sizeof(ngx_http_phase_handler_t)空间+1个


然后  cmcf->phase_engine.handlers = ph;
n=0;
除了下面列举的phase,其它的任何phase
checker设置为: checker = ngx_http_core_generic_phase;
n保存为当前phase的函数个数
接下来遍历NGX_HTTP_POST_READ_PHASE的elts,对于每个ph(cmcf->phase_engine.handlers)赋值;
ph->checker设置为ngx_http_core_generic_phase
ph->handler = h[j]; 当前ph的handler设置为当前phase的第j个函数
ph->next = n;每个ph都保存着下一个phase的开始地址,这样可以在每个phase的任何一个函数都可以调到下一个phase
ph++,调到下一个ph


如果是NGX_HTTP_SERVER_REWRITE_PHASE,
会把cmcf->phase_engine.server_rewrite_index 设置为 n,n即为前面phase所有的函数个数之和
checker = ngx_http_core_rewrite_phase;
接下来更新n,之前的phase里面的函数加上当前phase的函数个数


如果是NGX_HTTP_FIND_CONFIG_PHASE
find_config_index = n;
ph->checker = ngx_http_core_find_config_phase;
n++;
ph++;
只会对当前checker进行赋值,然后把n++,ph++


如果是NGX_HTTP_REWRITE_PHASE
会把cmcf->phase_engine.location_rewrite_index = n,对cmcf->phase_engine.location_rewrite_index进行赋值
把checker设置为ngx_http_core_rewrite_phase
接下来把当前phase的所有所有函数都加到ph里面
ph->checker赋值为当前设置的checker,ph->checker = checker;
ph->handler = h[j];
ph->next = n;
ph++;


如果是NGX_HTTP_POST_REWRITE_PHASE
if (use_rewrite) {  //判断在NGX_HTTP_REWRITE_PHASEphase里面有无函数
                ph->checker = ngx_http_core_post_rewrite_phase;
                ph->next = find_config_index;//下一个phase会到NGX_HTTP_FIND_CONFIG_PHASE
                n++;
                ph++;
            }


如果是NGX_HTTP_ACCESS_PHASE
 checker = ngx_http_core_access_phase;

 n++;  //n++ 为什么?暂时还没有想明白

接下来相同的操作把当前phase里面的函数加到ph链表里面


如果是NGX_HTTP_POST_ACCESS_PHASE

   if (use_access) {//查看access有无处理函数
                ph->checker = ngx_http_core_post_access_phase;
                ph->next = n;
                ph++;
            }

这个总体是跳过access阶段


如果是 NGX_HTTP_TRY_FILES_PHASE:
            if (cmcf->try_files) {//try_files是个命令
                ph->checker = ngx_http_core_try_files_phase;
                n++;
                ph++;

            }

如果是NGX_HTTP_CONTENT_PHASE

checker = ngx_http_core_content_phase;

把当前phase的函数都加入到ph中



上面是对cmcf->phase_engine.handlers结构的赋值,是一块连续的内存。

那如何调用呢?


在ngx_http_handler函数中

r->write_event_handler = ngx_http_core_run_phases;
ngx_http_core_run_phases(r);

ngx_http_core_run_phases函数的执行流程为:

 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
    ph = cmcf->phase_engine.handlers;  //获取所有phase的执行函数首地址
    while (ph[r->phase_handler].checker) {
        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]); //依次调用每个checker,r->phase_handler记录当前走到哪里了


        if (rc == NGX_OK) {
            return;
        }
    }


接下来逐个分析checker函数

NGX_HTTP_POST_READ_PHASE NGX_HTTP_PREACCESS_PHASE  NGX_HTTP_LOG_PHASE

ngx_http_core_generic_phase(ngx_http_request_t *r, ngx_http_phase_handler_t *ph)

{

rc = ph->handler(r); //依次调用每一个handler函数


    if (rc == NGX_OK) {                                                   NGX_OK会调到下一个phase
        r->phase_handler = ph->next;
        return NGX_AGAIN;
    }


    if (rc == NGX_DECLINED) {                                  NGX_DECLINED顺序执行
        r->phase_handler++;
        return NGX_AGAIN;
    }


    if (rc == NGX_AGAIN || rc == NGX_DONE) {                NGX_AGAIN  NGX_DONE返回NGX_OK,下次接着执行当前处理函数
        return NGX_OK;
    }


    /* rc == NGX_ERROR || rc == NGX_HTTP_...  */


    ngx_http_finalize_request(r, rc);

}


NGX_HTTP_SERVER_REWRITE_PHASE

ngx_http_core_rewrite_phase

 rc = ph->handler(r);


    if (rc == NGX_DECLINED) {                                                            NGX_DECLINED依次执行下一个处理函数
        r->phase_handler++;
        return NGX_AGAIN;
    }


    if (rc == NGX_DONE) {                                             下一次接着执行
        return NGX_OK;
    }


    /* NGX_OK, NGX_AGAIN, NGX_ERROR, NGX_HTTP_...  */


    ngx_http_finalize_request(r, rc);


NGX_HTTP_FIND_CONFIG_PHASE

该阶段只有一个处理函数,不能自己添加模块在该阶段 


NGX_HTTP_REWRITE_PHASE

    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);


    if (rc == NGX_DECLINED) {   NGX_DECLINED依次执行下一个函数
        r->phase_handler++;
        return NGX_AGAIN;
    }


    if (rc == NGX_DONE) {     NGX_DONE下次接着执行
        return NGX_OK;
    }


    /* NGX_OK, NGX_AGAIN, NGX_ERROR, NGX_HTTP_...  */   其它的返回状态码则会断开当前连接


    ngx_http_finalize_request(r, rc);


NGX_HTTP_POST_REWRITE_PHASE

 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) {   uri_changed为0,则会顺序执行下一个函数
        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) {
        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;  跳到NGX_HTTP_FIND_CONFIG_PHASE阶段


    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
    r->loc_conf = cscf->ctx->loc_conf;                      修改r->loc_conf为当前server的loc_conf


    return NGX_AGAIN;   //接下来会接着从NGX_HTTP_FIND_CONFIG_PHASE开始往下处理


NGX_HTTP_ACCESS_PHASE 该阶段首先把n++

ngx_int_t                  rc;
    ngx_http_core_loc_conf_t  *clcf;


    if (r != r->main) {
        r->phase_handler = ph->next;   //子请求不会再次进入access阶段,直接跳过该阶段
        return NGX_AGAIN;
    }


    ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                   "access phase: %ui", r->phase_handler);


    rc = ph->handler(r);


    if (rc == NGX_DECLINED) {                 NGX_DECLINED依次执行下一个函数
        r->phase_handler++;
        return NGX_AGAIN;                      接着再次执行
    }


    if (rc == NGX_AGAIN || rc == NGX_DONE) {       
        return NGX_OK;                           退出当前r的执行流程,等待下一次再次进入
    }


    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);


    if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {


        if (rc == NGX_OK) {                        如果是satisfyall,NGX_OK会把所有的当前phase的处理函数都遍历一遍
            r->phase_handler++;
            return NGX_AGAIN;
        }
} else {
        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;   在access阶段,只需要满足其中一个处理函数,则直接跳到下一个phase
            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++;                   如果是NGX_HTTP_FORBIDDEN,则会接着执行下一个函数,返回403内容是什么时候返回?
            return NGX_AGAIN;
        }
    }


    /* rc == NGX_ERROR || rc == NGX_HTTP_...  */


    ngx_http_finalize_request(r, rc);
    return NGX_OK;


NGX_HTTP_POST_ACCESS_PHASE (暂时没有接触到)

NGX_HTTP_TRY_FILES_PHASE(暂时没有接触到)

ngx_http_core_content_phase

 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);


    if (rc != NGX_DECLINED) {                          在该阶段,只有NGX_DECLINED才不会finalize当前请求
        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;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值