nginx源码分析(8)——phase handler处理

        nginx将请求的处理过程划分为11个phase(阶段),相当于是对请求处理的一种抽象,便于定制处理过程。这个11个phase,分别是(定义在http/ngx_http_core_module.h):

typedef enum {
    NGX_HTTP_POST_READ_PHASE = 0,    /* 读取请求 */

    NGX_HTTP_SERVER_REWRITE_PHASE,   /* server级别的rewrite */

    NGX_HTTP_FIND_CONFIG_PHASE,	     /* 根据uri查找location */
    NGX_HTTP_REWRITE_PHASE,          /* localtion级别的rewrite */
    NGX_HTTP_POST_REWRITE_PHASE,     /* server、location级别的rewrite都是在这个phase进行收尾工作的 */

    NGX_HTTP_PREACCESS_PHASE,        /* 粗粒度的access */

    NGX_HTTP_ACCESS_PHASE,           /* 细粒度的access,比如权限验证、存取控制 */
    NGX_HTTP_POST_ACCESS_PHASE,	     /* 根据上述两个phase得到access code进行操作 */

    NGX_HTTP_TRY_FILES_PHASE,        /* 实现try_files指令 */
    NGX_HTTP_CONTENT_PHASE,          /* 生成http响应 */

    NGX_HTTP_LOG_PHASE               /* log模块 */
} ngx_http_phases;
        这些phase按照先后顺序执行,只有在rewrite之后流程会重新跳转到NGX_HTTP_FIND_CONFIG_PHASE。其中,只有7个phase可以注册handler以定制处理过程,其他的只有一个固定的handler:

NGX_HTTP_POST_READ_PHASE   
NGX_HTTP_SERVER_REWRITE_PHASE,  
NGX_HTTP_REWRITE_PHASE,  
NGX_HTTP_PREACCESS_PHASE,  
NGX_HTTP_ACCESS_PHASE,  
NGX_HTTP_CONTENT_PHASE,  
NGX_HTTP_LOG_PHASE
        一般地,phase handler的注册都是在http模块的postconfiguration回调函数中,后面会看到为什么要在这个时间点注册。

1. 重要的数据结构

        1. ngx_http_phase_t

typedef struct {
    ngx_array_t                handlers;
} ngx_http_phase_t;

        ngx_http_core_main_conf_t的phases数组存放了所有的phase,其中每个元素是ngx_http_phase_t类型的,表示的就是对应的phase handler的数组。ngx_http_core_main_conf_t->phases数组主要用于handler的注册。

        2. ngx_http_phase_engine_t

typedef struct {
    /**
     * 所有phase handler的数组。
     */
    ngx_http_phase_handler_t  *handlers;

    /**
     * server rewrite阶段的handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标
     */
    ngx_uint_t                 server_rewrite_index;

    /**
     * rewrite阶段的handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标
     */
    ngx_uint_t                 location_rewrite_index;
} ngx_http_phase_engine_t;
        ngx_http_core_main_conf_t的phase_engine字段表示phase的执行引擎,它会把所有的phase handler组织成数组,元素是ngx_http_phase_handler_t。phase_engine会根据phases数组中注册的handler进行初始化。

        3. ngx_http_phase_handler_t
struct ngx_http_phase_handler_s {
    /* 执行校验,并调用handler函数,同一个phase的handler的checker相同 */
    ngx_http_phase_handler_pt  checker;
    /* handler函数指针 */
    ngx_http_handler_pt        handler;
    /*
     * 指向下一个phase的第一个handler在ngx_http_core_main_conf_t->phase_engine.handlers数组中的下标
     *
     */
    ngx_uint_t                 next;
};
        

