ngx_http_request_body_filter 函数解析

函数原型 static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t r, ngx_chain_t in);

此函数是nginx body解析中重要的函数,只要nginx读取到数据,就会调用此函数

函数定义如下

static ngx_int_t
ngx_http_request_body_filter(ngx_http_request_t r, ngx_chain_t in)
{

if (r->headers_in.chunked) {
    return ngx_http_request_body_chunked_filter(r, in);

} else {
    return ngx_http_request_body_length_filter(r, in);
}

}

以下只分析非 chunked 模式,也就是 ngx_http_request_body_length_filter 函数

函数定义 删除了不影响功能的行
static ngx_int_t
ngx_http_request_body_length_filter(ngx_http_request_t r, ngx_chain_t in)
{

size_t                     size;
ngx_int_t                  rc;
ngx_buf_t                 *b;
ngx_chain_t               *cl, *tl, *out, **ll;
ngx_http_request_body_t   *rb;

rb = r->request_body;

if (rb->rest == -1) {     // rest 设置为请求头的 content-length

    rb->rest = r->headers_in.content_length_n;
}

out = NULL;
ll = &out;

// 遍历输入的chain in
// 循环的结果是 out 指向的 chain,chain 中的 buf 对象是新创建的,
// 但是 buf 指向的内存仍和输入的 in 中的 buf 指向的是一致的,
// out 指向的 chain,最后一个 buf 中字段 last_buf 为 1
// 当然也可能读入的数据不足 content length 长度,此时 rest 不为 0
// 关键,out 指向的 chain 和 buf 对象都是新创建的,buf 指向的内存是 复用的,数据还在里面
for (cl = in; cl; cl = cl->next) {

    if (rb->rest == 0) {
        break;
    }

    tl = ngx_chain_get_free_buf(r->pool, &rb->free);
    if (tl == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    b = tl->buf;

    ngx_memzero(b, sizeof(ngx_buf_t));

    b->temporary = 1;
    b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
    b->start = cl->buf->pos;
    b->pos = cl->buf->pos;
    b->last = cl->buf->last;
    b->end = cl->buf->end;

    size = cl->buf->last - cl->buf->pos;

    if ((off_t) size < rb->rest) {
        cl->buf->pos = cl->buf->last;
        rb->rest -= size;

    } else {
        cl->buf->pos += (size_t) rb->rest;
        rb->rest = 0;
        b->last = cl->buf->pos;
        b->last_buf = 1;
    }

    *ll = tl;
    ll = &tl->next;
}

rc = ngx_http_request_body_save_filter(r, out);

ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
                        (ngx_buf_tag_t) &ngx_http_read_client_request_body);

return rc;

}

看后面的函数,里面只调用了一个函数,ngx_chain_add_copy

static ngx_int_t
ngx_http_request_body_save_filter(ngx_http_request_t r, ngx_chain_t in)
{

ngx_http_request_body_t   *rb;

rb = r->request_body;

// 合并相邻的 buf
if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
    return NGX_HTTP_INTERNAL_SERVER_ERROR;
}

return NGX_OK;

}

继续

// 把要处理的 chain 追加到 request body 的 chain 列表中
// 注意,只复制了 chain 对象本身,buf 对象是复用的,更不用说 buf 指向的内存了
ngx_int_t
ngx_chain_add_copy(ngx_pool_t pool, ngx_chain_t chain, ngx_chain_t in)
{

// 输入的 chain 是 request body 中的 bufs 的地址
// 输入的 in 是 要过滤的当前请求的 body 

ngx_chain_t  *cl, **ll;

ll = chain;

// 循环结束后,ll 指向最后一个 chain 的 next,next 又是指针,所以 ll 是二级指针
for (cl = *chain; cl; cl = cl->next) {
    ll = &cl->next;
}

// 遍历 in
// 生成 chain 列表追加到 request body 的 bufs 后面,注意此处并没有生成 buf 对象,因此 buf 对象本身是复用的
while (in) {
    cl = ngx_alloc_chain_link(pool);
    if (cl == NULL) {
        return NGX_ERROR;
    }

    cl->buf = in->buf;
    *ll = cl;
    ll = &cl->next;
    in = in->next;
}

*ll = NULL;

return NGX_OK;

}

还有一个很重要的函数 ngx_chain_update_chains

调用参数为:r->pool, &rb->free, &rb->busy, &out, (ngx_buf_tag_t) &ngx_http_read_client_request_body

void
ngx_chain_update_chains(ngx_pool_t p, ngx_chain_t free, ngx_chain_t *busy,

ngx_chain_t **out, ngx_buf_tag_t tag)

{

// free, busy, out 都是二级指针
ngx_chain_t  *cl;

if (*busy == NULL) {     // busy 指向 out 指向的地方
    *busy = *out;

} else {
    for (cl = *busy; cl->next; cl = cl->next) { /* void */ } // cl 指向 busy chain 链条的最后一个

    cl->next = *out;
}
// 上面的结果就是 out 挂载到了 busy 上

*out = NULL;

while (*busy) {
    cl = *busy;

    // buf 大小不是 0,说明还没有输出;request body 中的 bufs 是输出用的,如上所述,bufs 中指向的 buf 和 busy 指向的 buf 对象是一模一样的
    if (ngx_buf_size(cl->buf) != 0) {
        break;
    }

    if (cl->buf->tag != tag) {     // tag 中存储的是 函数指针
        *busy = cl->next;
        ngx_free_chain(p, cl);
        continue;
    }

    cl->buf->pos = cl->buf->start;     // 复位
    cl->buf->last = cl->buf->start;

    *busy = cl->next;
    cl->next = *free;
    *free = cl;     // 这个 chain 放到 free 列表的最前面
}

}



