
1 定义ngx_http_process_request_header 函数 定义在 ./nginx-1.24.0/src/http/ngx_http_request.cngx_int_tngx_http_process_request_header(ngx_http_request_t*r){if(r-headers_in.server.len0ngx_http_set_virtual_server(r,r-headers_in.server)NGX_ERROR){returnNGX_ERROR;}if(r-headers_in.hostNULLr-http_versionNGX_HTTP_VERSION_10){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent HTTP/1.1 request without \Host\ header);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}if(r-headers_in.content_length){r-headers_in.content_length_nngx_atoof(r-headers_in.content_length-value.data,r-headers_in.content_length-value.len);if(r-headers_in.content_length_nNGX_ERROR){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent invalid \Content-Length\ header);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}}if(r-headers_in.transfer_encoding){if(r-http_versionNGX_HTTP_VERSION_11){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent HTTP/1.0 request with \Transfer-Encoding\ header);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}if(r-headers_in.transfer_encoding-value.len7ngx_strncasecmp(r-headers_in.transfer_encoding-value.data,(u_char*)chunked,7)0){if(r-headers_in.content_length){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent \Content-Length\ and \Transfer-Encoding\ headers at the same time);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}r-headers_in.chunked1;}else{ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent unknown \Transfer-Encoding\: \%V\,r-headers_in.transfer_encoding-value);ngx_http_finalize_request(r,NGX_HTTP_NOT_IMPLEMENTED);returnNGX_ERROR;}}if(r-headers_in.connection_typeNGX_HTTP_CONNECTION_KEEP_ALIVE){if(r-headers_in.keep_alive){r-headers_in.keep_alive_nngx_atotm(r-headers_in.keep_alive-value.data,r-headers_in.keep_alive-value.len);}}if(r-methodNGX_HTTP_CONNECT){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent CONNECT method);ngx_http_finalize_request(r,NGX_HTTP_NOT_ALLOWED);returnNGX_ERROR;}if(r-methodNGX_HTTP_TRACE){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent TRACE method);ngx_http_finalize_request(r,NGX_HTTP_NOT_ALLOWED);returnNGX_ERROR;}returnNGX_OK;}ngx_http_process_request_header 函数 是 Nginx 在解析完 HTTP 请求头后调用的 协议合规性校验与预处理函数。 对已解析的请求头进行合法性、兼容性和语义检查初始化内部标志 拒绝不支持或不合规的请求确保后续处理模块获得合法且可处理的请求。2 详解1 函数签名ngx_int_tngx_http_process_request_header(ngx_http_request_t*r)返回值 用于表示函数执行状态。参数 ngx_http_request_t *r 当前请求的请求结构体2 逻辑流程1 虚拟服务器匹配 2 Host 头检查 3 Content-Length 头处理 4 Transfer-Encoding 头处理 5 长连接 Keep-Alive 参数解析 6 禁止 CONNECT 方法 7 禁止 TRACE 方法 8 校验通过1 虚拟服务器匹配{if(r-headers_in.server.len0ngx_http_set_virtual_server(r,r-headers_in.server)NGX_ERROR){returnNGX_ERROR;}if 条件判断用于设置虚拟服务器。条件有两部分用 连接 r-headers_in.server.len 0 server 字段存放从 Host 头部拷贝的主机名字符串 若长度为0说明 Host 头不存在或为空还未进行虚拟主机匹配。 ngx_http_set_virtual_server(r, r-headers_in.server) NGX_ERROR 调用虚拟主机匹配函数传入请求和主机名即使长度为0也会尝试匹配默认服务器。 若返回 NGX_ERROR 说明匹配过程失败如内存不足等内部错误。 仅当尚未匹配过虚拟主机server 长度0时才调用匹配函数 若匹配过程出错整个请求无法继续直接进入错误处理。2 Host 头检查if(r-headers_in.hostNULLr-http_versionNGX_HTTP_VERSION_10){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent HTTP/1.1 request without \Host\ header);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}检查 HTTP/1.1及更高版本请求是否缺少 Host 头部。 r-headers_in.host NULL host 指针指向原始的 Host 头部结构 若为 NULL 表示请求中完全未出现该头部。 r-http_version NGX_HTTP_VERSION_10 HTTP 版本高于 1.0即 1.1 或 2.0 等。 HTTP/1.1 规范强制要求请求必须包含 Host 头缺失则为错误请求。3 Content-Length 头处理if(r-headers_in.content_length){r-headers_in.content_length_nngx_atoof(r-headers_in.content_length-value.data,r-headers_in.content_length-value.len);if(r-headers_in.content_length_nNGX_ERROR){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent invalid \Content-Length\ header);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}}检查是否存在 Content-Length 头部。 r-headers_in.content_length 是一个指针 若非 NULL 则表示客户端提供了该头部。将 Content-Length 头的字符串值转换成整型off_t文件偏移类型用于表示字节长度。 调用 ngx_atoof传入字符串数据指针和长度。转换结果存入 r-headers_in.content_length_n 后续模块使用该数值读取请求体或进行长度校验。 检查转换是否失败。ngx_atoof 在遇到非数字字符、溢出等非法情况时返回 NGX_ERROR 转换失败记录日志说明客户端发送了非法的 Content-Length 头 返回 400 Bad Request 错误并结束请求。4 Transfer-Encoding 头处理if(r-headers_in.transfer_encoding){if(r-http_versionNGX_HTTP_VERSION_11){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent HTTP/1.0 request with \Transfer-Encoding\ header);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}if(r-headers_in.transfer_encoding-value.len7ngx_strncasecmp(r-headers_in.transfer_encoding-value.data,(u_char*)chunked,7)0){if(r-headers_in.content_length){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent \Content-Length\ and \Transfer-Encoding\ headers at the same time);ngx_http_finalize_request(r,NGX_HTTP_BAD_REQUEST);returnNGX_ERROR;}r-headers_in.chunked1;}else{ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent unknown \Transfer-Encoding\: \%V\,r-headers_in.transfer_encoding-value);ngx_http_finalize_request(r,NGX_HTTP_NOT_IMPLEMENTED);returnNGX_ERROR;}}#1 检查是否存在 Transfer-Encoding 头部。 非 NULL 表示客户端声明了传输编码 若 HTTP 版本低于 1.1即 HTTP/1.0 或更早 规范不允许使用 Transfer-Encoding视为错误。检查 Transfer-Encoding 的值是否为 chunked不区分大小写。 条件 长度等于7正好是 chunked 的长度。 调用 ngx_strncasecmp 比较前7个字符是否与 chunked 相同忽略大小写。 若满足说明客户端使用分块传输编码这是 Nginx 唯一完整支持的传输编码。在 chunked 的情况下再次检查是否同时存在 Content-Length 头部。 HTTP 规范明确禁止二者同时出现因为会产生消息边界歧义。一切正常设置 chunked 标志为1。 后续请求体读取函数会根据该标志采用分块解析模式#2 若传输编码不是 chunked 进入 else 分支 返回 501 Not Implemented 表示服务器不支持该传输编码5 长连接 Keep-Alive 参数解析if(r-headers_in.connection_typeNGX_HTTP_CONNECTION_KEEP_ALIVE){if(r-headers_in.keep_alive){r-headers_in.keep_alive_nngx_atotm(r-headers_in.keep_alive-value.data,r-headers_in.keep_alive-value.len);}}检查 Connection 头是否表示保持长连接。 connection_type 字段在解析 Connection 头时设置 NGX_HTTP_CONNECTION_KEEP_ALIVE 代表请求希望使用持久连接 常见于 HTTP/1.0 的 Connection: keep-alive 或 HTTP/1.1 的默认行为。如果同时存在 Keep-Alive 头则尝试解析其值6 禁止 CONNECT 方法if(r-methodNGX_HTTP_CONNECT){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent CONNECT method);ngx_http_finalize_request(r,NGX_HTTP_NOT_ALLOWED);returnNGX_ERROR;}检查请求方法是否为 CONNECT。 r-method 是解析出的 HTTP 方法常量 NGX_HTTP_CONNECT 对应 CONNECT 方法。返回 405 Not Allowed 状态码 表示服务器默认不允许 CONNECT 方法7 禁止 TRACE 方法if(r-methodNGX_HTTP_TRACE){ngx_log_error(NGX_LOG_INFO,r-connection-log,0,client sent TRACE method);ngx_http_finalize_request(r,NGX_HTTP_NOT_ALLOWED);returnNGX_ERROR;}检查请求方法是否为 TRACE 同样返回 405 Not Allowed 因为 TRACE 方法易引发跨站追踪 (XST) 安全风险Nginx 默认禁用。8 校验通过returnNGX_OK;}所有校验和预处理均已通过返回 NGX_OK