ngx_http_process_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;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; // 设置当前连接的超时标志位为1ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);return;}// NGX_AGAIN表示接收缓冲区header_in中没有未解析的数据rc = NGX_AGAIN;for ( ;; ) {// 若header_in中没有未解析的数据if (rc == NGX_AGAIN) {// 把内核套接字缓冲区的数据复制到header_in中n = ngx_http_read_request_header(r);// NGX_AGAIN表示若需要继续接收数据,NGX_ERROR表示客户端关闭连接或连接错误if (n == NGX_AGAIN || n == NGX_ERROR) {return;}}// 若header_in中有未解析的数据,用状态机解析数据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) {return;}if (r->host_start && 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);return;}if (rc == NGX_ERROR) {ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);return;}if (ngx_http_set_virtual_server(r, &host) == NGX_ERROR) {return;}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){return;}ngx_http_process_request(r);return;}// 初始化链表,为接收http请求头做好准备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);return;}c->log->action = "reading client request headers";// 修改当前连接的读事件的回调函数为ngx_http_process_request_headers()并调用该函数rev->handler = ngx_http_process_request_headers;ngx_http_process_request_headers(rev);return;}// 若ngx_http_parse_request_line()返回错误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]);ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);return;}/* NGX_AGAIN: a request line parsing is still incomplete */// 若ngx_http_parse_request_line()返回NGX_AGAIN,需要判断是缓冲区大小不够,还是已读数据不够// 若缓冲区已经用尽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);return;}// 若大缓冲区仍然装不下整个请求行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);return;}}}
}

ngx_http_read_request_header()

static ssize_t
ngx_http_read_request_header(ngx_http_request_t *r)
{ssize_t                    n;ngx_event_t               *rev;ngx_connection_t          *c;ngx_http_core_srv_conf_t  *cscf;c = r->connection; // 当前请求对应的连接rev = c->read; // 当前连接对应的读事件n = r->header_in->last - r->header_in->pos;// 若当前请求的接收缓冲区header_in中有未解析的数据,直接返回if (n > 0) {return n;}// 若当前读事件已就绪if (rev->ready) {// 循环调用recv()将内核套接字缓冲区中的数据复制到header_in中n = c->recv(c, r->header_in->last,r->header_in->end - r->header_in->last);} else {n = NGX_AGAIN;}if (n == NGX_AGAIN) {if (!rev->timer_set) {cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);// 将读事件加入到定时器中ngx_add_timer(rev, cscf->client_header_timeout);}// 将读事件加入到epoll中if (ngx_handle_read_event(rev, 0) != NGX_OK) {ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);return NGX_ERROR;}return NGX_AGAIN;}// 若客户端关闭连接if (n == 0) {ngx_log_error(NGX_LOG_INFO, c->log, 0,"client prematurely closed connection");}// 若客户端关闭连接或连接错误if (n == 0 || n == NGX_ERROR) {c->error = 1;c->log->action = "reading client request headers";ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);return NGX_ERROR;}r->header_in->last += n;return n;
}

ngx_http_process_request_headers()

