nginx request

在nginx系列nginx2中 我们理解了nginx针对连接的处理,下面我们来看看nginx针对http怎么进一步处理,nginx基于connect构建request request封装的是对http的请求,即http,请求头,请求体,响应头,响应体,从ngx_http_init_connection函数开始,设置读,写处理函数 在ngx_http_wait_request_handler读函数中最终设置读为ngx_http_process_request_line且调用,也就是说接下来的网络事件都由 该函数来处理

//src/http/ngx_http_request.c void ngx_http_init_connection(ngx_connection_t *c)
rev = c->read;
rev->handler = ngx_http_wait_request_handler;
c->write->handler = ngx_http_empty_handler;

...
rev->handler = ngx_http_process_request_line;
ngx_http_process_request_line(rev);

nginx ngx_http_process_request_line

首先通过调用ngx_http_read_request_header来获取请求请求数据,然后调用ngx_http_parse_request_line来获取请求数据 通过ngx_http_read_request_header获取请求头,以及一些校验,并将参数保存到ngx_http_request_t。解析完请求后会把读事件 设置成ngx_http_process_request_headers,后续的请求就会在该函数读取与解析,该函数也是调用ngx_http_read_request_header来读取请求头 并调用ngx_http_parse_header_line获取一行请求头数据,解析到的请求头会保存到 ngx_http_request_t 的域 headers_in中 headers_in 是一个链表结构,保存所有的请求头,有些请求头是需要特别处理,nginx会把请求头与处理函数存放在ngx_http_headers_in里, 初始化的时候,会生成一个hash表当每解析到一个请求头后,就会先在这个 hash 表中查找,如果 有找到,则调用相应的处理函数来处理这个请求头。比如:Host 头的处理函数是ngx_http_process_host。
当nginx解析到结束标\r\n的时候 代表请求头读完了,会调用ngx_http_process_request来处理请求体。具体代码如下

//这里设置的读写都是ngx_http_request_handler,在该函数中,会根据当前事件是读还是写事件调用read_event_handler/write_event_handler
c->read->handler = ngx_http_request_handler;
c->write->handler = ngx_http_request_handler;

//不读取数据了 由handler去读取
r->read_event_handler = ngx_http_block_reading;

//真正开始处理数据
ngx_http_handler(r);

这个函数会设置写事件为ngx_http_core_run_phases,并执行ngx_http_core_run_phases

 r->write_event_handler = ngx_http_core_run_phases;

接下来我们来看核心,这个函数将执行多阶段请求处理nginx 将一个 http请求的处理分为多个阶段,那么这个函数就是执行这些阶段来产生数据。对于将写事件 设置成ngx_http_core_run_phases,我们看下函数调用逻辑,最终是调用ngx_http_core_run_phases来处理请求,产生的响应头会放在ngx_http_request_t的headers_out中 而且各阶段会对请求进行处理,最后调用filter来过滤数据,对数据进行加工,如文件的trucked传输,gzip压缩

void ngx_http_core_run_phases(ngx_http_request_t *r)
{
    ngx_int_t                   rc;
    ngx_http_phase_handler_t   *ph;
    ngx_http_core_main_conf_t  *cmcf;

    cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
    ph = cmcf->phase_engine.handlers;
    while (ph[r->phase_handler].checker) {
        rc = ph[r->phase_handler].checker(r, &ph[r->phase_handler]);
        if (rc == NGX_OK) {
            return;
        }
    }
}
//http状态及11阶段
typedef enum {
    //注册handler函数到该阶段              //对应状态模块
    NGX_HTTP_POST_READ_PHASE = 0,       //realip
    //重写server配置的url
    NGX_HTTP_SERVER_REWRITE_PHASE,      //rewrite
    //查找location 配置
    NGX_HTTP_FIND_CONFIG_PHASE,       
    //location 重写url
    NGX_HTTP_REWRITE_PHASE,             //rewrite
    //检查是否发生了url重写,是则回到NGX_HTTP_FIND_CONFIG_PHASE
    NGX_HTTP_POST_REWRITE_PHASE,
    //访问控制阶段
    NGX_HTTP_PREACCESS_PHASE,           //limit_conn,limit_req
    //访问权限控制
    NGX_HTTP_ACCESS_PHASE,              //auth_basic,access,auth_request
    //处理权限控制
    NGX_HTTP_POST_ACCESS_PHASE,
    //内容预处理 配置try_files或mirror才会进入
    NGX_HTTP_PRECONTENT_PHASE,          //try_files
    //内容产生阶段,返回给客户端
    NGX_HTTP_CONTENT_PHASE,             //index,autoindex,concat
    //记录日志阶段
    NGX_HTTP_LOG_PHASE                  //access_log
} ngx_http_phases;

nginx http filter

filter 是一个链表结构,分别有header filter与body filter,先执行header filter 中的所有filter,然后再执行 body filter中的所有filter。 在header filter中的最后一个filter,即ngx_http_header_filter, 这个filter将会遍历所有的响应头,最后需要输出的响应头在一个连续的内存,然后调用 ngx_http_write_filter进行输出。ngx_http_write_filter是body filter中的最 后一个,所以nginx首先的body信息,在经过一系列的body filter之后, 最后也会调 用ngx_http_write_filter来进行输出
最后所有的请求头会放入buffer里,大小在nginx.conf里配置client_header_buffer_size

objs/ngx_module.c ngx_module_names数组里
"ngx_http_write_filter_module",
"ngx_http_header_filter_module",
"ngx_http_chunked_filter_module",
"ngx_http_range_header_filter_module",
"ngx_http_gzip_filter_module",
"ngx_http_postpone_filter_module",
"ngx_http_ssi_filter_module",
"ngx_http_charset_filter_module",
"ngx_http_addition_filter_module",
"ngx_http_userid_filter_module",
"ngx_http_headers_filter_module",
"ngx_http_copy_filter_module",
"ngx_http_range_body_filter_module",
"ngx_http_not_modified_filter_module",

//todo 剩余一张完整流程的图