ngx_http_process_request_line

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

成功解析请求行

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

处理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请求的第一阶段,包括错误处理、缓冲区管理和状态转换等关键功能。

内容概要:本文围绕SecureCRT自动化脚本开发在毕业设计中的应用,系统介绍了如何利用SecureCRT的脚本功能(支持Python、VBScript等)提升计算机、网络工程等相关专业毕业设计的效率与质量。文章从关键概念入手,阐明了SecureCRT脚本的核心对象(如crt、Screen、Session)及其在解决多设备调试、重复操作、跨场景验证等毕业设计常见痛点中的价值。通过三个典型应用场景——网络设备配置一致性验证、嵌入式系统稳定性测试、云平台CLI兼容性测试,展示了脚本的实际赋能效果,并以Python实现的交换机端口安全配置验证脚本为例,深入解析了会话管理、屏幕同步、输出解析、异常处理和结果导出等关键技术细节。最后展望了低代码化、AI辅助调试和云边协同等未来发展趋势。; 适合人群:计算机、网络工程、物联网、云计算等相关专业,具备一定编程基础(尤其是Python)的本科或研究生毕业生,以及需要进行设备自动化操作的科研人员; 使用场景及目标:①实现批量网络设备配置的自动验证与报告生成;②长时间自动化采集嵌入式系统串口数据;③批量执行云平台CLI命令并分析兼容性差异;目标是提升毕业设计的操作效率、增强实验可复现性与数据严谨性; 阅读建议:建议读者结合自身毕业设计课题,参考文中代码案例进行本地实践,重点关注异常处理机制与正则表达式的适配,并注意敏感信息(如密码)的加密管理,同时可探索将脚本与外部工具(如Excel、数据库)集成以增强结果分析能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值