src\http\ngx_http_request.c
static void
ngx_http_process_request_line(ngx_event_t *rev)
{
ssize_t n;
ngx_int_t rc, rv;
ngx_str_t host;
ngx_connection_t *c;
ngx_http_request_t *r;
c = rev->data;
r = c->data;
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"http process request line");
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
rc = NGX_AGAIN;
for ( ;; ) {
if (rc == NGX_AGAIN) {
n = ngx_http_read_request_header(r);
if (n == NGX_AGAIN || n == NGX_ERROR) {
break;
}
}
rc = ngx_http_parse_request_line(r, r->header_in);
if (rc == NGX_OK) {
/* the request line has been parsed successfully */
r->request_line.len = r->request_end - r->request_start;
r->request_line.data = r->request_start;
r->request_length = r->header_in->pos - r->request_start;
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http request line: \"%V\"", &r->request_line);
r->method_name.len = r->method_end - r->request_start + 1;
r->method_name.data = r->request_line.data;
if (r->http_protocol.data) {
r->http_protocol.len = r->request_end - r->http_protocol.data;
}
if (ngx_http_process_request_uri(r) != NGX_OK) {
break;
}
if (r->schema_end) {
r->schema.len = r->schema_end - r->schema_start;
r->schema.data = r->schema_start;
}
if (r->host_end) {
host.len = r->host_end - r->host_start;
host.data = r->host_start;
rc = ngx_http_validate_host(&host, r->pool, 0);
if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent invalid host in request line");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
break;
}
if (rc == NGX_ERROR) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
break;
}
if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {
break;
}
r->headers_in.server = host;
}
if (r->http_version < NGX_HTTP_VERSION_10) {
if (r->headers_in.server.len == 0
&& ngx_http_set_virtual_server(r, &r->headers_in.server)
== NGX_ERROR)
{
break;
}
ngx_http_process_request(r);
break;
}
if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
break;
}
c->log->action = "reading client request headers";
rev->handler = ngx_http_process_request_headers;
ngx_http_process_request_headers(rev);
break;
}
if (rc != NGX_AGAIN) {
/* there was error while a request line parsing */
ngx_log_error(NGX_LOG_INFO, c->log, 0,
ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]);
if (rc == NGX_HTTP_PARSE_INVALID_VERSION) {
ngx_http_finalize_request(r, NGX_HTTP_VERSION_NOT_SUPPORTED);
} else {
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
}
break;
}
/* NGX_AGAIN: a request line parsing is still incomplete */
if (r->header_in->pos == r->header_in->end) {
rv = ngx_http_alloc_large_header_buffer(r, 1);
if (rv == NGX_ERROR) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
break;
}
if (rv == NGX_DECLINED) {
r->request_line.len = r->header_in->end - r->request_start;
r->request_line.data = r->request_start;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent too long URI");
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
break;
}
}
}
ngx_http_run_posted_requests(c);
}
这个函数是Nginx处理HTTP请求的第一阶段,负责解析客户端发来的请求行(request line)。
函数声明和变量定义
static void
ngx_http_process_request_line(ngx_event_t *rev)
{
ssize_t n;
ngx_int_t rc, rv;
ngx_str_t host;
ngx_connection_t *c;
ngx_http_request_t *r;
rev: 接收事件对象,表示有数据可读的事件n: 用于存储读取的字节数rc,rv: 各种操作的返回状态码host: 存储解析出的主机名c: 连接对象指针r: HTTP请求对象指针
获取连接和请求对象
c = rev->data;
r = c->data;
- 从事件对象获取连接对象
- 从连接对象获取HTTP请求对象
调试日志
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,
"http process request line");
- 记录调试日志,表示开始处理请求行
超时检查
if (rev->timedout) {
ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");
c->timedout = 1;
ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
- 检查是否发生超时
- 如果超时,记录错误日志,标记连接为超时状态
- 关闭请求并返回HTTP 408(请求超时)状态
此时 rev->timedout=0
主循环
rc = NGX_AGAIN;
for ( ;; ) {
- 初始化返回码为NGX_AGAIN(表示需要更多数据)
- 开始无限循环处理请求行
读取请求头数据
if (rc == NGX_AGAIN) {
n = ngx_http_read_request_header(r);
if (n == NGX_AGAIN || n == NGX_ERROR) {
break;
}
}
- 如果需要更多数据(NGX_AGAIN),则尝试读取请求头数据
- 如果读取失败(NGX_AGAIN需要再次尝试或NGX_ERROR错误),跳出循环
- ngx_http_read_request_header
解析请求行
rc = ngx_http_parse_request_line(r, r->header_in);
- 调用请求行解析函数,尝试解析HTTP请求行(如"GET / HTTP/1.1")
- ngx_http_parse_request_line
成功解析请求行
if (rc == NGX_OK) {
- 如果解析成功(返回NGX_OK),进入处理流程
设置请求行信息
r->request_line.len = r->request_end - r->request_start;
r->request_line.data = r->request_start;
r->request_length = r->header_in->pos - r->request_start;
- 计算并设置请求行的长度和数据指针
- 记录整个请求的长度
记录调试日志
ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
"http request line: \"%V\"", &r->request_line);
- 记录调试日志,输出完整的请求行
设置方法名
r->method_name.len = r->method_end - r->request_start + 1;
r->method_name.data = r->request_line.data;
- 设置HTTP方法(GET/POST等)的长度和数据指针
处理HTTP协议版本
if (r->http_protocol.data) {
r->http_protocol.len = r->request_end - r->http_protocol.data;
}
- 如果有HTTP协议信息,设置其长度
处理请求URI
if (ngx_http_process_request_uri(r) != NGX_OK) {
break;
}
- 处理请求URI,如果失败则跳出循环
- ngx_http_process_request_uri
处理schema(协议方案)
if (r->schema_end) {
r->schema.len = r->schema_end - r->schema_start;
r->schema.data = r->schema_start;
}
- 如果有schema(如http://或https://),设置其长度和数据指针
处理主机名
if (r->host_end) {
host.len = r->host_end - r->host_start;
host.data = r->host_start;
- 如果有主机名,设置其长度和数据指针
验证主机名
rc = ngx_http_validate_host(&host, r->pool, 0);
if (rc == NGX_DECLINED) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent invalid host in request line");
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
break;
}
if (rc == NGX_ERROR) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
break;
}
- 验证主机名是否合法
- 如果主机名不合法,返回400错误
- 如果验证过程出错,返回500错误
设置虚拟服务器
if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {
break;
}
r->headers_in.server = host;
}
- 根据主机名设置虚拟服务器配置
- 将主机名存入请求头
处理HTTP/0.9请求
if (r->http_version < NGX_HTTP_VERSION_10) {
if (r->headers_in.server.len == 0
&& ngx_http_set_virtual_server(r, &r->headers_in.server)
== NGX_ERROR)
{
break;
}
ngx_http_process_request(r);
break;
}
- 如果是HTTP/0.9请求(没有版本号)
- 如果没有主机头,尝试设置虚拟服务器
- 直接处理请求(HTTP/0.9非常简单,没有头部)
初始化头部列表(HTTP/1.0+)
if (ngx_list_init(&r->headers_in.headers, r->pool, 20,
sizeof(ngx_table_elt_t))
!= NGX_OK)
{
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
break;
}
- 为HTTP头部初始化存储空间(预分配20个头部的空间)
- 如果失败,返回500错误
- ngx_table_elt_t
切换到头部处理阶段
c->log->action = "reading client request headers";
rev->handler = ngx_http_process_request_headers;
ngx_http_process_request_headers(rev);
break;
- 更新日志动作为"reading client request headers"
- 设置下一步处理函数为头部处理器
- 调用头部处理函数
- 跳出循环
- ngx_http_process_request_headers
解析错误处理
if (rc != NGX_AGAIN) {
ngx_log_error(NGX_LOG_INFO, c->log, 0,
ngx_http_client_errors[rc - NGX_HTTP_CLIENT_ERROR]);
if (rc == NGX_HTTP_PARSE_INVALID_VERSION) {
ngx_http_finalize_request(r, NGX_HTTP_VERSION_NOT_SUPPORTED);
} else {
ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
}
break;
}
- 如果解析出错(不是需要更多数据的状态)
- 记录客户端错误日志
- 如果是无效版本号,返回505错误
- 其他错误返回400错误
- 跳出循环
缓冲区空间不足处理
if (r->header_in->pos == r->header_in->end) {
rv = ngx_http_alloc_large_header_buffer(r, 1);
if (rv == NGX_ERROR) {
ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
break;
}
if (rv == NGX_DECLINED) {
r->request_line.len = r->header_in->end - r->request_start;
r->request_line.data = r->request_start;
ngx_log_error(NGX_LOG_INFO, c->log, 0,
"client sent too long URI");
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_URI_TOO_LARGE);
break;
}
}
- 如果缓冲区已满
- 尝试分配更大的缓冲区
- 如果分配失败(NGX_ERROR),返回500错误
- 如果拒绝分配(NGX_DECLINED,如URI太长),返回414错误
- 记录URI太长的错误
运行后续请求
ngx_http_run_posted_requests(c);
}
- 函数最后,运行任何已发布的请求(处理可能挂起的请求)
这个函数展示了Nginx如何高效地处理HTTP请求的第一阶段,包括错误处理、缓冲区管理和状态转换等关键功能。
2149

被折叠的 条评论
为什么被折叠?



