ngx_http_core_content_phase

src\http\ngx_http_core_module.c

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

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

ngx_http_core_content_phase 是 Nginx HTTP 核心模块中处理内容生成阶段(content phase)的关键函数。这个函数负责协调请求的内容生成过程,包括调用预定义的内容处理器(content handler)或按阶段顺序尝试不同的处理器。


函数签名

ngx_int_t
ngx_http_core_content_phase(ngx_http_request_t *r,
    ngx_http_phase_handler_t *ph)
  • r: 当前 HTTP 请求对象,包含请求的所有相关信息
  • ph: 当前阶段处理器对象,包含处理函数和检查器

变量声明

size_t     root;
ngx_int_t  rc;
ngx_str_t  path;
  • root: 用于存储路径根目录的长度
  • rc: 存储处理函数的返回码
  • 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;
}
  • 如果请求已经设置了content_handler(通常在location配置中指定),则直接调用该处理器
  • 设置写事件处理器为空处理器(ngx_http_request_empty_handler)
  • 调用ngx_http_finalize_request完成请求处理,传入内容处理器的返回值
  • 返回NGX_OK表示处理完成

调试日志

ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
               "content phase: %ui", r->phase_handler);
  • 记录调试日志,显示当前处于内容阶段,并输出阶段处理器索引

调用当前阶段处理器

rc = ph->handler(r);
  • 调用当前阶段处理器(ph->handler)处理请求
  • 将返回值存储在rc变量中

此时的 ph->handler 是
ngx_http_index_handler


处理非DECLINED返回值

if (rc != NGX_DECLINED) {
    ngx_http_finalize_request(r, rc);
    return NGX_OK;
}
  • 如果处理器返回值不是NGX_DECLINED(表示拒绝处理),则认为该处理器已经处理了请求
  • 调用ngx_http_finalize_request完成请求处理
  • 返回NGX_OK表示处理完成

处理DECLINED情况

/* rc == NGX_DECLINED */

ph++;

if (ph->checker) {
    r->phase_handler++;
    return NGX_AGAIN;
}
  • 如果处理器返回NGX_DECLINED,表示它拒绝处理当前请求
  • 移动到下一个阶段处理器(ph++)
  • 如果下一个处理器有效(有checker函数),则:
    • 递增请求的阶段处理器索引(r->phase_handler++)
    • 返回NGX_AGAIN让核心循环继续尝试下一个处理器

没有找到内容处理器的情况

处理目录请求(URI以/结尾)

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;
}
  • 如果URI以斜杠(/)结尾,表示这是一个目录请求
  • 尝试将URI映射到文件系统路径(用于错误日志)
  • 记录错误日志,显示目录索引被禁止
  • 返回403 Forbidden状态码终止请求

处理一般未找到情况

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;
  • 记录错误日志,表示没有找到合适的处理器
  • 返回404 Not Found状态码终止请求
  • 返回NGX_OK表示处理完成

总结

ngx_http_core_content_phase 函数是Nginx内容生成阶段的核心调度器,它的主要逻辑流程是:

  1. 首先检查是否有预定义的内容处理器,有则直接调用
  2. 否则按阶段处理器数组顺序尝试各个处理器
  3. 如果处理器返回非DECLINED,则完成请求处理
  4. 如果处理器返回DECLINED,则尝试下一个处理器
  5. 如果所有处理器都拒绝处理,则根据URI类型返回403或404错误

这个函数体现了Nginx的高度模块化设计,通过阶段处理器机制,不同的模块可以注册自己的内容处理器,而核心模块负责协调这些处理器的执行顺序和结果处理。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值