
1 定义ngx_http_discard_request_body 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request_body.cngx_int_tngx_http_discard_request_body(ngx_http_request_t*r){ssize_tsize;ngx_int_trc;ngx_event_t*rev;if(r!r-main||r-discard_body||r-request_body){returnNGX_OK;}#if(NGX_HTTP_V2)if(r-stream){r-stream-skip_data1;returnNGX_OK;}#endifif(ngx_http_test_expect(r)!NGX_OK){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}revr-connection-read;ngx_log_debug0(NGX_LOG_DEBUG_HTTP,rev-log,0,http set discard body);if(rev-timer_set){ngx_del_timer(rev);}if(r-headers_in.content_length_n0!r-headers_in.chunked){returnNGX_OK;}sizer-header_in-last-r-header_in-pos;if(size||r-headers_in.chunked){rcngx_http_discard_request_body_filter(r,r-header_in);if(rc!NGX_OK){returnrc;}if(r-headers_in.content_length_n0){returnNGX_OK;}}rcngx_http_read_discarded_request_body(r);if(rcNGX_OK){r-lingering_close0;returnNGX_OK;}if(rcNGX_HTTP_SPECIAL_RESPONSE){returnrc;}/* rc NGX_AGAIN */r-read_event_handlerngx_http_discarded_request_body_handler;if(ngx_handle_read_event(rev,0)!NGX_OK){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}r-count;r-discard_body1;returnNGX_OK;}ngx_http_discard_request_body 函数的作用是 安全地丢弃当前请求的请求体。 当服务器不需要处理请求体如即将返回错误、请求体过大被拒时 该函数会同步丢弃已读取的缓冲区数据 并异步注册读事件等待剩余数据 确保连接可以继续复用且不阻塞事件循环。2 详解1 函数签名ngx_int_tngx_http_discard_request_body(ngx_http_request_t*r)返回值 返回本函数执行结果的状态码 告知调用者执行情况参数 ngx_http_request_t *r 指向当前 HTTP 请求上下文结构体2 逻辑流程1 局部变量 2 无需丢弃 3 HTTP/2 处理 4 处理 Expect: 100-continue 头部 5 获取读事件并记录日志 6 移除读事件上的旧定时器 7 无请求体时的快速退出 8 计算请求头缓冲区中剩余的数据量 9 使用过滤器丢弃缓冲区中的请求体数据 10 启动从网络读取剩余数据 读取完成 返回 错误 需要等待1 局部变量{ssize_tsize;ngx_int_trc;ngx_event_t*rev;2 无需丢弃if(r!r-main||r-discard_body||r-request_body){returnNGX_OK;}快速退出条件无需丢弃若满足以下任一条件 直接返回 NGX_OK 表示当前无需执行丢弃操作。 r ! r-main 当前是子请求。 子请求与主请求共享同一个连接 丢弃请求体的操作应由主请求统一处理 子请求不单独操作。 r-discard_body 已经标记为丢弃请求体 说明该函数已被调用过 避免重复进入丢弃流程。 r-request_body 如果已经为请求体分配了结构体例如模块需要读取请求体 则不应粗暴丢弃应该由请求体读取模块正常处理。 意义 保证丢弃操作只在正确的时机由主请求发起 且不被重复触发或误伤需要正常读取请求体的场景。3 HTTP/2 处理#if(NGX_HTTP_V2)if(r-stream){r-stream-skip_data1;returnNGX_OK;}#endif4 处理 Expect: 100-continue 头部if(ngx_http_test_expect(r)!NGX_OK){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}调用 ngx_http_test_expect 检查请求是否包含 Expect: 100-continue 头部 并根据配置决定是否发送 100 Continue 响应或返回错误。 逻辑 如果函数返回非 NGX_OK说明处理 Expect 头失败例如无法发送响应 此时直接向上返回 NGX_HTTP_INTERNAL_SERVER_ERROR。 意义 必须在操作请求体之前处理 Expect 头符合 HTTP/1.1 协议要求。 如果服务器决定丢弃请求体也应先告知客户端无需继续发送请求体。5 获取读事件并记录日志revr-connection-read;ngx_log_debug0(NGX_LOG_DEBUG_HTTP,rev-log,0,http set discard body);rev r-connection-read 获取当前连接的读事件对象 后续需要操作该事件的定时器和回调。 ngx_log_debug0 输出调试日志记录当前开始丢弃请求体。 意义方便跟踪丢弃动作的触发点读事件对象是异步等待数据的基础6 移除读事件上的旧定时器if(rev-timer_set){ngx_del_timer(rev);}如果读事件当前设置了定时器例如在等待客户端发送请求体时启动的超时计时器则将其删除。 逻辑 旧的定时器可能是为正常读取请求体而设 现在要执行丢弃操作时间要求可能不同或无需超时 因此先清除后续可按需重新设置。 意义 避免旧的超时逻辑误触发确保事件调度状态干净。7 无请求体时的快速退出if(r-headers_in.content_length_n0!r-headers_in.chunked){returnNGX_OK;}条件content_length_n 0 且不是分块传输编码。 content_length_n 为 0 或 -1未设置表示没有消息体。 动作 直接返回 NGX_OK因为没有需要丢弃的数据。 意义快速路径避免不必要的后续处理。8 计算请求头缓冲区中剩余的数据量sizer-header_in-last-r-header_in-pos;r-header_in 是用于解析请求头的缓冲区。 当请求头解析完毕时可能已经有部分请求体数据被读入该缓冲区。 pos 是当前读取位置last 是缓冲区中有效数据的末尾。 差值 size 就是已读入但尚未被消费的请求体数据大小。 意义需要先丢弃这些已经在内存中的数据再处理网络上尚未到达的剩余部分。9 使用过滤器丢弃缓冲区中的请求体数据if(size||r-headers_in.chunked){rcngx_http_discard_request_body_filter(r,r-header_in);if(rc!NGX_OK){returnrc;}if(r-headers_in.content_length_n0){returnNGX_OK;}}条件 size || r-headers_in.chunked 缓冲区中有数据或者请求体是 chunked 编码 即使缓冲区当前为空也需要初始化 chunked 解析状态。 ngx_http_discard_request_body_filter 这是专门用于丢弃请求体数据的过滤器函数。 它会解析缓冲区中的字节如果是有固定 Content-Length 的请求体就递减 content_length_n 如果是 chunked 编码则解析 chunk 头并消耗数据。 错误处理 如果过滤器返回错误如 chunk 格式错误 则直接向上传递错误码。 检查是否已丢弃完毕 如果经过过滤后content_length_n 变为 0 说明整个请求体已经完全丢弃返回 NGX_OK。 意义 充分利用已读取到内存的数据 同步完成部分或全部丢弃工作减少后续异步等待。10 启动从网络读取剩余数据rcngx_http_read_discarded_request_body(r);调用该函数尝试从套接字读取尚未到达的请求体数据并丢弃。 它是非阻塞的可能返回 NGX_OK 所有剩余数据已读完例如客户端已发送完并关闭写端。 NGX_AGAIN 数据尚未到达需要等待读事件。 错误码或 HTTP 状态码 读取中发生错误或协议问题。 意义 真正执行网络 I/O 的丢弃步骤 与前面的内存丢弃配合逐步消耗整个请求体。if(rcNGX_OK){r-lingering_close0;returnNGX_OK;}如果同步读取完成关闭延迟关闭标志 所有剩余数据已成功丢弃没有错误也无需等待。 动作 将 r-lingering_close 置为 0。 该标志原本可能因为请求有 body 被设置为 1 指示在关闭连接前需要延迟读取以避免 RST。 现在 body 已完全丢弃不再需要延迟关闭 可以立即复用连接或干净关闭。 意义优化连接管理避免不必要的延迟关闭操作。if(rcNGX_HTTP_SPECIAL_RESPONSE){returnrc;}检查是否遇到需要立即返回的 HTTP 错误 如果 ngx_http_read_discarded_request_body 返回了一个 HTTP 状态码 例如 NGX_HTTP_BAD_REQUEST则直接将其返回给调用者。 逻辑 NGX_HTTP_SPECIAL_RESPONSE 是一个阈值 大于等于它的值表示可发送给客户端的最终响应码。 此时应终止丢弃并让上层返回错误。 意义确保在丢弃过程中遇到的协议错误能及时转换为相应的 HTTP 错误响应。/* rc NGX_AGAIN */r-read_event_handlerngx_http_discarded_request_body_handler;此时必然为 NGX_AGAIN需要异步等待 逻辑 执行到这里说明 rc 必定是 NGX_AGAIN 即数据尚未到达需要等待。 作用 将请求的读事件处理器设置为专门的 ngx_http_discarded_request_body_handler 函数。 当读事件再次触发有数据可读时事件模块会调用该函数继续丢弃操作。 意义实现异步非阻塞的请求体丢弃将控制权交还给事件循环worker 进程可处理其他连接。if(ngx_handle_read_event(rev,0)!NGX_OK){returnNGX_HTTP_INTERNAL_SERVER_ERROR;}注册读事件到事件驱动模块 作用 将读事件 rev 重新注册到事件模块如 epoll、kqueue 并携带标志 0通常意味着使用水平触发或默认模式。 失败处理 如果注册失败返回 NGX_HTTP_INTERNAL_SERVER_ERROR因为无法继续异步等待。 意义确保当客户端发送后续数据时内核能唤醒 Nginx从而继续执行丢弃处理。r-count;r-discard_body1;r-count 增加请求的引用计数。 因为现在有一个异步操作挂起的读事件回调引用该请求 在回调完成之前请求对象不能被释放。 引用计数防止提前销毁。 r-discard_body 1 标记该请求正在丢弃请求体。 这可以防止其他代码路径再次启动丢弃 或错误地尝试读取请求体。 意义正确管理请求的生命周期保证异步回调执行时请求仍然有效同时避免重复丢弃。returnNGX_OK;}返回 NGX_OK异步启动完成 通知调用者丢弃请求体的操作已经成功启动但可能尚未完成。 调用者可以继续执行后续清理或结束请求处理不必等待实际数据丢弃完毕。 发起异步操作后立即返回不阻塞当前处理流。 最终的丢弃完成和连接复用由事件驱动机制保证。