static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
    off_t                      rest;
    size_t                     size;
    ssize_t                    n;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t               *cl, out;
    ngx_connection_t          *c;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    c = r->connection;
    rb = r->request_body;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http read client request body");

    for ( ;; ) {
        for ( ;; ) {
            if (rb->buf->last == rb->buf->end) {

                if (rb->buf->pos != rb->buf->last) {

                    /* pass buffer to request body filter chain */

                    out.buf = rb->buf;
                    out.next = NULL;

                    rc = ngx_http_request_body_filter(r, &out);

                    if (rc != NGX_OK) {
                        return rc;
                    }

                } else {

                    /* update chains */

                    rc = ngx_http_request_body_filter(r, NULL);

                    if (rc != NGX_OK) {
                        return rc;
                    }
                }

                if (rb->busy != NULL) {
                    if (r->request_body_no_buffering) {
                        if (c->read->timer_set) {
                            ngx_del_timer(c->read);
                        }

                        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                            return NGX_HTTP_INTERNAL_SERVER_ERROR;
                        }

                        return NGX_AGAIN;
                    }

                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                rb->buf->pos = rb->buf->start;
                rb->buf->last = rb->buf->start;
            }

            size = rb->buf->end - rb->buf->last;
            rest = rb->rest - (rb->buf->last - rb->buf->pos);

            if ((off_t) size > rest) {
                size = (size_t) rest;
            }

            n = c->recv(c, rb->buf->last, size);

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                           "http client request body recv %z", n);

            if (n == NGX_AGAIN) {
                break;
            }

            if (n == 0) {
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client prematurely closed connection");
            }

            if (n == 0 || n == NGX_ERROR) {
                c->error = 1;
                return NGX_HTTP_BAD_REQUEST;
            }

            rb->buf->last += n;
            r->request_length += n;

            if (n == rest) {
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

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

            if (rb->buf->last < rb->buf->end) {
                break;
            }
        }

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                       "http client request body rest %O", rb->rest);

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

        if (!c->read->ready) {

            if (r->request_body_no_buffering
                    && rb->buf->pos != rb->buf->last)
            {
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
            ngx_add_timer(c->read, clcf->client_body_timeout);

            if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            return NGX_AGAIN;
        }
    }

    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }

    if (rb->temp_file || r->request_body_in_file_only) {

        /* save the last part */

        if (ngx_http_write_request_body(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        if (rb->temp_file->file.offset != 0) {

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

            b = cl->buf;

            ngx_memzero(b, sizeof(ngx_buf_t));

            b->in_file = 1;
            b->file_last = rb->temp_file->file.offset;
            b->file = &rb->temp_file->file;

            rb->bufs = cl;

        } else {
            rb->bufs = NULL;
        }
    }

    if (!r->request_body_no_buffering) {
        r->read_event_handler = ngx_http_block_reading;
        rb->post_handler(r);
    }

    return NGX_OK;
}
Ejemplo n.º 2
0
static ngx_int_t
ngx_http_do_read_non_buffered_client_request_body(ngx_http_request_t *r)
{
    off_t                                  rest;
    size_t                                 size;
    ssize_t                                n;
    ngx_int_t                              rc;
    ngx_chain_t                            out;
    ngx_connection_t                      *c;
    ngx_http_request_body_t               *rb;
    ngx_http_core_loc_conf_t              *clcf;
    ngx_http_request_body_non_buffered_t  *nb;

    c = r->connection;
    rb = r->request_body;
    nb = rb->non_buffered;
    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http read non buffered client request body");

    for ( ;; ) {
        for ( ;; ) {
            if (rb->buf->last == rb->buf->end) {

                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }

                rb->buf->pos = rb->buf->start;
                rb->buf->last = rb->buf->start;

            }

            if (rb->bufs) {

                /* copy to non_buffered buffers */

                rc = ngx_http_copy_non_buffered_request_body(r);

                if (rc == NGX_DECLINED) {

                    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                                   "http no buffered client request body "
                                   "request_length: %O, rest: %uz, "
                                   "postpone_size: %O",
                                   r->request_length, rb->rest,
                                   nb->postpone_size);

                    if (nb->postpone_size
                        >= (off_t) clcf->client_body_postpone_size)
                    {
                        if (nb->buffered) {
                            nb->flush = 1;
                            goto read_ok;
                        }
                    }

                    return NGX_DECLINED;

                } else if (rc == NGX_ERROR) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                /* update chains */

                rc = ngx_http_request_body_filter(r, NULL);

                if (rc != NGX_OK) {
                    return rc;
                }

                if (rb->busy != NULL) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                               "http no buffered client request body "
                               "request_length: %O, rest: %uz, "
                               "postpone_size: %O",
                               r->request_length, rb->rest,
                               nb->postpone_size);

                if (nb->postpone_size
                    >= (off_t) clcf->client_body_postpone_size)
                {
                    nb->flush = 1;

                    if (nb->buffered) {
                        goto read_ok;
                    }

                    return NGX_DECLINED;
                }
            }

            size = rb->buf->end - rb->buf->last;
            rest = rb->rest - (rb->buf->last - rb->buf->pos);

            if ((off_t) size > rest) {
                size = (size_t) rest;
            }

            n = c->recv(c, rb->buf->last, size);

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                           "http client non buffered request body recv %z", n);

            if (n == NGX_AGAIN) {

                if (nb->postpone_size
                    >= (off_t) clcf->client_body_postpone_size) {

                    if (nb->buffered) {
                        nb->flush = 1;
                        goto read_ok;
                    }
                }

                break;
            }

            if (n == 0) {
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client prematurely closed connection");
            }

            if (n == 0 || n == NGX_ERROR) {
                c->error = 1;
                return NGX_HTTP_BAD_REQUEST;
            }

            rb->buf->last += n;
            r->request_length += n;

            if (n == rest) {
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

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

            if (rb->buf->last < rb->buf->end) {
                break;
            }
        }

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                       "http client non buffered request body rest %O",
                       rb->rest);

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

        if (!c->read->ready) {
            ngx_add_timer(c->read, clcf->client_body_timeout);

            if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            return NGX_AGAIN;
        }
    }

    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }

    /* save the last part */

    rc = ngx_http_copy_non_buffered_request_body(r);
    ngx_log_debug3(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http no buffered client request body "
                   "request_length: %O, rest: %uz, postpone_size: %O",
                   r->request_length, rb->rest, nb->postpone_size);

    if (rc == NGX_DECLINED) {
        return NGX_DECLINED;
    } else if (rc == NGX_ERROR) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