static void
ngx_http_process_request_headers(ngx_event_t *rev)
{u_char                     *p;size_t                      len;ssize_t                     n;ngx_int_t                   rc, rv;ngx_table_elt_t            *h;ngx_connection_t           *c;ngx_http_header_t          *hh;ngx_http_request_t         *r;ngx_http_core_srv_conf_t   *cscf;ngx_http_core_main_conf_t  *cmcf;c = rev->data;r = c->data;ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0,"http process request header line");// 若当前读事件已经超时if (rev->timedout) {ngx_log_error(NGX_LOG_INFO, c->log, NGX_ETIMEDOUT, "client timed out");c->timedout = 1; // 设置当前连接的超时标志位为1ngx_http_close_request(r, NGX_HTTP_REQUEST_TIME_OUT);return;}cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);rc = NGX_AGAIN;for ( ;; ) {if (rc == NGX_AGAIN) {// 若缓冲区已经用尽if (r->header_in->pos == r->header_in->end) {// 分配另一块大缓冲区并拷贝之前的数据rv = ngx_http_alloc_large_header_buffer(r, 0);if (rv == NGX_ERROR) {ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);return;}// 若大缓冲区仍然装不下整个请求头if (rv == NGX_DECLINED) {p = r->header_name_start;r->lingering_close = 1;if (p == NULL) {ngx_log_error(NGX_LOG_INFO, c->log, 0,"client sent too large request");ngx_http_finalize_request(r,NGX_HTTP_REQUEST_HEADER_TOO_LARGE);return;}len = r->header_in->end - p;if (len > NGX_MAX_ERROR_STR - 300) {len = NGX_MAX_ERROR_STR - 300;}ngx_log_error(NGX_LOG_INFO, c->log, 0,"client sent too long header line: \"%*s...\"",len, r->header_name_start);ngx_http_finalize_request(r,NGX_HTTP_REQUEST_HEADER_TOO_LARGE);return;}}// 把内核套接字缓冲区的数据复制到header_in中n = ngx_http_read_request_header(r);// NGX_AGAIN表示若需要继续接收数据,NGX_ERROR表示客户端关闭连接或连接错误if (n == NGX_AGAIN || n == NGX_ERROR) {return;}}/* the host header could change the server configuration context */cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);// 若header_in中有未解析的数据,用状态机解析数据rc = ngx_http_parse_header_line(r, r->header_in,cscf->underscores_in_headers);// 返回NGX_OK,表示解析出了一行请求头if (rc == NGX_OK) {r->request_length += r->header_in->pos - r->header_name_start;if (r->invalid_header && cscf->ignore_invalid_headers) {/* there was error while a header line parsing */ngx_log_error(NGX_LOG_INFO, c->log, 0,"client sent invalid header line: \"%*s\"",r->header_end - r->header_name_start,r->header_name_start);continue;}/* a header line has been parsed successfully */h = ngx_list_push(&r->headers_in.headers);if (h == NULL) {ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);return;}h->hash = r->header_hash;h->key.len = r->header_name_end - r->header_name_start;h->key.data = r->header_name_start;h->key.data[h->key.len] = '\0';h->value.len = r->header_end - r->header_start;h->value.data = r->header_start;h->value.data[h->value.len] = '\0';h->lowcase_key = ngx_pnalloc(r->pool, h->key.len);if (h->lowcase_key == NULL) {ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);return;}if (h->key.len == r->lowcase_index) {ngx_memcpy(h->lowcase_key, r->lowcase_header, h->key.len);} else {ngx_strlow(h->lowcase_key, h->key.data, h->key.len);}hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,h->lowcase_key, h->key.len);if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {return;}ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"http header: \"%V: %V\"",&h->key, &h->value);continue;}// 返回NGX_HTTP_PARSE_HEADER_DONE,表示解析出了整个请求头if (rc == NGX_HTTP_PARSE_HEADER_DONE) {/* a whole header has been parsed successfully */ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,"http header done");r->request_length += r->header_in->pos - r->header_name_start;// 设置请求状态为NGX_HTTP_PROCESS_REQUEST_STATEr->http_state = NGX_HTTP_PROCESS_REQUEST_STATE;/* ngx_http_process_request_header() {...ngx_http_set_virtual_server() {...ngx_http_find_virtual_server()...}}   ngx_http_process_request_header()主要做了两个方面的事情:一是调用ngx_http_find_virtual_server()查找虚拟服务器配置;二是对一些请求头做一些协议的检查 */rc = ngx_http_process_request_header(r);if (rc != NGX_OK) {return;}// 处理http请求ngx_http_process_request(r);return;}// 返回NGX_AGAIN,表示需要继续接收数据if (rc == NGX_AGAIN) {/* a header line parsing is still not complete */continue;}/* rc == NGX_HTTP_PARSE_INVALID_HEADER */// 返回NGX_HTTP_PARSE_INVALID_HEADER,表示请求头解析过程中遇到错误ngx_log_error(NGX_LOG_INFO, c->log, 0,"client sent invalid header line");ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);return;}
}

--------------------- 
作者:hz5034 
来源:CSDN 
原文:https://blog.csdn.net/hz5034/article/details/81055155 
版权声明:本文为博主原创文章,转载请附上博文链接!

