Nginx的请求处理流程之二:handler发送包头、包体
本文是解析自定义module的handler中调用了发送包头、包体函数后,nginx做了哪些工作。
参考《
Nginx的请求处理流程之一:分派handler
》中的框图。简要的说,就是调用了filters模块的链表,对handler生成的包头、包体内容最后进行加工,然后调用writev()来发送。
一、发送http包头
1、ngx_http_send_header()
系统将各个包头过滤模块的处理加入ngx_http_next_header_filter指针链表中,在调用ngx_http_send_header()时,会依次调用所有头部的过滤模块。这些模块是处理r->headers_outs 中的内容。
包头Filter模块的调用链表是如何实现的,请见下面2.2中的包体Filter模块的调用链表的说明。
2、
ngx_http_header_filter()
包头Filter模块处理链表最后一个头部过滤的方法负责发送头部。
包头最后的过滤模块就是ngx_http_header_filter_module。
其
ngx_http_header_filter(),它
将r->header_outs的内容序列化并发送出去。如果一次发送不完,需要将剩下的响应头部保存到r->out链表中,以备后续发送:
ngx_int_t ngx_http_header_filter(ngx_http_request_t *r)
{
ngx_chain_t out;
if (r->header_sent) return NGX_OK;
r->header_sent = 1;
//将r->header_outs的内容序列化为http包头
......
return
ngx_http_write_filter(r, &out);
//发送包头
}
|
3、ngx_http_write_filter() //ngx_http_writer_filter_module
这是包头Filter模块处理链表的最后一个
模块ngx_http_writer_filter_module的处理方法。发送包头、包体都用这个的:
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_chain_t *chain;
ngx_connection_t *c;
c = r->connection;
...
//将in追加如r->out的尾部。
if (c->write->delayed) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
}
//send_chain返回的是没有发完的chain
chain = c->
send_chain(c, r->out, limit);
r->out = chain;
//如果chain不为空,那么buf没有发送完,需要设置buffered标记,并返回NGX_AGAIN
if (chain)
{
c->
buffered |= NGX_HTTP_WRITE_BUFFERED;
return
NGX_AGAIN;
}
//如果已经没有未发送的chain,就清空buffered标记
c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
//如果其他filter模块buffer了chain并且postponed为NULL,那么返回NGX_AGAIN,需要继续处理buf
if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
return
NGX_AGAIN;
}
return
NGX_OK;
}
|
如果无法一次发送,则将剩余内容保存到r->out中,并返回NGX_AGAIN。
返回到ngx_http_finalize_request(),这时http框架就会继续将可写事件注册到epoll。
其中,c->send_chain在
ngx_event_accept()和
ngx_event_connect_peer()中设置:
c->recv = ngx_recv;
c->send = ngx_send;
c->recv_chain = ngx_recv_chain;
c->send_chain = ngx_send_chain;
ngx_send_chain最后调用了
ngx_writev_chain.c的
:
ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
|- ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec);
|-
writev(
c->fd, vec->iovs, vec->count
);
ngx_http_write_filter()的返回值的最终会在ngx_http_finalize_request()中处理,该函数
负责根据返回值调整
当前请求的后续流程,包括结束请求:
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
if (rc ==
NGX_DONE) {
ngx_http_finalize_connection(r);
return;
}
if (rc ==
NGX_OK && r->filter_finalize) {
c->error = 1;
}
if (rc ==
NGX_DECLINED) {
r->content_handler = NULL;
r->write_event_handler =
ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
return;
}
if (rc ==
NGX_ERROR
|| rc == NGX_HTTP_REQUEST_TIME_OUT
|| rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
|| c->error)
{
if (ngx_http_post_action(r) == NGX_OK)
return;
if (r->main->blocked)
r->write_event_handler = ngx_http_request_finalizer;
ngx_http_terminate_request(r, rc);
return;
}
...
if (r->buffered || c->
buffered || r->postponed || r->blocked) {
//这里应该就是默认的NGX_AGAIN
if (
ngx_http_set_write_handler(r) != NGX_OK)
ngx_http_terminate_request(r, 0);
return;
}
if (c->read->eof) {
ngx_http_close_request(r, 0);
return;
}
ngx_http_finalize_connection(r);
}
|
5、ngx_http_set_write_handler()
该函数(ngx_http_request.c中)中
调用了
ngx_handle_write_event()将当前连接的写事件重新加入epoll:
ngx_int_t
ngx_http_set_write_handler(ngx_http_request_t *r)
{
ngx_event_t *wev;
ngx_http_core_loc_conf_t *clcf;
r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
r->write_event_handler =
ngx_http_writer;
wev = r->connection->write;
...
if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
ngx_http_close_request(r, 0);
return NGX_ERROR;
}
return NGX_OK;
}
|
6、void ngx_http_writer()
该函数(ngx_http_request.c中)中调用了ngx_http_output_filter发送。并根据结果重设epoll事件。
void ngx_http_writer(ngx_http_request_t *r)
{
int rc;
ngx_event_t *wev;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
c = r->connection;
wev = c->write;
clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);
//首先处理写事件超时
if (wev->timedout)
{
if (!wev->delayed)
{
c->timedout = 1;
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
wev->timedout = 0;
wev->delayed = 0;
//如果写事件延迟了但仍未准备好,重新放入epoll事件
if (!wev->ready)
{
ngx_add_timer(wev, clcf->send_timeout);
if (
ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
ngx_http_close_request(r, 0);
return;
}
}
//未超时时,但事件需要延期,重新加入epoll事件。
if (wev->delayed || r->aio)
{
if (
ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
ngx_http_close_request(r, 0);
return;
}
rc =
ngx_http_output_filter(r, NULL);
if (rc == NGX_ERROR)
{
ngx_http_finalize_request(r, rc);
return;
}
//已经发送完了包了,如果当前还在接收数据,或需要延期时,进行的处理
if (r->buffered || r->postponed || (r == r->main && c->buffered))
{
//如果没有写延期,将启动超时定时器
if (!wev->delayed)
ngx_add_timer(wev, clcf->send_timeout);
//将当前写事件加入epoll中等待处理。
if (
ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
ngx_http_close_request(r, 0);
return;
}
//即不再处理写事件了
r->write_event_handler = ngx_http_request_empty_handler;
ngx_http_finalize_request(r,
rc);
}
|
二、发送包体
发送包头执行的也就是ngx_http_writer()中调用的ngx_http_output_filter这个函数。而发送包体
也要先经过包体
过滤模块来处理,最后再发送。
1、ngx_http_output_filter()
typedef ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_http_output_body_filter_pt ngx_http_top_body_filter;
ngx_int_t
ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
return ngx_http_top_body_filter(r, in);
}
|
2、 ngx_http_write_filter() //ngx_http_writer_filter_module
如下可见通过各包体Filter模块的本地变量ngx_http_next_body_filter,形成了一个包体Filter模块的调用链表。最后调用的ngx_http_top_body_filter 就是
ngx_http_write_filter_module模块的ngx_http_write_filter()。
ngx_http_write_filter()的流程解析,参考前面
发送包头部分
。
//ngx_http_write_filter_module.c:
//ngx_http_write_filter_module_ctx的postconfiguration函数
ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf)
{
ngx_http_top_body_filter =
ngx_http_write_filter;
return NGX_OK;
}
//ngx_http_copy_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
ngx_int_t ngx_http_copy_filter_init(ngx_conf_t *cf)
{
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_copy_filter;
return NGX_OK;
}
//ngx_http_postpone_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf)
{
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_postpone_filter;
return NGX_OK;
}
|
注意:
ngx_http_top_body_filter是全局的。而ngx_http_next_body_filter静态的,当前filter文件中的,用于缓存全局变量,而在执行ngx_http_copy_filter完成时再把静态变量赋给全局的。
ngx_http_write_filter_module是最后一个模块,因此不再设置ngx_http_next_body_filter了。
这样实现了一个output filter链表,由Filter模块代码自己来加入链表,而不需修改其他代码。如nginx自己的gzip压缩处理等Filter模块就是这样被调用的。
三、结束请求
1、ngx_http_finalize_request()
前面已经有分析了,所有发送结果都要返回这里重新进行分派,是终止连接、正常结束请求还是继续发送,视模块handler的返回值来定。
2、ngx_http_close_request()
最终的结束请求的方法,在于其中调用的最后两个函数:
void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
{
ngx_connection_t *c;
r = r->main;
c = r->connection;
r->count--;
if (r->count || r->blocked)
return;
ngx_http_free_request(r, rc);
ngx_http_close_connection(c);
}
|
Nginx的请求处理流程之二:handler发送包头、包体
本文是解析自己写的module的handler中调用了发送包头、包体函数后,nginx做了哪些工作。
参考《
Nginx的请求处理流程之一:分派handler
》中的框图。简要的说,就是调用了filters模块的链表,对handler生成的包头、包体内容最后进行加工,然后调用writev()来发送。
一、发送http包头
1、ngx_http_send_header()
系统将各个包头过滤模块的处理加入ngx_http_next_header_filter指针链表中,在调用ngx_http_send_header()时,会依次调用所有头部的过滤模块。这些模块是处理r->headers_outs 中的内容。
包头Filter模块的调用链表是如何实现的,请见下面2.2中的包体Filter模块的调用链表的说明。
2、
ngx_http_header_filter()
包头Filter模块处理链表最后一个头部过滤的方法负责发送头部。
包头最后的过滤模块就是ngx_http_header_filter_module。
其
ngx_http_header_filter(),它
将r->header_outs的内容序列化并发送出去。如果一次发送不完,需要将剩下的响应头部保存到r->out链表中,以备后续发送:
ngx_int_t ngx_http_header_filter(ngx_http_request_t *r)
{
ngx_chain_t out;
if (r->header_sent) return NGX_OK;
r->header_sent = 1;
//将r->header_outs的内容序列化为http包头
......
return
ngx_http_write_filter(r, &out);
//发送包头
}
|
3、ngx_http_write_filter() //ngx_http_writer_filter_module
这是包头Filter模块处理链表的最后一个
模块ngx_http_writer_filter_module的处理方法。发送包头、包体都用这个的:
ngx_int_t ngx_http_write_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
ngx_chain_t *chain;
ngx_connection_t *c;
c = r->connection;
...
//将in追加如r->out的尾部。
if (c->write->delayed) {
c->buffered |= NGX_HTTP_WRITE_BUFFERED;
return NGX_AGAIN;
}
//send_chain返回的是没有发完的chain
chain = c->
send_chain(c, r->out, limit);
r->out = chain;
//如果chain不为空,那么buf没有发送完,需要设置buffered标记,并返回NGX_AGAIN
if (chain)
{
c->
buffered |= NGX_HTTP_WRITE_BUFFERED;
return
NGX_AGAIN;
}
//如果已经没有未发送的chain,就清空buffered标记
c->buffered &= ~NGX_HTTP_WRITE_BUFFERED;
//如果其他filter模块buffer了chain并且postponed为NULL,那么返回NGX_AGAIN,需要继续处理buf
if ((c->buffered & NGX_LOWLEVEL_BUFFERED) && r->postponed == NULL) {
return
NGX_AGAIN;
}
return
NGX_OK;
}
|
如果无法一次发送,则将剩余内容保存到r->out中,并返回NGX_AGAIN。
返回到ngx_http_finalize_request(),这时http框架就会继续将可写事件注册到epoll。
其中,c->send_chain在
ngx_event_accept()和
ngx_event_connect_peer()中设置:
c->recv = ngx_recv;
c->send = ngx_send;
c->recv_chain = ngx_recv_chain;
c->send_chain = ngx_send_chain;
ngx_send_chain最后调用了
ngx_writev_chain.c的
:
ngx_writev_chain(ngx_connection_t *c, ngx_chain_t *in, off_t limit)
|- ngx_writev(ngx_connection_t *c, ngx_iovec_t *vec);
|-
writev(
c->fd, vec->iovs, vec->count
);
ngx_http_write_filter()的返回值的最终会在ngx_http_finalize_request()中处理,该函数
负责根据返回值调整
当前请求的后续流程,包括结束请求:
void ngx_http_finalize_request(ngx_http_request_t *r, ngx_int_t rc)
{
if (rc ==
NGX_DONE) {
ngx_http_finalize_connection(r);
return;
}
if (rc ==
NGX_OK && r->filter_finalize) {
c->error = 1;
}
if (rc ==
NGX_DECLINED) {
r->content_handler = NULL;
r->write_event_handler =
ngx_http_core_run_phases;
ngx_http_core_run_phases(r);
return;
}
if (rc ==
NGX_ERROR
|| rc == NGX_HTTP_REQUEST_TIME_OUT
|| rc == NGX_HTTP_CLIENT_CLOSED_REQUEST
|| c->error)
{
if (ngx_http_post_action(r) == NGX_OK)
return;
if (r->main->blocked)
r->write_event_handler = ngx_http_request_finalizer;
ngx_http_terminate_request(r, rc);
return;
}
...
if (r->buffered || c->
buffered || r->postponed || r->blocked) {
//这里应该就是默认的NGX_AGAIN
if (
ngx_http_set_write_handler(r) != NGX_OK)
ngx_http_terminate_request(r, 0);
return;
}
if (c->read->eof) {
ngx_http_close_request(r, 0);
return;
}
ngx_http_finalize_connection(r);
}
|
5、ngx_http_set_write_handler()
该函数(ngx_http_request.c中)中
调用了
ngx_handle_write_event()将当前连接的写事件重新加入epoll:
ngx_int_t
ngx_http_set_write_handler(ngx_http_request_t *r)
{
ngx_event_t *wev;
ngx_http_core_loc_conf_t *clcf;
r->http_state = NGX_HTTP_WRITING_REQUEST_STATE;
r->write_event_handler =
ngx_http_writer;
wev = r->connection->write;
...
if (ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK) {
ngx_http_close_request(r, 0);
return NGX_ERROR;
}
return NGX_OK;
}
|
6、void ngx_http_writer()
该函数(ngx_http_request.c中)中调用了ngx_http_output_filter发送。并根据结果重设epoll事件。
void ngx_http_writer(ngx_http_request_t *r)
{
int rc;
ngx_event_t *wev;
ngx_connection_t *c;
ngx_http_core_loc_conf_t *clcf;
c = r->connection;
wev = c->write;
clcf = ngx_http_get_module_loc_conf(r->main, ngx_http_core_module);
//首先处理写事件超时
if (wev->timedout)
{
if (!wev->delayed)
{
c->timedout = 1;
ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
return;
}
wev->timedout = 0;
wev->delayed = 0;
//如果写事件延迟了但仍未准备好,重新放入epoll事件
if (!wev->ready)
{
ngx_add_timer(wev, clcf->send_timeout);
if (
ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
ngx_http_close_request(r, 0);
return;
}
}
//未超时时,但事件需要延期,重新加入epoll事件。
if (wev->delayed || r->aio)
{
if (
ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
ngx_http_close_request(r, 0);
return;
}
rc =
ngx_http_output_filter(r, NULL);
if (rc == NGX_ERROR)
{
ngx_http_finalize_request(r, rc);
return;
}
//已经发送完了包了,如果当前还在接收数据,或需要延期时,进行的处理
if (r->buffered || r->postponed || (r == r->main && c->buffered))
{
//如果没有写延期,将启动超时定时器
if (!wev->delayed)
ngx_add_timer(wev, clcf->send_timeout);
//将当前写事件加入epoll中等待处理。
if (
ngx_handle_write_event(wev, clcf->send_lowat) != NGX_OK)
ngx_http_close_request(r, 0);
return;
}
//即不再处理写事件了
r->write_event_handler = ngx_http_request_empty_handler;
ngx_http_finalize_request(r,
rc);
}
|
二、发送包体
发送包头执行的也就是ngx_http_writer()中调用的ngx_http_output_filter这个函数。而发送包体
也要先经过包体
过滤模块来处理,最后再发送。
1、ngx_http_output_filter()
typedef ngx_int_t (*ngx_http_output_body_filter_pt)(ngx_http_request_t *r, ngx_chain_t *chain);
ngx_http_output_body_filter_pt ngx_http_top_body_filter;
ngx_int_t
ngx_http_output_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
return ngx_http_top_body_filter(r, in);
}
|
2、 ngx_http_write_filter() //ngx_http_writer_filter_module
如下可见通过各包体Filter模块的本地变量ngx_http_next_body_filter,形成了一个包体Filter模块的调用链表。最后调用的ngx_http_top_body_filter 就是
ngx_http_write_filter_module模块的ngx_http_write_filter()。
ngx_http_write_filter()的流程解析,参考前面
发送包头部分
。
//ngx_http_write_filter_module.c:
//ngx_http_write_filter_module_ctx的postconfiguration函数
ngx_int_t ngx_http_write_filter_init(ngx_conf_t *cf)
{
ngx_http_top_body_filter =
ngx_http_write_filter;
return NGX_OK;
}
//ngx_http_copy_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
ngx_int_t ngx_http_copy_filter_init(ngx_conf_t *cf)
{
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_copy_filter;
return NGX_OK;
}
//ngx_http_postpone_filter_module.c:
static ngx_http_output_body_filter_pt ngx_http_next_body_filter;
ngx_int_t ngx_http_postpone_filter_init(ngx_conf_t *cf)
{
ngx_http_next_body_filter = ngx_http_top_body_filter;
ngx_http_top_body_filter = ngx_http_postpone_filter;
return NGX_OK;
}
|
注意:
ngx_http_top_body_filter是全局的。而ngx_http_next_body_filter静态的,当前filter文件中的,用于缓存全局变量,而在执行ngx_http_copy_filter完成时再把静态变量赋给全局的。
ngx_http_write_filter_module是最后一个模块,因此不再设置ngx_http_next_body_filter了。
这样实现了一个output filter链表,由Filter模块代码自己来加入链表,而不需修改其他代码。如nginx自己的gzip压缩处理等Filter模块就是这样被调用的。
3、结束请求
1、ngx_http_finalize_request()
前面已经有分析了,所有发送结果都要返回这里重新进行分派,是终止连接、正常结束请求还是继续发送,视模块handler的返回值来定。
2、ngx_http_close_request()
最终的结束请求的方法,在于其中调用的最后两个函数:
void ngx_http_close_request(ngx_http_request_t *r, ngx_int_t rc)
{
ngx_connection_t *c;
r = r->main;
c = r->connection;
r->count--;
if (r->count || r->blocked)
return;
ngx_http_free_request(r, rc);
ngx_http_close_connection(c);
}
|