ngxin源码分析(9)——filter模块
phase handler处理中介绍了content handler用于产生响应内容,随便找一个content phase的模块,比如:ngx_http_static_module.c,会发现在content handler中会调用ngx_http_send_header,然后最后调用ngx_http_output_filter。这两个函数就是发送响应头部和响应体的,在nginx中输出内容是通过filter完成的。
filter模块用于过滤和输出响应内容,nginx将所有的filter组织成只有头结点的单链表(实际上就是栈),这个头结点分别是ngx_http_top_header_filter(过滤头部)和ngx_http_top_body_filter(过滤响应体)。在每次初始化一个filter模块时,都会将当前filter链表的头结点ngx_http_top_header_filter和ngx_http_top_body_filter分别保存为ngx_http_next_header_filter和ngx_http_next_body_filter,同时将本模块的filter函数保存为ngx_http_top_header_filter和ngx_http_top_body_filter,然后在本模块filter函数的最后部分调用ngx_http_next_header_filter和ngx_http_next_body_filter,这样就实现了所有filter模块的链式调用。由于filter模块的添加实际上就是不停的向链表的头push节点,所以后添加的模块比先添加的模块在filter链中靠前。
先看一下ngx_http_send_header函数:
sent = c->sent; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter limit %O", limit); /* send_chain返回的是没有发完的chain */ chain = c->send_chain(c, r->out, limit); ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0, "http write filter %p", chain); if (chain == NGX_CHAIN_ERROR) { c->error = 1; return NGX_ERROR; } /* 对limit_rate处理,可能会设置delayed标记 */ if (r->limit_rate) { nsent = c->sent; if (clcf->limit_rate_after) { sent -= clcf->limit_rate_after; if (sent < 0) { sent = 0; } nsent -= clcf->limit_rate_after; if (nsent < 0) { nsent = 0; } } delay = (ngx_msec_t) ((nsent - sent) * 1000 / r->limit_rate + 1); if (delay > 0) { c->write->delayed = 1; ngx_add_timer(c->write, delay); } } else if (c->write->ready && clcf->sendfile_max_chunk && (size_t) (c->sent - sent) >= clcf->sendfile_max_chunk - 2 * ngx_pagesize) { c->write->delayed = 1; ngx_add_timer(c->write, 1); } /* 释放已经发送的chain的内存 */ for (cl = r->out; cl && cl != chain; /* void */) { ln = cl; cl = cl->next; ngx_free_chain(r->pool, ln); } /* 重新赋值尚未发送的chain */ 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;上面就是ngx_http_write_filter的处理过程,ngx_http_header_filter与之类似,只是它处理的是响应头,然后在最后也是通过ngx_http_write_filter输出。