2. phase handler初始化

        phase handler初始化是在http模块初始化函数ngx_http_block中完成的,摘录关键代码:
    /**
     * 初始化每个phase对应的handlers数组,以便在执行postconfiguration回调函数时,
     * 注册phase handler。
     * ngx_http_core_main_conf_t->phases数组存放所有的phase。
     */
    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;
    }


    for (m = 0; ngx_modules[m]; m++) {
        if (ngx_modules[m]->type != NGX_HTTP_MODULE) {
            continue;
        }

        module = ngx_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;


    /**
     * 根据各个phase的handlers数组初始化ngx_http_core_main_conf_t->phase_engine。
     * 在phase_engine中所有的handler存放在一个数组中。
     */
    if (ngx_http_init_phase_handlers(cf, cmcf) != NGX_OK) {
        return NGX_CONF_ERROR;
    }
        先调用ngx_http_init_phases为ngx_http_core_main_conf_t->phases分配空间,然后会调用所有http module的postconfiguration回调函数,最后再调用ngx_http_init_phase_handlers初始化ngx_http_core_main_conf_t->phase_engine。这就是为什么phase handler的注册只能在postconfiguration回调函数中,因为只有在它调用前phases才会分配空间。ngx_http_init_phases函数很简单,就是一堆ngx_array_t的初始化,下面看一下ngx_http_init_phase_handlers。
1. ngx_http_init_phase_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;
    /* ngx_http_rewrite在http module的postconfiguration回调函数中添加REWRITE阶段的处理函数 */
    use_rewrite = cmcf->phases[NGX_HTTP_REWRITE_PHASE].handlers.nelts ? 1 : 0;
    /* ngx_http_access在http module的postconfiguration回调函数中添加ACCESS阶段的处理函数 */
    use_access = cmcf->phases[NGX_HTTP_ACCESS_PHASE].handlers.nelts ? 1 : 0;

    /* 计算handler数组的大小 */
    n = use_rewrite + use_access + cmcf->try_files + 1 /* find config phase */;

    /* 对所有handlers计数 */
    for (i = 0; i < NGX_HTTP_LOG_PHASE; i++) {
        n += cmcf->phases[i].handlers.nelts;
    }

    /* 为handler数组分配内存 */
    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;

    /* 下一个phase的第一个handler的索引 */
    n = 0;

    /*
     * 初始化phase handler,保存checker和next字段
     * continue的都是不能添加handler的phase
     */
    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) {
            	/* 设置server rewrite对应的handler的开始下标 */
                cmcf->phase_engine.server_rewrite_index = n;
            }
            checker = ngx_http_core_rewrite_phase;

            break;

        case NGX_HTTP_FIND_CONFIG_PHASE:
        	/* find config对应的handler的下标,后面post rewrite的handler设置需要用到 */
            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) {
            	/* 设置location rewrite的handler的开始下标 */
                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;
                /**
                 * 这里将post rewrite的next设置为find config的handler对应下标。
                 * 因为在location rewrite之后,需要重新匹配location,所以需要再次
                 * 进入这个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;
        }

        /* 跳过本phase所有handler,也就指向了下一个phase的第一个handler */
        n += cmcf->phases[i].handlers.nelts;

        /* 遍历初始化同一个phase上的handler */
        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;
}

        具体可以参见注释。大致原理就是将所有的phase handler以ngx_http_phase_handler_t->next组织成handler链表,处理请求时遍历这个链表。handler处理函数ngx_http_phase_handler_t->handler的调用是在checker中完成的,不同的phase具有不同的checker,但是同一个phase的checker相同。调用完这个函数,phase handler的初始化就完成了,下面看一下handler的调用。

3. phase handler调用

        在 请求处理一文中介绍了在处理的最后一步就是调用ngx_http_core_run_phases跑一遍所有的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;

    /* 遍历phase上注册的所有handler,这里是以r->phase_handler为索引组成的链表 */
    while (ph[r->phase_handler].checker) {

        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);

        /* 如果一个checker返回ok,则后面的handler不会被调用 */
        if (rc == NGX_OK) {
            return;
        }
    }
}
        ngx_http_core_run_phases会遍历所有的phase,然后调用它的checker进行处理,phase处理过程中的错误处理,校验等都是在checker中完成的,不同phase的checker的逻辑是不同,但是返回值的意义是相同的,如果checker的返回值时NGX_OK表示请求处理完毕,否则会进入下一个handler继续处理。接下来看一下phase的checker。

4. phase handler的checker

        由于checker的返回值决定了是否执行下一个handler,而且handler的返回值又决定了checker的返回值,所以在编写phase handler时,要特别注意返回值。