综上所述,ngx_http_request_body_filter 函数的目的就是要解析读取到的数据 in,追加到 request body 里的 bufs 列表中,busy 也指向要解析到的 chain 和 buf,同时 函数会更新 request body 中 rest 的值,此值表示当前请求还有多少字节没有读取。

时间: 2024-08-30 06:57:17

ngx_http_request_body_filter 函数解析的相关文章

AngularJS指令中的compile与link函数解析

AngularJS指令中的compile与link函数解析 通常大家在使用ng中的指令的时候,用的链接函数最多的是link属性,下面这篇文章将告诉大家complie,pre-link,post-link的用法与区别. 原文地址 angularjs里的指令非常神奇,允许你创建非常语义化以及高度重用的组件,可以理解为web components的先驱者. 网上已经有很多介绍怎么使用指令的文章以及相关书籍,相互比较的话,很少有介绍compile与link的区别,更别说pre-link与post-lin

ngx_http_process_request_headers函数解析

ngx_http_process_request_headers函数被ngx_http_process_request_line函数调用,将请求头逐个放到r->headers_in.headers结构体中.由于不确定请求中一共有多少个header,所以这个函数主要功能也是在for(;;){}循环中完成,一下所有的代码都是在上述循环内部的.主要代码和解析如下: 判断是否超时,如果超时,报错并结束请求.    if (rev->timedout) {        ngx_log_error(NG

iOS 基础函数解析 - Foundation Functions Reference

Foundation Functions Reference Framework Foundation/Foundation.h Declared in NSBundle.h NSByteOrder.h NSDecimal.h NSException.h NSObjCRuntime.h NSObject.h NSPathUtilities.h NSRange.h NSZone.h Overview This chapter describes the functions and function

thread.join函数,java多线程中的join函数解析

join函数的作用,是让当前线程等待,直到调用join()的 线程结束或者等到一段时间,我们来看以下代码 1 package mian; 2 3 4 public class simpleplela { 5 static void threadMessage(String message) { 6 String threadName = 7 Thread.currentThread().getName(); 8 9 System.out.println(threadName+" "+m

socket使用TCP协议时,send、recv函数解析以及TCP连接关闭的问题

Tcp协议本身是可靠的,并不等于应用程序用tcp发送数据就一定是可靠的.不管是否阻塞,send发送的大小,并不代表对端recv到多少的数据. 在阻塞模式下, send函数的过程是将应用程序请求发送的数据拷贝到发送缓存中发送并得到确认后再返回.但由于发送缓存的存在,表现为:如果发送缓存大小比请求发送的大小要大,那么send函数立即返回,同时向网络中发送数据;否则,send向网络发送缓存中不能容纳的那部分数据,并等待对端确认后再返回(接收端只要将数据收到接收缓存中,就会确认,并不一定要等待应用程序调

BulkLoop例程の初始化函数and重复调度函数の解析

//----------------------------------------------------------------------------- // File: bulkloop.c // Contents: Hooks required to implement USB peripheral function. // // $Archive: /USB/Examples/FX2LP/bulkloop/bulkloop.c $ // $Date: 3/23/05 2:55p $

C++虚函数解析(转载)

虚函数详解第一篇:对象内存模型浅析 C++中的虚函数的内部实现机制到底是怎样的呢? 鉴于涉及到的内容有点多,我将分三篇文章来介绍. 第一篇:对象内存模型浅析,这里我将对对象的内存模型进行简单的实验和总结. 第二篇:继承对象的构造和析构浅析,这里我将对存在继承关系的对象的构造和析构进行简单的实验和总结. 第三篇:虚函数的内部机制浅析,这里我将对虚函数内部的实现机制进行实验总结. 我使用的编译器是VS2008,有不足或者不准确的地方,欢迎大家拍砖(我个人非常迫切的希望得到大家的指正),我会及时修正相

ngx_http_process_request_line函数解析

处理请求行,一般的http请求过程中,ngx_http_process_request_line函数被ngx_http_wait_request_handler调用,并且在ngx_http_wait_request_handler中被设置为读事件的回调函数.在连接被accept之后,有数据到达之后会执行ngx_http_create_request函数,之后再有读事件被触发时被调用的回调函数就是ngx_http_process_request_line.主要代码和解析如下. 判断是否超时,如果超

PHP json_decode 函数解析 json 结果为 NULL 的解决方法

在做网站 CMS 模块时,对于模块内容 content 字段,保存的是 json 格式的字符串,所以在后台进行模块内容的编辑操作 ( 取出保存的数据 ) 时,需要用到 json_decode() 函数. 但是在解析的时候,使用 json_decode() 函数解析的结果一直是 NULL,没有出现希望解析成的数组.下面是问题和分析: 1. 当输出 json 字符串时,代码和页面的显示内容分别是: echo $content = $res[0]['con']['content']; 只需要考虑 $c