read_ok:

    r->read_event_handler = ngx_http_block_reading;

    nb->buffered = 0;

    return NGX_OK;
}
ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t *r,
                                  ngx_http_client_body_handler_pt post_handler)
{
    size_t                     preread;
    ssize_t                    size;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t                out, *cl;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    r->main->count++;



    if (r != r->main || r->request_body || r->discard_body) {
        r->request_body_no_buffering = 0;
        post_handler(r);
        return NGX_OK;
    }

    if (ngx_http_test_expect(r) != NGX_OK) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    if (r->request_body_no_buffering) {
        r->request_body_in_file_only = 0;
    }

    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    if (rb == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->free = NULL;
     *     rb->busy = NULL;
     *     rb->chunked = NULL;
     */

    rb->rest = -1;
    rb->post_handler = post_handler;

    r->request_body = rb;

    if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
        r->request_body_no_buffering = 0;
        post_handler(r);
        return NGX_OK;
    }

    preread = r->header_in->last - r->header_in->pos;

    if (preread) {

        /* there is the pre-read part of the request body */

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http client request body preread %uz", preread);

        out.buf = r->header_in;
        out.next = NULL;

        rc = ngx_http_request_body_filter(r, &out);

        if (rc != NGX_OK) {
            goto done;
        }

        r->request_length += preread - (r->header_in->last - r->header_in->pos);

        if (!r->headers_in.chunked
                && rb->rest > 0
                && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
        {
            /* the whole request body may be placed in r->header_in */

            b = ngx_calloc_buf(r->pool);
            if (b == NULL) {
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                goto done;
            }

            b->temporary = 1;
            b->start = r->header_in->pos;
            b->pos = r->header_in->pos;
            b->last = r->header_in->last;
            b->end = r->header_in->end;

            rb->buf = b;

            r->read_event_handler = ngx_http_read_client_request_body_handler;
            r->write_event_handler = ngx_http_request_empty_handler;

            rc = ngx_http_do_read_client_request_body(r);
            goto done;
        }

    } else {
        /* set rb->rest */

        if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            goto done;
        }
    }

    if (rb->rest == 0) {
        /* the whole request body was pre-read */

        if (r->request_body_in_file_only) {
            if (ngx_http_write_request_body(r) != NGX_OK) {
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                goto done;
            }

            if (rb->temp_file->file.offset != 0) {

                cl = ngx_chain_get_free_buf(r->pool, &rb->free);
                if (cl == NULL) {
                    rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    goto done;
                }

                b = cl->buf;

                ngx_memzero(b, sizeof(ngx_buf_t));

                b->in_file = 1;
                b->file_last = rb->temp_file->file.offset;
                b->file = &rb->temp_file->file;

                rb->bufs = cl;

            } else {
                rb->bufs = NULL;
            }
        }

        r->request_body_no_buffering = 0;

        post_handler(r);

        return NGX_OK;
    }

    if (rb->rest < 0) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "negative request body rest");
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    size = clcf->client_body_buffer_size;
    size += size >> 2;

    /* TODO: honor r->request_body_in_single_buf */

    if (!r->headers_in.chunked && rb->rest < size) {
        size = (ssize_t) rb->rest;

        if (r->request_body_in_single_buf) {
            size += preread;
        }

    } else {
        size = clcf->client_body_buffer_size;
    }

    rb->buf = ngx_create_temp_buf(r->pool, size);
    if (rb->buf == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    r->read_event_handler = ngx_http_read_client_request_body_handler;
    r->write_event_handler = ngx_http_request_empty_handler;

    rc = ngx_http_do_read_client_request_body(r);

done:

    if (r->request_body_no_buffering
            && (rc == NGX_OK || rc == NGX_AGAIN))
    {
        if (rc == NGX_OK) {
            r->request_body_no_buffering = 0;

        } else {
            /* rc == NGX_AGAIN */
            r->reading_body = 1;
        }

        r->read_event_handler = ngx_http_block_reading;
        post_handler(r);
    }

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        r->main->count--;
    }

    return rc;
}
Ejemplo n.º 4
0
static ngx_int_t
ngx_http_read_non_buffered_client_request_body(ngx_http_request_t *r,
    ngx_http_client_body_handler_pt post_handler)
{
    size_t                                 size;
    size_t                                 preread;
    ngx_int_t                              rc;
    ngx_chain_t                            out;
    ngx_http_request_body_t               *rb;
    ngx_http_core_loc_conf_t              *clcf;
    ngx_http_request_body_non_buffered_t  *nb;

    rb = r->request_body;
    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    nb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_non_buffered_t));
    if (nb == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    rb->non_buffered = nb;
    nb->last_out = &nb->bufs;
    nb->read_handler = ngx_http_do_read_non_buffered_client_request_body;
    nb->update_handler = ngx_http_request_body_update_chains;
    nb->tag = (ngx_buf_tag_t *) nb->read_handler;

    preread = r->header_in->last - r->header_in->pos;

    if (preread) {

        /* there is the pre-read part of the request body */

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http client no buffered request body preread %uz",
                       preread);

        out.buf = r->header_in;
        out.next = NULL;

        rc = ngx_http_request_body_filter(r, &out);

        if (rc != NGX_OK) {
            goto done;
        }

        r->request_length += preread - (r->header_in->last - r->header_in->pos);

        if (!r->headers_in.chunked
            && rb->rest > 0
            && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
        {
            /* the whole request body may be placed in r->header_in */

            rb->buf = r->header_in;
            r->read_event_handler =
                ngx_http_read_non_buffered_client_request_body_handler;
            r->write_event_handler = ngx_http_request_empty_handler;

            rc = ngx_http_do_read_non_buffered_client_request_body(r);
            goto done;
        }

    } else {
        /* set rb->rest */

        if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            goto done;
        }
    }

    if (rb->rest == 0) {

        ngx_http_copy_non_buffered_request_body(r);
        /* the whole request body was pre-read */
        rb->post_handler(r);

        return NGX_OK;
    }

    if (rb->rest < 0) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "negative request body rest");
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    size = clcf->client_body_buffer_size;
    size += size >> 2;

    if (!r->headers_in.chunked && (rb->rest < (off_t) size)) {
        size = (ssize_t) rb->rest;

        if (r->request_body_in_single_buf) {
            size += preread;
        }

    } else {
        size = clcf->client_body_buffer_size;
    }

    rb->buf = ngx_create_temp_buf(r->pool, size);
    if (rb->buf == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    r->read_event_handler =
        ngx_http_read_non_buffered_client_request_body_handler;
    r->write_event_handler = ngx_http_request_empty_handler;

    nb->buffered = 1;
    nb->postpone_size = preread;

    rc = ngx_http_do_read_non_buffered_client_request_body(r);

done:

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        r->main->count--;
    }

    if (rc == NGX_AGAIN) {

        if (nb->buffered) {
            r->read_event_handler =
                ngx_http_read_non_buffered_client_request_body_handler;
        }

    } else if (rc == NGX_OK || rc == NGX_DECLINED) {
        rb->post_handler(r);
    }

    return rc;
}
// 要求nginx读取请求体,传入一个post_handler
// 引用计数器增加,表示此请求还有关联的操作,不能直接销毁
// 所以post_handler里需要调用ngx_http_finalize_request来结束请求
ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t *r,
    ngx_http_client_body_handler_pt post_handler)
{
    size_t                     preread;
    ssize_t                    size;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t                out;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    // 引用计数器增加,表示此请求还有关联的操作,不能直接销毁
    r->main->count++;

    // 删除了原spdy的代码
    // 子请求不与客户端直接通信,不会有请求体的读取
    // 已经设置了discard_body标志,表示已经开始丢弃请求体
    // request_body指针不空,表示已经开始读取请求体
    if (r != r->main || r->request_body || r->discard_body) {
        r->request_body_no_buffering = 0;

        // 不需要再读取数据了,直接回调handler
        // 相当于触发写事件,继续之前中断的处理流程
        post_handler(r);

        return NGX_OK;
    }

#if (NGX_HTTP_V2)
    if (r->stream) {
        rc = ngx_http_v2_read_request_body(r, post_handler);
        goto done;
    }
#endif

    // 如果要求不缓存请求体数据
    // 那么请求体就不会存在磁盘文件里
    // if (r->request_body_no_buffering) {
    //     r->request_body_in_file_only = 0;
    // }

    if (ngx_http_test_expect(r) != NGX_OK) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    // 创建请求体数据结构体
    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    if (rb == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->free = NULL;
     *     rb->busy = NULL;
     *     rb->chunked = NULL;
     */

    // -1表示未初始化
    rb->rest = -1;

    // 当读取完毕后的回调函数
    // 即ngx_http_read_client_request_body的第二个参数
    rb->post_handler = post_handler;

    r->request_body = rb;

    // 数据长度不对,直接回调handler
    if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
        r->request_body_no_buffering = 0;

        // 不需要再读取数据了,直接回调handler
        // 相当于触发写事件,继续之前中断的处理流程
        post_handler(r);
        return NGX_OK;
    }

    // 查看已经读取的数据,即缓冲区里头之后的数据
    preread = r->header_in->last - r->header_in->pos;

    // 已经读取了部分body
    if (preread) {

        /* there is the pre-read part of the request body */

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http client request body preread %uz", preread);

        // 链表的第一个节点指向r->header_in
        out.buf = r->header_in;
        out.next = NULL;

        // 分为chunked和确定长度两种
        // 简单起见只研究确定长度,即ngx_http_request_body_length_filter
        //
        // 处理确定长度的请求体数据,参数是已经读取的数据链表
        // 先看free里是否有空闲节点,有则直接使用
        // 如果没有,就从内存池的空闲链表里获取
        // 这里只是指针操作,没有内存拷贝
        // 调用请求体过滤链表,对数据进行过滤处理
        // 实际上是ngx_http_request_body_save_filter
        // 拷贝in链表里的buf到rb->bufs里,不是直接连接
        // 最后把用完的ngx_chaint_t挂到free里供复用,提高效率
        rc = ngx_http_request_body_filter(r, &out);

        if (rc != NGX_OK) {
            goto done;
        }

        // 增加已经读取的数据长度,但因为
        // preread = r->header_in->last - r->header_in->pos;
        // 实际上是没有增加
        r->request_length += preread - (r->header_in->last - r->header_in->pos);

        // 不是chunked,有确定长度
        // 还有剩余数据要读取
        // header_in缓冲区里还有空间,足够容纳rest字节的数据
        // 所以不需要再另外分配内存了,header_in缓冲区可以存下所有请求数据
        // 特别优化处理
        // 设置读事件handler为ngx_http_read_client_request_body_handler
        // 要求继续读取
        if (!r->headers_in.chunked
            && rb->rest > 0
            && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
        {
            /* the whole request body may be placed in r->header_in */

            // 创建一个缓冲区对象
            b = ngx_calloc_buf(r->pool);
            if (b == NULL) {
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                goto done;
            }

            // 指向header_in里的请求头后的所有空间
            b->temporary = 1;
            b->start = r->header_in->pos;
            b->pos = r->header_in->pos;
            b->last = r->header_in->last;
            b->end = r->header_in->end;

            // 请求体使用此缓冲区
            rb->buf = b;

            // 设置读事件handler为ngx_http_read_client_request_body_handler
            // 注意,读事件的handler实际上是ngx_http_request_handler
            // 但最终会调用r->read_event_handler

            // 读取请求体的handler
            // 首先检查超时,实际功能在ngx_http_do_read_client_request_body
            r->read_event_handler = ngx_http_read_client_request_body_handler;

            // 写事件阻塞
            r->write_event_handler = ngx_http_request_empty_handler;

            // 在rb->buf里读取数据
            // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数
            rc = ngx_http_do_read_client_request_body(r);
            goto done;
        }

        // 这里表示rest==0,一次就已经全部读取了header+body
        // 不需要再关心读事件
        // 走下面的if (rb->rest == 0)

    } else {
        /* set rb->rest */
        // 没有读取body数据

        // 分为chunked和确定长度两种
        // 简单起见只研究确定长度,即ngx_http_request_body_length_filter
        // 因为参数是null,所以函数里只会设置rb->rest,即剩余要读取的字节数
        if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            goto done;
        }

        // 走下面的clcf = ngx_http_get_module_loc_conf
    }

    // rb->rest == 0 body已经读取完毕
    // preread >= content length
    if (rb->rest == 0) {
        /* the whole request body was pre-read */

        // body已经读取完毕,可以调用post_handler继续处理流程
        r->request_body_no_buffering = 0;
        post_handler(r);
        return NGX_OK;
    }

    // 错误,负数body
    if (rb->rest < 0) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "negative request body rest");
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    // 没读到body数据,但知道了确定的body长度

    // 取模块的loc配置
    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    // 查看body的缓冲区大小
    size = clcf->client_body_buffer_size;

    // 增加1/4的长度
    size += size >> 2;

    /* TODO: honor r->request_body_in_single_buf */

    // 长度确定,且在size里可以容纳剩余字节数
    if (!r->headers_in.chunked && rb->rest < size) {
        size = (ssize_t) rb->rest;

        // 要求body在一块缓冲区里,长度增加
        if (r->request_body_in_single_buf) {
            size += preread;
        }

    } else {
        size = clcf->client_body_buffer_size;
    }

    // 内存池里分配一个缓冲区,大小为size
    rb->buf = ngx_create_temp_buf(r->pool, size);
    if (rb->buf == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    // 设置读事件handler为ngx_http_read_client_request_body_handler
    // 注意,读事件的handler实际上是ngx_http_request_handler
    // 但最终会调用r->read_event_handler

    // 读取请求体的handler
    // 首先检查超时,实际功能在ngx_http_do_read_client_request_body
    r->read_event_handler = ngx_http_read_client_request_body_handler;

    // 写事件阻塞
    r->write_event_handler = ngx_http_request_empty_handler;

    // 在rb->buf里读取数据
    // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数
    rc = ngx_http_do_read_client_request_body(r);

done:

    if (r->request_body_no_buffering
        && (rc == NGX_OK || rc == NGX_AGAIN))
    {
        if (rc == NGX_OK) {
            r->request_body_no_buffering = 0;

        } else {
            /* rc == NGX_AGAIN */
            r->reading_body = 1;
        }

        r->read_event_handler = ngx_http_block_reading;
        post_handler(r);
    }

    // 出错,减少引用计数
    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        r->main->count--;
    }

    // 返回错误码
    return rc;
}
// 在rb->buf里读取数据
// 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数
static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
    off_t                      rest;
    size_t                     size;
    ssize_t                    n;
    ngx_int_t                  rc;
    ngx_chain_t                out;
    ngx_connection_t          *c;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    // 获取读事件相关的连接对象和请求对象
    c = r->connection;
    rb = r->request_body;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http read client request body");

    for ( ;; ) {

        // 在rb->buf里读取数据
        // 如果已经读完了所有剩余数据,那么就挂到bufs指针,结束函数
        for ( ;; ) {

            // 检查请求体结构里的缓冲区
            // 是否已经满了
            if (rb->buf->last == rb->buf->end) {

                if (rb->buf->pos != rb->buf->last) {

                    /* pass buffer to request body filter chain */

                    out.buf = rb->buf;
                    out.next = NULL;

                    rc = ngx_http_request_body_filter(r, &out);

                    if (rc != NGX_OK) {
                        return rc;
                    }

                } else {

                    /* update chains */

                    rc = ngx_http_request_body_filter(r, NULL);

                    if (rc != NGX_OK) {
                        return rc;
                    }
                }

                if (rb->busy != NULL) {
                    if (r->request_body_no_buffering) {
                        if (c->read->timer_set) {
                            ngx_del_timer(c->read);
                        }

                        if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                            return NGX_HTTP_INTERNAL_SERVER_ERROR;
                        }

                        return NGX_AGAIN;
                    }

                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                rb->buf->pos = rb->buf->start;
                rb->buf->last = rb->buf->start;
            }   // if (rb->buf->last == rb->buf->end)

            // 缓冲区没有满,还可以存放数据

            // 计算剩余空间的大小
            size = rb->buf->end - rb->buf->last;

            // 减去缓冲区里已经读取的长度
            rest = rb->rest - (rb->buf->last - rb->buf->pos);

            // 计算实际应该读取的长度,两者的小值
            if ((off_t) size > rest) {
                size = (size_t) rest;
            }

            // 调用recv,读取数据,放入缓冲区
            // <0 出错, =0 连接关闭, >0 接收到数据大小
            n = c->recv(c, rb->buf->last, size);

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                           "http client request body recv %z", n);

            // again,暂时无数据,中断内层循环
            if (n == NGX_AGAIN) {
                break;
            }

            // 读到了0字节,即连接被客户端关闭,client abort
            if (n == 0) {
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client prematurely closed connection");
            }

            // 读到了0字节,即连接被客户端关闭,client abort
            if (n == 0 || n == NGX_ERROR) {
                c->error = 1;
                return NGX_HTTP_BAD_REQUEST;
            }

            // n>0,读取了一些数据

            // 调整buf的last指针,有效数据增加
            rb->buf->last += n;

            // 总请求数据长度增加
            r->request_length += n;

            // 已经读完了所有剩余数据
            if (n == rest) {
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                // 分为chunked和确定长度两种
                // 简单起见只研究确定长度,即ngx_http_request_body_length_filter
                //
                // 处理确定长度的请求体数据,参数是已经读取的数据链表
                // 先看free里是否有空闲节点,有则直接使用
                // 如果没有,就从内存池的空闲链表里获取
                // 这里只是指针操作,没有内存拷贝
                // 调用请求体过滤链表,对数据进行过滤处理
                // 实际上是ngx_http_request_body_save_filter
                // 拷贝in链表里的buf到rb->bufs里,不是直接连接
                // 最后把用完的ngx_chaint_t挂到free里供复用,提高效率
                rc = ngx_http_request_body_filter(r, &out);

                // 出错则结束函数
                if (rc != NGX_OK) {
                    return rc;
                }
            }

            // ngx_http_request_body_filter里计算了rest剩余字节数
            // 读取完毕则结束内层循环
            if (rb->rest == 0) {
                break;
            }

            // 缓冲区没有用完,也结束内层循环
            // 在后面调用ngx_http_request_body_filter处理读取到的数据
            if (rb->buf->last < rb->buf->end) {
                break;
            }

            // 回到内层循环开头,即缓冲区已满

        }   // 内层for

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                       "http client request body rest %O", rb->rest);

        // ngx_http_request_body_filter里计算了rest剩余字节数
        // 读取完毕则结束外层循环
        if (rb->rest == 0) {
            break;
        }

        // 还有数据要读,且已经无数据可读
        if (!c->read->ready) {

            if (r->request_body_no_buffering
                && rb->buf->pos != rb->buf->last)
            {
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                // 分为chunked和确定长度两种
                // 简单起见只研究确定长度,即ngx_http_request_body_length_filter
                //
                // 处理确定长度的请求体数据,参数是已经读取的数据链表
                // 先看free里是否有空闲节点,有则直接使用
                // 如果没有,就从内存池的空闲链表里获取
                // 这里只是指针操作,没有内存拷贝
                // 调用请求体过滤链表,对数据进行过滤处理
                // 实际上是ngx_http_request_body_save_filter
                // 拷贝in链表里的buf到rb->bufs里,不是直接连接
                // 最后把用完的ngx_chaint_t挂到free里供复用,提高效率
                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

            // 读取body的超时时间
            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
            ngx_add_timer(c->read, clcf->client_body_timeout);

            // 读事件加入epoll,可读会调用ngx_http_read_client_request_body_handler
            // 即再次进入本函数
            if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            return NGX_AGAIN;
        }
    }   // 外层for

    // 只有rest==0,即读取完毕才会走到这里

    if (c->read->timer_set) {
        ngx_del_timer(c->read);
    }

    // 要求缓存请求体
    if (!r->request_body_no_buffering) {
        r->read_event_handler = ngx_http_block_reading;

        // body已经读取完毕,可以调用post_handler继续处理流程
        rb->post_handler(r);
    }

    return NGX_OK;
}
//只有在连接后端服务器的时候才会读取客户端请求包体,见ngx_http_xxx_handler(proxy fastcgi等)
//post_handler在ngx_http_do_read_client_request_body接收完所有包体后执行,或者在本函数能读取完包体后也会执行
//post_handler方法被回调时,务必调用类似ngx_http_finalize_request的方法去结束请求,否则引用计数会始终无法清零,从而导致请求无法释放。
ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t *r, ngx_http_client_body_handler_pt post_handler)
{
    size_t                     preread;
    ssize_t                    size;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t                out, *cl;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    /*
     首先把该请求对应的原始请求的引用计数加1。这同时是在要求每一个HTTP模块在传入的post_handler方法被回调时,务必调用类似
     ngx_http_finalize_request的方法去结束请求,否则引用计数会始终无法清零,从而导致请求无法释放。
     */
    r->main->count++;

#if (NGX_HTTP_SPDY)
    if (r->spdy_stream && r == r->main) {
        r->request_body_no_buffering = 0;
        rc = ngx_http_spdy_read_request_body(r, post_handler);
        goto done;
    }
#endif

    /*
    检查请求ngx_http_request_t结构体中的request_body成员,如果它已经被分配过了,证明已经读取过HTTP包体了,不需要再次读取一遍;
再检查请求ngx_http_request_t结构体中的discard_body标志位,如果discard_body为1,则证明曾经执行过丢弃包体的方法,现在包体正在被丢弃中。
只有这两个条件都不满足,才说明真正需要接收HTTP包体。
     */
    if (r != r->main || r->request_body || r->discard_body) {
        r->request_body_no_buffering = 0;
        post_handler(r); //直接执行各HTTP模块提供的post_handler回调方法
        return NGX_OK;
    }

    if (ngx_http_test_expect(r) != NGX_OK) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    if (r->request_body_no_buffering) { //如果不缓存包体,request_body_no_buffering和request_body_in_file_only是互斥的
        r->request_body_in_file_only = 0; //设置为不缓存包体,则就不能把包体写道文件中
    }

    /* 分配请求的ngx_http_request_t结构体中的request_body成员(之前request_body是NULL空指针),准备接收包体。 */
    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    if (rb == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->free = NULL;
     *     rb->busy = NULL;
     *     rb->chunked = NULL;
     */

    rb->rest = -1;
    rb->post_handler = post_handler;

    r->request_body = rb; //把创建的ngx_http_request_body_t空间赋值给request_body

    /* 检查请求的content-length头部,如果指定了包体长度的content-length字段小于或等于0,当然不用继续接收包体:
    如果content-length大于0,则意味着继续执行,但HTTP模块定义的post_handler方法不会知道在哪一次事件的触发中会被回调,
    所以先把它设置到request_body结构体的post_handler成员中。 */
    if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
        r->request_body_no_buffering = 0;
        post_handler(r);
        return NGX_OK;
    }

    /*
     * 接收HTTP头部的流程中,是有可能接收到HTTP包体的。
     * 首先我们需要检查在header_in缓冲区中已经接收到的包体长度,确定其是否大于或者等于content-length头部指定的长度,
     * 如果大干或等于则说明已经接收到完整的包体
     */
    preread = r->header_in->last - r->header_in->pos;

    if (preread) { //注意在ngx_http_wait_request_handler中第一次读的时候默认是读1024字节,有可能ngx_http_wait_request_handler已经把包体读了

        /* there is the pre-read part of the request body */

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
                       "http client request body preread %uz", preread);

        out.buf = r->header_in;//
        out.next = NULL;

        //把最新读取到的buf数据添加到r->request_body->bufs中,并且让free指向该bufs中所有数据中已经解析了的数据节点信息(重复利用ngx_buf_t)
        //busy链表中的ngx_buf_t节点指向bufs中所有数据中还没有解析完毕的数据
        rc = ngx_http_request_body_filter(r, &out);

        if (rc != NGX_OK) {
            goto done;
        }

        r->request_length += preread - (r->header_in->last - r->header_in->pos);

        /* 当上述条件不满足时,再检查header_in缓冲区里的剩余空闲空间是否可以存放下全部的包体(content-length头部指定),如果可以,就不用分配新的包体缓冲区浪费内存了 */
        if (!r->headers_in.chunked
            && rb->rest > 0 //还需要读取rb->rest才能保证包体读完
            && rb->rest <= (off_t) (r->header_in->end - r->header_in->last)) //判断header_in指向的剩余未用空间是否足够存取剩余的rest字节数据
        {
            /* the whole request body may be placed in r->header_in */
            //header_in中剩余的未用空间足够,例如还差rest = 1000字节才能读取完包体,但是header_in中剩余空间end - last超过1000,则不需要从新开辟空间
            //直接使用header_in剩余空间,开辟新的ngx_buf_t空间,使用新的ngx_buf_t中的各个指针指向header_in中剩余未用空间,用来继续读取
            b = ngx_calloc_buf(r->pool);
            if (b == NULL) {
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                goto done;
            }

            b->temporary = 1;
            b->start = r->header_in->pos;
            b->pos = r->header_in->pos;
            b->last = r->header_in->last;
            b->end = r->header_in->end;

            rb->buf = b;

            r->read_event_handler = ngx_http_read_client_request_body_handler;
            r->write_event_handler = ngx_http_request_empty_handler;


            rc = ngx_http_do_read_client_request_body(r);
            goto done;
        }

    } else {
        /* set rb->rest */

        if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            goto done;
        }
    }

    //包体一次读取完毕
    if (rb->rest == 0) {
        /* the whole request body was pre-read */

        //如果配置"client_body_in_file_only" on | clean 表示包体存储在磁盘文件中
        if (r->request_body_in_file_only) {
            if (ngx_http_write_request_body(r) != NGX_OK) {
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                goto done;
            }

            if (rb->temp_file->file.offset != 0) {

                cl = ngx_chain_get_free_buf(r->pool, &rb->free);
                if (cl == NULL) {
                    rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
                    goto done;
                }

                b = cl->buf;

                ngx_memzero(b, sizeof(ngx_buf_t));

                b->in_file = 1;
                b->file_last = rb->temp_file->file.offset;
                b->file = &rb->temp_file->file;

                rb->bufs = cl; //如果包体存入临时文件中,则读取包体完成后,bufs指向的ngx_chain_t中的各个指针指向文件中的相关偏移

            } else {
                rb->bufs = NULL;
            }
        }

        r->request_body_no_buffering = 0;

        post_handler(r);

        return NGX_OK;
    }

    //包体一次没有读取完毕

    if (rb->rest < 0) {
        ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
                      "negative request body rest");
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    size = clcf->client_body_buffer_size;
    size += size >> 2; //实际上就是四分之五5/4个client_body_buffer_size

    /* TODO: honor r->request_body_in_single_buf */
    //走到这里之前至少在ngx_http_wait_request_handler函数中读取过一次,也就是读取头部的时候,可能会读取一部分包体,在读取头部的时候
    //读取的最大报文长度为client_header_buffer_size,所以包体有可能在那里读取后处理了头部行后,会走到本函数处理包体,这时候可能包体没有读完

    if (!r->headers_in.chunked && rb->rest < size) {
        size = (ssize_t) rb->rest;

        if (r->request_body_in_single_buf) { //需要缓存到同一个buf中,那么开辟的空间就必须一次分配完,这样可以存储后面所有的。
            size += preread; //如果是把读取的网络数据存到同一个single buffer中,则本次读到preread字节,但是还有size字节没读,所以需要相加,表示一共需要这么多空间,
        }

    } else {
        size = clcf->client_body_buffer_size; //如果不是缓存到同一个buf,则一次最多开辟这么多空间,这样可能需要多个buf才能读取完
    }

    /*
    说明确实需要分配用于接收包体的缓冲区了。缓冲区长度由nginx.conf丈件中的client_body_buffer_size配置项指定,缓冲区就在ngx_http_request_body_t
    结构体的buf成员中存放着,同时,bufs和to_ write这两个缓冲区链表首部也指向该buf。
     */

    rb->buf = ngx_create_temp_buf(r->pool, size); //这个是为下次读取准备的
    if (rb->buf == NULL) {
        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
        goto done;
    }

    /*
     设置请求ngx_http_request_t结构体的read_ event_ handler成员为上面介绍过的ngx_http_read_client_request_body_handler方法,
     它意味着如果epoll再次检测到可读事件或者读事件的定时器超时,HTTP框架将调用ngx_http_read_client_request_body_handler方法处理
     */
    r->read_event_handler = ngx_http_read_client_request_body_handler;
    r->write_event_handler = ngx_http_request_empty_handler;

    /*
    调用ngx_http_do_read_client_request_body方法接收包体。该方法的意义在于把客户端与Nginx之间TCP连接上套接字缓冲区中的当前字符流全
    部读出来,并判断是否需要写入文件,以及是否接收到全部的包体,同时在接收到完整的包体后激活post_handler回调方法
     */
    rc = ngx_http_do_read_client_request_body(r);//这里面添加ngx_handle_read_event的时候,对应的handler为ngx_http_read_client_request_body_handler

