12.6.2 默认的input_filter方法
如果HTTP模块没有实现input_filter方法,那么将使用ngx_http_upstream_non_buffered_filter方法作为input_filter,这个默认的方法将会试图在buffer缓冲区中存放全部的响应包体。
ngx_http_upstream_non_buffered_filter方法其实很简单,下面直接列出其主要代码来分析该方法。
static ngx_int_t ngx_http_upstream_non_buffered_filter(void*data,ssize_t bytes)
{
/前文说过,data参数就是ngx_http_upstream_t结构体中的input_filter_ctx,当HTTP模块未实现input_filter方法时,input_filter_ctx成员会指向请求的ngx_http_request_t结构体/
ngx_http_request_t*r=data;
ngx_buf_t*b;
ngx_chain_tcl,*ll;
ngx_http_upstream_t*u;
u=r->upstream;
/找到out_bufs链表的末尾,其中cl指向链表中最后一个ngx_chain_t元素的next成员,所以cl最后一定是NULL空指针,而ll指向最后一个缓冲区的地址,它用来在后面的代码中向out_bufs链表添加新的缓冲区/
for(cl=u->out_bufs,ll=&u->out_bufs;cl;cl=cl->next)
{
ll=&cl->next;
}
/free_bufs指向空闲的ngx_buf_t结构体构成的链表,如果free_bufs此时是空的,那么将会重新由r->pool内存池中分配一个ngx_buf_t结构体给cl;如果free_bufs链表不为空,则直接由free_bufs中获取一个ngx_buf_t结构体给cl/
cl=ngx_chain_get_free_buf(r->pool,&u->free_bufs);
if(cl==NULL){
return NGX_ERROR;
}
//将新分配的ngx_buf_t结构体添加到out_bufs链表的末尾
*ll=cl;
/修改新分配缓冲区的标志位,表明在内存中,flush标志位为可能发送缓冲区到客户端服务,参见12.7节/
cl->buf->flush=1;
cl->buf->memory=1;
//buffer缓冲区才是真正接收上游服务器响应包体的缓冲区
b=&u->buffer;
//last实际指向本次接收到的包体首地址
cl->buf->pos=b->last;
//last向后移动bytes字节,意味着buffer需要保存这次收到的包体
b->last+=bytes;
//last和pos成员确定了out_bufs链表中每个缓冲区的包体数据
cl->buf->last=b->last;
cl->buf->tag=u->output.tag;
/如果没有设置包体长度,u->length就是NGX_MAX_SIZE_T_VALUE,那么到这里结束/
if(u->length==NGX_MAX_SIZE_T_VALUE){
return NGX_OK;
}
//更新length,需要接收到的包体长度减少bytes字节
u->length-=bytes;
return NGX_OK;
}
可以看到,默认的input_filter方法会试图让独立的buffer缓冲区保存全部的包体,这就要求我们对上游服务器的响应包体大小有绝对正确的判断,否则一旦上游服务器发来的响应包体超过buffer缓冲区的大小,请求将会出错。
注意 对于上述这段代码的理解,可参见图12-8第4步中ngx_chain_update_chains方法的执行过程,它们是配对执行的。