Nginx源码阅读(ngx_http_process_request_line)相关推荐

  1. Nginx源码阅读:ngx_palloc 内存池

    Nginx源码阅读:ngx_palloc 内存池 一.内存池 二.大块 三.chunck(小块) 四.nginx内存池的结构图 五.源码阅读 1.`ngx_create_pool` 2.`ngx_de ...

  2. Nginx源码阅读:共享内存ngx_shm_t和它的组织方式ngx_shm_zone_t、ngx_list_t

    Nginx源码阅读:共享内存ngx_shm_t和它的组织方式ngx_shm_zone_t.ngx_list_t 一.Nginx中共享内存的结构图 二.Nginx中实现共享内存的部分 1.共享内存配置信 ...

  3. nginx源码阅读(二).初始化:main函数及ngx_init_cycle函数

    前言 在分析源码时,我们可以先把握主干,然后其他部分再挨个分析就行了.接下来我们先看看nginx的main函数干了些什么. main函数 这里先介绍一些下面会遇到的变量类型: ngx_int_t: t ...

  4. nginx源码阅读(一).综述

    前言 nginx作为一款开源的轻量级高性能web服务器,是非常值得立志从事服务端开发方向的人学习的.现今nginx的最新版本是nginx-1.13.6,代码量也日渐庞大,但是由于其核心思想并没改变,为 ...

  5. Nginx源码阅读笔记-内存池的设计

    2019独角兽企业重金招聘Python工程师标准>>> nginx的内存池设计的比较简单了,一个内存池中分为两个部分: 超过max大小的内存分配,走大块内存分配,这部分内存管理由ng ...

  6. 从9个组件开始,教你如何高效的阅读nginx源码?

    从9个组件开始,教你如何高效的阅读nginx源码?|内存池.线程池.内存共享组件实现. http处理流程.phase原理.红黑树.配置文件.惊群.原子操作 专注于服务器后台开发,包括C/C++,Lin ...

  7. 16w行的nginx源码,如何分拆模块阅读,手把手教你造轮子丨Nginx模块开发丨C/C++丨Linux服务器开发丨后端开发

    16w行的nginx源码,如何分拆模块阅读,让你明白轮子如何造  1. 多进程模型下的惊群处理 2. 内存池的代码封装 3. slab共享内存分配 视频讲解如下,点击观看: 16w行的nginx源码, ...

  8. Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现

    Nginx模块开发:模块结构的源码阅读以及过滤器(Filter)模块的实现 一.Nignx中的模块是什么? 二.模块的基本结构 `ngx_module_s` `ngx_command_s` `ngx_ ...

  9. Nginx 源码分析-- 模块module 解析执行 nginx.conf 配置文件流程分析 一

    搭建nginx服务器时,主要的配置文件 nginx.conf 是部署和维护服务器人员经常要使用到的文件, 里面进行了许多服务器参数的设置.那么nginx 以模块 module为骨架的设计下是如何运用模 ...

最新文章

  1. Newtonsoft.Json文件错误
  2. Linux入门:部署JavaWeb项目
  3. 安装Microsoft Sysprep工具
  4. 【详细教程】教你如何使用Node + Express + Typescript开发一个应用
  5. golang 远程批量执行shell_S2061远程代码执行漏洞复现及批量检测脚本(CVE202017530)...
  6. JavaWeb之Servlet入门(一)
  7. 静态、动态函数库的设计
  8. 网站seo优化一定要注意这几件事
  9. 定位到excel最后一个非空单元格操作技巧,你一定要知道!(一)
  10. 哪个数据库替代oracle,关于Oracle数据库替代加密算法
  11. JavaScript每日一题 20170207
  12. 时序预测 | MATLAB实现基于EMD-LSTM时间序列预测(EMD分解结合LSTM长短期记忆神经网络)
  13. 视频和图片合成软件,简单快速合成视频和图片
  14. linux驱动文件目录
  15. 什么是真正的 HTAP ?(二)挑战篇
  16. 天津教育杂志天津教育杂志社天津教育编辑部2022年第30期目录
  17. 十二月份地支藏干强度表
  18. 基于MATLAB的多项式数据拟合方法研究-毕业论文
  19. MW75蓝牙5.2双模热插拔PCB
  20. Firefox 导入书签,不覆盖已有书签

热门文章

  1. 苹果推送消息服务(转)
  2. ClickOnce部署(3):使用证书
  3. CodeForces - 1363E Tree Shuffling(树上贪心)
  4. POJ - 2528 Mayor's posters(线段数+离散化)
  5. linux控制编译so 位数,Linux下解决64位下Apache编译模块时/usr/lib/libexpat.so问题
  6. 石子合并(GarsiaWachs算法)
  7. 16.枚举中的option和result.rs
  8. python3之协程(3)---greenlet实现协程操作
  9. sscanf,sscanf_s及其相关用法(字符串格式化为其他类型)
  10. STL 之count,count_if,max,max_element,min,min_element和random_shuffle