static ngx_int_t
ngx_http_request_body_chunked_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, *out, *tl, **ll;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    rb = r->request_body;

    if (rb->rest == -1) {

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http request body chunked filter");

        rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
        if (rb->chunked == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

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

    out = NULL;
    ll = &out;

    for (cl = in; cl; cl = cl->next) {

        for ( ;; ) {

            ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                           "http body chunked buf "
                           "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
                           cl->buf->temporary, cl->buf->in_file,
                           cl->buf->start, cl->buf->pos,
                           cl->buf->last - cl->buf->pos,
                           cl->buf->file_pos,
                           cl->buf->file_last - cl->buf->file_pos);

            rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);

            if (rc == NGX_OK) {

                /* a chunk has been parsed successfully */

                clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

                if (clcf->client_max_body_size
                        && clcf->client_max_body_size
                        - r->headers_in.content_length_n < rb->chunked->size)
                {
                    ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                                  "client intended to send too large chunked "
                                  "body: %O+%O bytes",
                                  r->headers_in.content_length_n,
                                  rb->chunked->size);

                    r->lingering_close = 1;

                    return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
                }

                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;
                b->flush = r->request_body_no_buffering;

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

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

                if ((off_t) size > rb->chunked->size) {
                    cl->buf->pos += (size_t) rb->chunked->size;
                    r->headers_in.content_length_n += rb->chunked->size;
                    rb->chunked->size = 0;

                } else {
                    rb->chunked->size -= size;
                    r->headers_in.content_length_n += size;
                    cl->buf->pos = cl->buf->last;
                }

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

                continue;
            }

            if (rc == NGX_DONE) {

                /* a whole response has been parsed successfully */

                rb->rest = 0;

                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->last_buf = 1;

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

                break;
            }

            if (rc == NGX_AGAIN) {

                /* set rb->rest, amount of data we want to see next time */

                rb->rest = rb->chunked->length;

                break;
            }

            /* invalid */

            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "client sent invalid chunked body");

            return NGX_HTTP_BAD_REQUEST;
        }
    }

    rc = ngx_http_top_request_body_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;
}
// 处理确定长度的请求体数据,参数in是已经读取的数据链表
// 先看free里是否有空闲节点,有则直接使用
// 如果没有,就从内存池的空闲链表里获取
// 创建新的链表节点,加入到out链表里
// 这里只是指针操作,没有内存拷贝
// 调用请求体过滤链表,对数据进行过滤处理
// 实际上是ngx_http_request_body_save_filter
// 拷贝in链表里的buf到rb->bufs里,不是直接连接
// 最后把用完的ngx_chaint_t挂到free里供复用,提高效率
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;

    // -1表示无效,即还没有开始读取
    // 那么剩余字节数就是content_length_n
    if (rb->rest == -1) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http request body content length filter");

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

    out = NULL;
    ll = &out;

    // 遍历已经读取的数据链表
    // 创建新的链表节点,加入到out链表里
    // 这里只是指针操作,没有内存拷贝
    for (cl = in; cl; cl = cl->next) {

        // 已经读完,无剩余字节,那么就结束循环
        if (rb->rest == 0) {
            break;
        }

        // 先看free里是否有空闲节点,有则直接使用
        // 如果没有,就从内存池的空闲链表里获取
        // 最开始rb->free是空的,所以要从内存池里获取
        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;
        b->flush = r->request_body_no_buffering;

        // 计算此缓冲区里的数据长度
        size = cl->buf->last - cl->buf->pos;

        // 剩余的数据还很多
        // 这里处理的是in链表,不是out
        // 消费的是in链表里的缓冲区
        if ((off_t) size < rb->rest) {
            // 消费缓冲区里的数据
            cl->buf->pos = cl->buf->last;

            // 剩余字节数减少
            rb->rest -= size;

        } else {
            // 这里rest字节已经读取足够了

            // 消费缓冲区里的数据
            cl->buf->pos += (size_t) rb->rest;

            // 剩余数据全部读取完毕,rest=0
            rb->rest = 0;

            // 如果还有多余的数据也不再考虑,调整last
            b->last = cl->buf->pos;

            // 标记为最后一块数据,重要
            b->last_buf = 1;
        }

        // 加入链表
        *ll = tl;
        ll = &tl->next;
    }

    // 这里调用请求体过滤链表,对数据进行过滤处理
    // 实际上是ngx_http_request_body_save_filter

    // 从内存池里分配节点
    // 拷贝in链表里的buf到rb->bufs里,不是直接连接
    // 同样是指针操作,没有内存拷贝
    // 如果要求写磁盘文件,那么调用ngx_http_write_request_body
    rc = ngx_http_top_request_body_filter(r, out);

    // 用于处理请求体数据,更新free/busy几个链表指针
    // 先把out链表挂到busy指针上
    // 遍历busy链表
    // 缓冲区为空,说明可以复用,应该挂到free链表里
    // 把缓冲区复位,都指向start,即完全可用
    // 此节点不应该在busy里,从busy链表摘除
    // 加入到free链表里,供以后复用
    ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
                            (ngx_buf_tag_t) &ngx_http_read_client_request_body);

    return rc;
}
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) {
        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http request body content length filter");

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

    out = NULL;
    ll = &out;

    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;
        b->flush = r->request_body_no_buffering;

        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_top_request_body_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;
}
static ngx_int_t
ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
{ //in其实也是从r->request_body->buf中来的
    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

        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http request body content length filter");

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

    out = NULL;
    ll = &out;

    //把in中的所有数据节点数据连接在一起添加到out头中
    for (cl = in; cl; cl = cl->next) {//遍历r->request_body中的所有buf

        if (rb->rest == 0) {//表示包体数据已经处理完毕
            break;
        }

        tl = ngx_chain_get_free_buf(r->pool, &rb->free); //从free链表中poll中获取ngx_chain_t空间,如果free中为空,则直接创建
        if (tl == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b = tl->buf; //获取tl中的buf

        ngx_memzero(b, sizeof(ngx_buf_t));

        //b的相关成员指针指向in中的各个节点里面的对于成员,即新的b指向获取到的包体数据中的各个ngx_buf_t
        //b指向的数据和cl->buf指向的数据时一致的,最后实际读取到的数据的头尾用b指向
        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;
        b->flush = r->request_body_no_buffering;

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

        if ((off_t) size < rb->rest) { //说明数据还不够r->headers_in.content_length_n;
            cl->buf->pos = cl->buf->last;
            rb->rest -= size; //已经获取到size了,还差rb->rest才到content_length_n

        } else { //说明已经获取到了content_length_n这么多包体,也就是包体已经够了
            cl->buf->pos += (size_t) rb->rest; //注意这时候的last没有移动,如果头部行content-length:len中的len小于实际携带的包体数据,就会造成pos小于last
            rb->rest = 0;//表示包体有这么多了
            b->last = cl->buf->pos; //实际读到的数据比我们期望的rest数据多,因此我们截取实际需要的数据即可
            b->last_buf = 1; //标记该buf是组成包体数据的buf数组中的最后一个ngx_buf_t
        }

        *ll = tl;
        ll = &tl->next; //前面创建的所有tl(ngx_chain_t)通过next连接在一起,所有这些节点的头部是前面的out
    }

//把in表中的数据(通过从新创建ngx_buf_t指向in表中各个数据的成员)连接到r->request_body->bufs中,这样所有的out数据都会添加到r->request_body->bufs数组中
//通过新创建的ngx_chain_t(之前out中的ngx_chain_t就通过下面的ngx_chain_update_chains进行回收)中的各个指针来执行新读取到的out数据,ngx_http_request_body_save_filter,通过该函数后所有的out数据都连接到rb->bufs中缓存了
    rc = ngx_http_top_request_body_filter(r, out); //ngx_http_request_body_save_filter


    //rb中的bufs链表中的成员中的各个指针指向读取到的原始数据位置(如pos指向读取到数据的头,last指向读取到数据的尾部)
    //rb->busy最初是直接从out中拷贝的,指向的数据空间最初与bufs是一样的,但是一旦http模块从网络读取到的数据中解析出一部分数据,那么free中成员的各个指针就会移动,例如pos会
    //向last方向移动,直到pos=list,这时候busy中的这个ngx_buf_t节点成员就可以从busy链表中取出,然后添加到free链表中
    ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
                            (ngx_buf_tag_t) &ngx_http_read_client_request_body);

    return rc;
}