done:

    if (r->request_body_no_buffering
        && (rc == NGX_OK || rc == NGX_AGAIN))
    {
        if (rc == NGX_OK) {
            r->request_body_no_buffering = 0;

        } else {
            /* rc == NGX_AGAIN */
            r->reading_body = 1;
        }

        r->read_event_handler = ngx_http_block_reading;
        post_handler(r);
    }

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {//如果返回出错
        r->main->count--; //该函数处理结束后-1,因为该函数开始处理的时候有+1
    }

    return rc;
}
/*
调用ngx_http_do_read_client_request_body方法接收包体。该方法的意义在于把客户端与Nginx之间TCP连接上套接字缓冲区中的当前字符流全
部读出来,并判断是否需要写入文件,以及是否接收到全部的包体,同时在接收到完整的包体后激活post_handler回调方法
负责具体的读取包体工作,该函数会在for循环中会反复读直到包体读取完毕,如果内核已经没有数据并且包体还没有读完,则添加读事件,并退出循环,这样HTTP模块还能继续作用其他功能,避免阻塞
读取的时候一个buf装满后,会把buf中存储的数据写到临时文件中(不管有没有配置request_body_in_file_only),然后继续使用该buf读取数据,
存储数据的内存分配地方有两个:1.在读取报文头部的时候ngx_http_wait_request_handler  2.如果在1中读到的内容里面不包括完整包体,则需要在
ngx_http_read_client_request_body中会重新分配内存读取,触发再次读取的地方未ngx_http_read_client_request_body中为读取到完整包体的时候添加的ngx_handle_read_event
*/
static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
    off_t                      rest;
    size_t                     size;
    ssize_t                    n;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t               *cl, out;
    ngx_connection_t          *c;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    c = r->connection;
    rb = r->request_body;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
                   "http read client request body");

    for ( ;; ) {
        for ( ;; ) {
            /*
              首先检查请求的request_body成员中的buf缓冲区,如果缓冲区还有空闲的空间,则跳过该if{}去读取内核中套接字缓冲区里的TCP字符流;
              如果缓冲区已经写满,则调用ngx_http_write_request_body方法把缓冲区中的字符流写入文件。不管有没有配置request_body_in_file_only置1
             */
            if (rb->buf->last == rb->buf->end) {

                if (rb->buf->pos != rb->buf->last) {

                    /* pass buffer to request body filter chain */

                    out.buf = rb->buf;
                    out.next = NULL;
                    //这里肯定会调用ngx_http_request_body_save_filter->ngx_http_write_request_body写该buf中的内容到临时文件,因为该buf指向的空间
                    //会重复利用来读取包体内容
                    rc = ngx_http_request_body_filter(r, &out);

                    if (rc != NGX_OK) {
                        return rc;
                    }

                } else {

                    /* update chains */

                    rc = ngx_http_request_body_filter(r, NULL);

                    if (rc != NGX_OK) {
                        return rc;
                    }
                }

                if (rb->busy != NULL) { //如果头部行中的content-length:LEN中的len长度表示后面的包体大小,如果后面的包体数据长度实际比头部中的LEN大,则会走这里,
                    if (r->request_body_no_buffering) {
                        if (c->read->timer_set) {
                            ngx_del_timer(c->read, NGX_FUNC_LINE);
                        }

                        if (ngx_handle_read_event(c->read, 0, NGX_FUNC_LINE) != NGX_OK) {
                            return NGX_HTTP_INTERNAL_SERVER_ERROR;
                        }

                        return NGX_AGAIN;
                    }

                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                /*
                 为什么能下次还可以直接利用rb->buf空间来读取数据呢?
                 当一个rb->buf填满后就会通过ngx_http_write_request_body把bufs链表中的所有ngx_chain_t->ngx_buf_t中指向的数据写入到临时文件,因此rb->buf中的内存就可以再次使用了
                 */
                //只需要把缓冲区ngx_buf_t结构体的last指针指向start指针,缓冲区即可复用。
                rb->buf->pos = rb->buf->start;
                rb->buf->last = rb->buf->start;
            }

            size = rb->buf->end - rb->buf->last;              //buf中还剩余这么多空间
            rest = rb->rest - (rb->buf->last - rb->buf->pos); //还有多少字节包体没有读取

            if ((off_t) size > rest) { //说明空间够用来存储剩余的没有读取的字节数
                size = (size_t) rest;
            }

            //负责具体的读取包体工作,该函数会在for循环中会反复读直到包体读取完毕,如果内核已经没有数据并且包体还没有读完,则添加读事件,并退出循环,这样HTTP模块还能继续作用其他功能,避免阻塞
            //调用封装了recv的方法从套接字缓冲区中读取包体到缓冲区中。
            n = c->recv(c, rb->buf->last, size);

            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                           "http client request body recv %z", n);

            if (n == NGX_AGAIN) {
                break;
            }

            if (n == 0) {//如果recv方法返回错误,或者客户端主动关闭了连接
                ngx_log_error(NGX_LOG_INFO, c->log, 0,
                              "client prematurely closed connection");
            }

            if (n == 0 || n == NGX_ERROR) {//如果recv方法返回错误,或者客户端主动关闭了连接
                c->error = 1;
                return NGX_HTTP_BAD_REQUEST;
            }

            /*
               根据接收到的TCP流长度,修改缓冲区参数。例如,把缓冲区ngx_buf_t结构体的last揩针加上接收到的长度,同时更新request_body结
               构体中表示待接收的剩余包体长度的rest成员、更新ngx_http_request_t结构体中表示已接收请求长度的request_length成员。
               */ //从这里可以看出在多次读取包体的时候,需要先把前面开辟空间buf中没有填充的部分填满,如果buf填满了,则重新利用该buf读取数据
               //之前读取到填满buf中的数据取出来存放到临时文件中,参考前面的if (rb->buf->last == rb->buf->end)
            rb->buf->last += n;
            r->request_length += n;

            if (n == rest) {//根据rest成员检查是否接收到完整的包体
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

            if (rb->rest == 0) {
                break; //所有包体读取处理完毕,则退出for
            }

            if (rb->buf->last < rb->buf->end) {
                break;
            }
        }

        ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                       "http client request body rest %O", rb->rest);

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

        /*
        如果当前已经没有可读的字符流,同时还没有接收到完整的包体,则说明需要把读事件添加到事件模块,等待可读事件发生时,事件框架可以再次
        调度到这个方法接收包体。这一步是调用ngx_add_timer方法将读事件添加到定时器中,超时时间以nginx.conf文件中的client_body_timeout配置项参数为准。
          */ //说明前面的 n = c->recv(c, rb->buf->last, size);返回的是NGX_AGAIN,所以在recv中会把ready置0
        if (!c->read->ready) {

            if (r->request_body_no_buffering
                && rb->buf->pos != rb->buf->last)
            {
                /* pass buffer to request body filter chain */

                out.buf = rb->buf;
                out.next = NULL;

                rc = ngx_http_request_body_filter(r, &out);

                if (rc != NGX_OK) {
                    return rc;
                }
            }

            clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
            //当读取到完整的包体后,会删除该定时器,见后面的ngx_del_timer(c->read);
            ngx_add_timer(c->read, clcf->client_body_timeout, NGX_FUNC_LINE);//handle应该是ngx_http_request_handler

            /*
             这个请求连接上的读事件触发时的回调方法ngx_http_request_handler,从而会调用read_event_handler方法(ngx_http_read_client_request_body_handler)
               */
            if (ngx_handle_read_event(c->read, 0, NGX_FUNC_LINE) != NGX_OK) { //handle应该是ngx_http_request_handler,通过这里触发再次读取包体
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            return NGX_AGAIN; //把控制器交给HTTP框架,由框架感知读事件,当读事件发生,也就是数据到来,继续读取包体
        }
    }

    //只有包体读取完毕,才会从上面的for()循环中退出

    /*
       表明已经接收到完整的包体,需要做一些收尾工作了。首先不需要检查是否接收HTTP包体超时了,要把读事件从定时器中取出,防止不必要的定时器触发。
       这一步会检查读事件的timer set标志位,如果为1,则调用ngx_del_timer方法把读事件从定时器中移除。
     */
    if (c->read->timer_set) {
        ngx_del_timer(c->read, NGX_FUNC_LINE);
    }

    //如果缓冲区中还有未写入文件的内容,调用ngx_http_write_request_body方法把最后的包体内容也写入文件。
    if (rb->temp_file || r->request_body_in_file_only) { //只要之前的内存有写入文件,那么剩余的部分也要写入文件

        /* save the last part */

        if (ngx_http_write_request_body(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        if (rb->temp_file->file.offset != 0) {

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

            b = cl->buf;

            ngx_memzero(b, sizeof(ngx_buf_t));

            b->in_file = 1;
            b->file_last = rb->temp_file->file.offset;
            b->file = &rb->temp_file->file;

            rb->bufs = cl; //读取客户包体即使是存入临时文件中,当所有包体读取完毕后(ngx_http_do_read_client_request_body),还是会让r->request_body->bufs指向文件中的相关偏移内存地址

        } else {
            rb->bufs = NULL;
        }
    }

    /*
    在之前read_event_handler成员设置为ngx_http_read_client_request_body_handler方法,现在既然已经接收到完整的包体了,就会把
    read_event_handler设为ngx_http_block_reading方法,表示连接上再有读事件将不做任何处理。
     */
    if (!r->request_body_no_buffering) {
        r->read_event_handler = ngx_http_block_reading;
        rb->post_handler(r); //执行ngx_http_read_client_request_body的第二个参数
    }

    return NGX_OK;
}