1. ngx_http_core_generic_phase

        这个checker用于处理post read和preaccess两个phase。它的作用很简单,就是根据handler的返回值决定继续这个phase的handler的处理,还是调用下一个phase的handler。它的返回值分为四种:
        NGX_OK:本phase处理完毕,可以继续执行下一个phase的handler,返回NGX_AGAIN。
        NGX_DECLINED:handler由于某种原因执行失败,但不影响本phase其他handler的执行,所以继续执行本phase的其他handler,返回NGX_AGAIN。
        NGX_AGAIN或者NGX_DONE:请求处理完毕,返回NGX_OK。
        NGX_ERROR或其他错误:终结请求的处理,释放相关资源。
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);

    rc = ph->handler(r);

    /* phase处理完毕,将r->phase_handler指向下一个phase的第一个handler */
    if (rc == NGX_OK) {
        r->phase_handler = ph->next;
        return NGX_AGAIN;
    }

    /* 继续处理本phase。handler因为某种原因没有执行,继续执行其他的handler */
    if (rc == NGX_DECLINED) {
        r->phase_handler++;
        return NGX_AGAIN;
    }

    /* 整个请求处理完毕 */
    if (rc == NGX_AGAIN || rc == NGX_DONE) {
        return NGX_OK;
    }

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

    ngx_http_finalize_request(r, rc);

    return NGX_OK;
}

2. ngx_http_core_find_config_phase

        这是find config phase的checker,用于根据uri查找对应的location,nginx中location的处理是相当复杂的,这里关注于phase handler的处理流程。find config phase只有一个phase handler,并且它没有相应的handler回调函数,完成的只是根据uri匹配到location之后,将location的loc_conf赋值给request,并且根据loc_conf对request进行一些处理。所有的由静态字符串标识的location被称作static location,由正则表达式表示的location成为regex location。所有的static location被组织成二叉树,以便于查找。在static location匹配失败后,会进行regex location匹配。这个过程正好描述了nginx中location的匹配规则。
        find config的checker可能会被执行多次,当rewrite成功后,会修改uri参数,需要重新匹配location。这就是find_config_index存在的必要,它用于初始化post rewrite phase handler的next字段,当uri被修改后会重新跳至find config phase执行。
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;

    /* 根据uri查找location,先静态查找,再正则匹配 */
    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);

    /* 非内部请求访问内部location是非法的,所有与error处理类似 */
    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);

    /* 根据匹配的location设置request的属性 */
    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);

        (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) {
        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;
        }

        /*
         * we do not need to set the r->headers_out.location->hash and
         * r->headers_out.location->key fields
         */

        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_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;
    }

    /* 执行rewrite phase handler */
    r->phase_handler++;
    return NGX_AGAIN;
}

3. ngx_http_core_rewrite_phase

        用于处理server rewrite phase和rewrite phase。逻辑很简单就是执行响应的handler,因为phase handler执行流程的跳转是在post rewrite中完成的,所以这里只需要将r->phase_handler++顺序遍历其后的handler即可。
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);

    /* 继续处理本phase的handler */
    if (rc == 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);

    return NGX_OK;
}

4. ngx_http_core_post_rewrite_phase

        这是post rewrite phase的checker,用于对rewrite和server rewrite phase进行收尾工作。request中有两个字段与重写相关:
        uri_changed:uri是否被重写。
        uri_changes:uri被重写的次数,初始值为11,所以只能重写10次。
        server rewrite和rewrite的handler会修改这两个变量,实现重写。这个checker就是根据uri_changed判断是否进入find config phase,然后再根据uri_changes做一些校验。
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);

    /**
     * uri_changed标志位表示uri是否有被重写。
     * 如果没有的话,这里累加r->phase_handler,由于post rewrite只有一个handler,
     * 所以就会跳到下一个phase继续执行。
     */
    if (!r->uri_changed) {
        r->phase_handler++;
        return NGX_AGAIN;
    }

    /* uri被重写 */

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

    /* 校验是否被重写了多次,uri_changes初始值为11,所以最多可以重写10次 */
    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;
    }

    /* 
     * 在ngx_http_init_phase_handlers中,如果use_rewrite不为0,那么
     * post rewrite phase handler的next指向find config的phase handler。
     * 接下来会进入find config phase
     */
    r->phase_handler = ph->next;

    /* server rewrite有可能改变了server config,所以要对r->loc_conf重新赋值 */
    cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
    r->loc_conf = cscf->ctx->loc_conf;

    return NGX_AGAIN;
}

5. ngx_http_core_access_phase

        这是access phase的checker,逻辑和之前的checker差不多,但需要注意这个checker有自己特有的逻辑:
        satisfy:对应于satisfy指令,‘satisfy all’要满足所有的access handler,‘satisfy any’只需要满足任意一个access handler。
        access_code:access phase中只判断是否有权限,而处理是在post access phase中完成的。access handler中设置具体的access code,然后传递给post access handler,由它处理最终的响应结果。
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);

    /* 跳到本phase的下一个handler */
    if (rc == NGX_DECLINED) {
        r->phase_handler++;
        return NGX_AGAIN;
    }

    /* 请求处理完毕 */
    if (rc == NGX_AGAIN || rc == NGX_DONE) {
        return NGX_OK;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    /* 相当于satisfy all,就是必须满足所有条件,所以继续执行access handler */
    if (clcf->satisfy == NGX_HTTP_SATISFY_ALL) {

        if (rc == NGX_OK) {
            r->phase_handler++;
            return NGX_AGAIN;
        }

    /* 否则只要满足任意一个条件即可,所以执行下一个phase的第一个handler */
    } else {
        if (rc == NGX_OK) {
        	/* 对access_code清零,后面post access phase根据这个属性处理 */
            r->access_code = 0;

            if (r->headers_out.www_authenticate) {
                r->headers_out.www_authenticate->hash = 0;
            }

            r->phase_handler = ph->next;
            return NGX_AGAIN;
        }

        if (rc == NGX_HTTP_FORBIDDEN || rc == NGX_HTTP_UNAUTHORIZED) {
        	/* 设置access_code,如果多个handler校验不通过,则只记录最后一个 */
            r->access_code = rc;

            r->phase_handler++;
            return NGX_AGAIN;
        }
    }

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

    ngx_http_finalize_request(r, rc);
    return NGX_OK;
}

6. ngx_http_core_post_access_phase

        这个是post access phase的checker,用于对access phase做收尾处理。在ngx_http_init_phase_handlers中只有当use_access为1时这个phase才会有handler,也就是说只有在access phase注册了handler时这个phase才会添加到请求处理流程里。post access handler完成的工作很简单,就是根据access_code做些出。
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;

    /* 设置了access_code,说明没有权限,则终结请求 */
    if (access_code) {
        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;
    }

    /* 否则,跳到下一个handler */
    r->phase_handler++;
    return NGX_AGAIN;
}

7. ngx_http_core_content_phase

        这个checker处理content phase,也就是用于生成响应内容的,我们编写的模块大部分是在这个phase执行的。这个需要注意一点,如果location设置了handler(就是content handler),那么就只会执行这一个handler,而不会执行其他的。大部分content handler中会调用output filter产生输出。content handler的返回值只有等于NGX_DECLINED时才会执行接下来的handler,而如果是其他值则返回NGX_OK,结束请求的处理。
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;

    /*
     * 在find config phase中如果匹配到的location具有handler,则会赋值给r->content_handler。
     * 而这里可以看到,如果r->content_handler存在则只会执行这一个handler,然后返回。
     * 也就是说如果location设置了handler,则只会执行这一个content handler,不会执行其他的。
     */
    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_http_finalize_request(r, rc);
        return NGX_OK;
    }

    /* handler返回NGX_DECLINED会由接下来的content handler继续处理 */
    /* rc == NGX_DECLINED */

    ph++;

    /* 如果下一个handler的checker存在,则返回NGX_AGAIN,继续调用下一个handler */
    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;
}
        这一篇介绍请求处理,下一篇我们来看看响应内容是如何输出的。

你可能感兴趣的:(nginx源码分析(8)——phase handler处理)