//通过ngx_http_top_request_body_filter调用
ngx_int_t
ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
#if (NGX_DEBUG)
    ngx_chain_t               *cl;
#endif
    ngx_http_request_body_t   *rb;

    rb = r->request_body;

#if (NGX_DEBUG)

    for (cl = rb->bufs; cl; cl = cl->next) {
        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                       "http body old 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);
    }

    for (cl = in; cl; cl = cl->next) {
        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                       "http body new 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);
    }

#endif

    /* TODO: coalesce neighbouring buffers */

    if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    //当一个rb->buf填满后就会通过ngx_http_write_request_body把bufs链表中的所有ngx_chain_t->ngx_buf_t中指向的数据
    //写入到临时文件,并把ngx_buf_t结构加入poll->chain,通过poll统一释放他们
    if (rb->rest > 0
        && rb->buf && rb->buf->last == rb->buf->end
        && !r->request_body_no_buffering)
    {
        //需要缓存数据,并且rb->buf数据已经解析完毕,并且buf已经满了,但是包体还没有读完,那么就可以把buf中的数据写入临时文件,
        //这样改buf指向的内存空间在该函数退出后可以继续用来读取数据
        if (ngx_http_write_request_body(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    return NGX_OK;
}
Пример #2
0
ngx_int_t
ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
#if (NGX_DEBUG)
    ngx_chain_t               *cl;
#endif
    ngx_http_request_body_t   *rb;

    rb = r->request_body;

#if (NGX_DEBUG)

    for (cl = rb->bufs; cl; cl = cl->next) {
        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                       "http body old 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);
    }

    for (cl = in; cl; cl = cl->next) {
        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                       "http body new 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);
    }

#endif

    /* TODO: coalesce neighbouring buffers */

    if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (rb->rest > 0
        && rb->buf && rb->buf->last == rb->buf->end
        && !r->request_body_no_buffering)
    {
        if (ngx_http_write_request_body(r) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }
    }

    return NGX_OK;
}
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;
}
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;
}
Пример #5
0
static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
    size_t                     size;
    ssize_t                    n;
    ngx_buf_t                 *b, buf;
    ngx_int_t                  rc;
    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 (ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
                    ngx_http_probe_read_body_abort(r, "write temp file failed");
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }

                rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
                rb->buf->last = rb->buf->start;
            }

            size = rb->buf->end - rb->buf->last;

            if ((off_t) size > rb->rest) {
                size = (size_t) rb->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_http_probe_read_body_abort(r, "connection closed");

                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;
            }

            buf.start = rb->buf->last;
            buf.pos = rb->buf->last;
            buf.last = buf.start + n;
            buf.end = buf.last;

            rc = ngx_http_top_input_body_filter(r, &buf);
            if (rc != NGX_OK) {
                return rc;
            }

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

            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) {
            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, rb->to_write) != NGX_OK) {
            ngx_http_probe_read_body_abort(r, "write temp file failed");
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

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

        if (rb->bufs->next) {
            rb->bufs->next->buf = b;

        } else {
            rb->bufs->buf = b;
        }
    }

    if (rb->bufs->next
        && (r->request_body_in_file_only || r->request_body_in_single_buf))
    {
        rb->bufs = rb->bufs->next;
    }

    r->read_event_handler = ngx_http_block_reading;

    ngx_http_probe_read_body_done(r);

    rb->post_handler(r);

    return NGX_OK;
}
Пример #6
0
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_buf_t                 *b, buf;
    ngx_int_t                  rc;
    ngx_chain_t               *cl, **next;
    ngx_temp_file_t           *tf;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    r->main->count++;

    if (r->request_body || r->discard_body) {
        ngx_http_probe_read_body_abort(r,
                                       (r->request_body ? "body exists"
                                                        : "body discarded"));
        post_handler(r);
        return NGX_OK;
    }

    if (ngx_http_test_expect(r) != NGX_OK) {
        ngx_http_probe_read_body_abort(r, "test expect failed");
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

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

    r->request_body = rb;

    if (r->headers_in.content_length_n < 0) {
        ngx_http_probe_read_body_abort(r, "no content length");
        post_handler(r);
        return NGX_OK;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (r->headers_in.content_length_n == 0) {

        if (r->request_body_in_file_only) {
            tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
            if (tf == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            tf->file.fd = NGX_INVALID_FILE;
            tf->file.log = r->connection->log;
            tf->path = clcf->client_body_temp_path;
            tf->pool = r->pool;
            tf->warn = "a client request body is buffered to a temporary file";
            tf->log_level = r->request_body_file_log_level;
            tf->persistent = r->request_body_in_persistent_file;
            tf->clean = r->request_body_in_clean_file;

            if (r->request_body_file_group_access) {
                tf->access = 0660;
            }

            rb->temp_file = tf;

            if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
                                     tf->persistent, tf->clean, tf->access)
                != NGX_OK)
            {
                ngx_http_probe_read_body_abort(r, "create temp file failed");
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }
        }

        ngx_http_probe_read_body_done(r);

        post_handler(r);

        return NGX_OK;
    }

    rb->post_handler = post_handler;

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->rest = 0;
     */

    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);

        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        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;

        buf.start = r->header_in->pos;
        buf.pos = r->header_in->pos;
        buf.last = (off_t) preread >= r->headers_in.content_length_n
                 ? r->header_in->pos + (size_t) r->headers_in.content_length_n
                 : r->header_in->last;
        buf.end = r->header_in->end;

        rc = ngx_http_top_input_body_filter(r, &buf);
        if (rc != NGX_OK) {
            return rc;
        }

        rb->bufs = ngx_alloc_chain_link(r->pool);
        if (rb->bufs == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        rb->bufs->buf = b;
        rb->bufs->next = NULL;

        rb->buf = b;

        if ((off_t) preread >= r->headers_in.content_length_n) {

            /* the whole request body was pre-read */

            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->request_length += r->headers_in.content_length_n;
            b->last = r->header_in->pos;

            if (r->request_body_in_file_only) {
                if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
                    ngx_http_probe_read_body_abort(r, "write temp file failed");
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }
            }

            ngx_http_probe_read_body_done(r);

            post_handler(r);

            return NGX_OK;
        }

        /*
         * to not consider the body as pipelined request in
         * ngx_http_set_keepalive()
         */
        r->header_in->pos = r->header_in->last;

        r->request_length += preread;

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

        if (rb->rest <= (off_t) (b->end - b->last)) {

            /* the whole request body may be placed in r->header_in */

            rb->to_write = rb->bufs;

            r->read_event_handler = ngx_http_read_client_request_body_handler;

            return ngx_http_do_read_client_request_body(r);
        }

        next = &rb->bufs->next;

    } else {
        b = NULL;
        rb->rest = r->headers_in.content_length_n;
        next = &rb->bufs;
    }

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

    if (rb->rest < size) {
        size = (ssize_t) rb->rest;

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

    } else {
        size = clcf->client_body_buffer_size;

        /* disable copying buffer for r->request_body_in_single_buf */
        b = NULL;
    }

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

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    cl->buf = rb->buf;
    cl->next = NULL;

    if (b && r->request_body_in_single_buf) {
        size = b->last - b->pos;
        ngx_memcpy(rb->buf->pos, b->pos, size);
        rb->buf->last += size;

        next = &rb->bufs;
    }

    *next = cl;

    if (r->request_body_in_file_only || r->request_body_in_single_buf) {
        rb->to_write = rb->bufs;

    } else {
        rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
    }

    r->read_event_handler = ngx_http_read_client_request_body_handler;

    return ngx_http_do_read_client_request_body(r);
}
Пример #7
0
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_buf_t                 *b, buf;
    ngx_int_t                  rc;
    ngx_chain_t               *cl, **next;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    r->main->count++;

    if (r->request_body || r->discard_body) {
        post_handler(r);
        return NGX_OK;
    }

    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;
    }

    r->request_body = rb;

    if (r->headers_in.content_length_n < 0) {
        post_handler(r);
        return NGX_OK;
    }

    if (!r->request_buffering) {
        return ngx_http_read_non_buffered_client_request_body(r, post_handler);
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (r->headers_in.content_length_n == 0) {

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

        post_handler(r);

        return NGX_OK;
    }

    rb->post_handler = post_handler;

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->rest = 0;
     *     rb->postpone_size = 0;
     *     rb->num = 0;
     */

    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);

        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;

        ngx_memzero(&buf, sizeof(ngx_buf_t));
        buf.memory = 1;
        buf.start = r->header_in->pos;
        buf.pos = r->header_in->pos;
        buf.last = (off_t) preread >= r->headers_in.content_length_n
                 ? r->header_in->pos + (size_t) r->headers_in.content_length_n
                 : r->header_in->last;
        buf.end = r->header_in->end;

        rb->bufs = ngx_alloc_chain_link(r->pool);
        if (rb->bufs == NULL) {
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            goto done;
        }

        rb->bufs->buf = b;
        rb->bufs->next = NULL;

        rb->buf = b;

        rc = ngx_http_top_input_body_filter(r, &buf);
        if (rc != NGX_OK) {
            if (rc > NGX_OK && rc < NGX_HTTP_SPECIAL_RESPONSE) {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                              "input filter: return code 1xx or 2xx "
                              "will cause trouble and is converted to 500");
            }

            /**
             * NGX_OK: success and continue;
             * NGX_ERROR: failed and exit;
             * NGX_AGAIN: not ready and retry later.
             */

            if (rc < NGX_HTTP_SPECIAL_RESPONSE && rc != NGX_AGAIN) {
                rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            return rc;
        }

        if ((off_t) preread >= r->headers_in.content_length_n) {

            /* the whole request body was pre-read */

            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->request_length += r->headers_in.content_length_n;
            b->last = r->header_in->pos;

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

            post_handler(r);

            return NGX_OK;
        }

        /*
         * to not consider the body as pipelined request in
         * ngx_http_set_keepalive()
         */
        r->header_in->pos = r->header_in->last;

        r->request_length += preread;

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

        if (rb->rest <= (off_t) (b->end - b->last)) {

            /* the whole request body may be placed in r->header_in */

            rb->to_write = rb->bufs;

            r->read_event_handler = ngx_http_read_client_request_body_handler;

            rc = ngx_http_do_read_client_request_body(r);
            goto done;
        }

        next = &rb->bufs->next;

    } else {
        b = NULL;
        rb->rest = r->headers_in.content_length_n;
        next = &rb->bufs;
    }

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

    if (rb->rest < size) {
        size = (ssize_t) rb->rest;

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

    } else {
        size = clcf->client_body_buffer_size;

        /* disable copying buffer for r->request_body_in_single_buf */
        b = NULL;
    }

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

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

    cl->buf = rb->buf;
    cl->next = NULL;

    if (b && r->request_body_in_single_buf) {
        size = b->last - b->pos;
        ngx_memcpy(rb->buf->pos, b->pos, size);
        rb->buf->last += size;

        next = &rb->bufs;
    }

    *next = cl;

    if (r->request_body_in_file_only || r->request_body_in_single_buf) {
        rb->to_write = rb->bufs;

    } else {
        rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
    }

    r->read_event_handler = ngx_http_read_client_request_body_handler;

    rc = ngx_http_do_read_client_request_body(r);

done:

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

    return rc;
}
/* mostly based on the ngx_http_do_read_client_request_body
 * function in ngx_http_request_body.c of nginx 0.8.20.
 * copyrighted by Igor Sysoev. */
static ngx_int_t
ngx_http_chunkin_do_read_chunked_request_body(ngx_http_request_t *r)
{
    ngx_int_t                  rc;
    size_t                     size;
    ssize_t                    n;
    ngx_buf_t                 *b;
    ngx_connection_t          *c;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;
    ngx_http_chunkin_ctx_t    *ctx;
    ngx_flag_t                 done;
    ngx_chain_t               *cl, *pending_chunk;
    u_char                    *p;
    ngx_http_chunkin_conf_t  *conf;

    c = r->connection;
    rb = r->request_body;
    ctx = ngx_http_get_module_ctx(r, ngx_http_chunkin_filter_module);

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

    done = 0;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (ctx->just_after_preread) {
        ctx->just_after_preread = 0;

        dd("Just after preread and ctx->chunks defined (bytes read: %d, "
                "chunk size: %d, last chars %c %c %c)", ctx->chunk_bytes_read,
                ctx->chunk_size, *(r->header_in->pos - 2),
                *(r->header_in->pos - 1), *r->header_in->pos);

        for (cl = ctx->chunks; cl; cl = cl->next) {
            b = cl->buf;

            dd("before ngx_copy...");
            p = rb->buf->last;
            rb->buf->last = ngx_copy(rb->buf->last, b->pos, b->last - b->pos);
            dd("after ngx_copy...");

            b->pos = p;
            b->last = rb->buf->last;
        }
    }

    conf = ngx_http_get_module_loc_conf(r, ngx_http_chunkin_filter_module);

    for ( ;; ) {
        for ( ;; ) {
            /*
            dd("client_max_body_size: %d, raw_body_size: %d",
                    (int)clcf->client_max_body_size,
                    (int)ctx->raw_body_size);
                    */

            if (clcf->client_max_body_size
                    && clcf->client_max_body_size < ctx->raw_body_size)
            {
                ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                          "chunkin: client intended to send too large body: "
                          "%O bytes", (off_t) ctx->raw_body_size);

                return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
            }

            /* dd("rb->buf pos: %d", (int) (rb->buf->last - rb->buf->pos)); */

            if (rb->buf->last == rb->buf->end
                    || ctx->chunks_count > conf->max_chunks_per_buf)
            {
                if (ctx->chunks_count > conf->max_chunks_per_buf) {
                    dd("too many chounks already: %d (max %d, buf last %c)",
                            (int) ctx->chunks_count,
                            (int) conf->max_chunks_per_buf,
                            *(rb->buf->last - 2));
                }

                if (ctx->chunks == NULL
                        || (ctx->chunks_total_size
                            && ctx->chunks_total_size <=
                            ctx->chunks_written_size))
                {
                    ngx_log_error(NGX_LOG_WARN, c->log, 0,
                          "chunkin: the chunkin_max_chunks_per_buf or "
                          "max_client_body_size setting seems rather small "
                          "(chunks %snull, total decoded %d, "
                          "total written %d)",
                          (u_char *) (ctx->chunks ? "not " : ""),
                          (int) ctx->chunks_total_size,
                          (int) ctx->chunks_written_size);

                } else {
                    dd("save exceeding part to disk (%d bytes), buf size: %d, "
                            "chunks count: %d",
                            ctx->chunks_total_size - ctx->chunks_written_size,
                            rb->buf->end - rb->buf->start,
                            ctx->chunks_count);

                    rc = ngx_http_write_request_body(r, ctx->chunks,
                            ctx->chunks_count);

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

                if (ctx->last_complete_chunk) {
                    pending_chunk = ctx->last_complete_chunk->next;
                    /* add ctx->chunks ~ ctx->last_complete_chunk
                     * into ctx->free_bufs */
                    ctx->last_complete_chunk->next = ctx->free_bufs;
                    ctx->free_bufs = ctx->chunks;
                    ctx->last_complete_chunk = NULL;
                } else {
                    pending_chunk = ctx->chunks;
                }

                if (pending_chunk) {
                    ctx->next_chunk = &pending_chunk->next;
                    ctx->chunks = pending_chunk;
                    ctx->chunk = pending_chunk;

                    ctx->chunk->buf->pos = rb->buf->start;
                    ctx->chunk->buf->last = rb->buf->start;
                    ctx->chunks_count = 1;

                    ctx->chunks_written_size = ctx->chunks_total_size
                        - ngx_buf_size(pending_chunk->buf);
                } else {
                    ctx->next_chunk = NULL;

                    ctx->chunks = NULL;
                    ctx->chunk = NULL;

                    ctx->chunks_count = 0;

                    ctx->chunks_written_size = ctx->chunks_total_size;
                }

                dd("reset rb->buf");

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

#if 0
                /* XXX just for debugging... */
                ngx_memzero(rb->buf->start, rb->buf->end - rb->buf->start);
#endif
            }

            size = rb->buf->end - rb->buf->last;

            n = c->recv(c, rb->buf->last, size);
            ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
                           "chunkin: http chunked client request body recv %z",
                           n);

            if (n == NGX_AGAIN) {
                dd("NGX_AGAIN caught");
                break;
            }

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

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

            /* save the original pos */
            p = rb->buf->last;

            rc = ngx_http_chunkin_run_chunked_parser(r, ctx,
                    &rb->buf->last, rb->buf->last + n, "main handler");

            if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
                return rc;
            }

            if (rc == NGX_ERROR) {
                /* chunked body parsefail */
                return NGX_HTTP_BAD_REQUEST;
            }

            /* rb->buf->last += n; */

            r->request_length += n;

            ctx->raw_body_size += n;

            if (rc == NGX_OK) {
                dd("successfully done the parsing");

                dd("keepalive? %s", r->keepalive ? "yes" : "no");

                if (r->keepalive) {
                    dd("cleaning the buffers for pipelined reqeusts (if any)");
                    size = p + n - rb->buf->last;
                    if (size) {
                        dd("found remaining data for pipelined requests");
                        if (size > (size_t) (r->header_in->end
                                    - ctx->saved_header_in_pos))
                        {
                            /* XXX enlarge the r->header_in buffer... */
                            r->keepalive = 0;
                        } else {
                            r->header_in->pos = ctx->saved_header_in_pos;
                            r->header_in->last = ngx_copy(r->header_in->pos,
                                    rb->buf->last, size);

                        }
                    }
                }

                done = 1;
                break;
            }

            /* rc == NGX_AGAIN */

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

        if (done) {
            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 (!done) {
        return NGX_HTTP_BAD_REQUEST;
    }

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

    if (rb->temp_file || r->request_body_in_file_only) {
        size = ctx->chunks_total_size - ctx->chunks_written_size;
        dd("save the last part to disk...(%d bytes left)", size);
        if (size == 0) {
            ctx->chunks = NULL;
        }

#if 0
        n = 0;
        for (cl = ctx->chunks; cl != NULL; cl = cl->next) {
            /* dd("chunks %d found buf %c", n, *cl->buf->start); */
            n++;
        }
#endif

        dd("for total %d chunks found", n);

        /* save the last part */
        rc = ngx_http_write_request_body(r, ctx->chunks, ctx->chunks_count);
        if (rc != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

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

        rb->bufs = ngx_http_chunkin_get_buf(r->pool, ctx);

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

        rb->bufs->buf = b;

    } else if ( r->request_body_in_single_buf ) {
        dd("request body in single buf");

        /* XXX we may not have to allocate a big buffer here */

        size = 0;
        for (cl = ctx->chunks; cl != NULL; cl = cl->next) {
            size += ngx_buf_size(cl->buf);
        }

        rb->buf = ngx_create_temp_buf(r->pool, size);

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

        for (cl = ctx->chunks; cl != NULL; cl = cl->next) {
            size = ngx_buf_size(cl->buf);

            dd("copy buf ...(size %d)", size);

            rb->buf->last =
                ngx_cpymem(rb->buf->last, cl->buf->pos, size);
        }

        rb->bufs = ngx_http_chunkin_get_buf(r->pool, ctx);

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

        rb->bufs->buf = rb->buf;

    } else {
        rb->bufs = ctx->chunks;
    }

#if 0
    if (rb->bufs) {
        int i;
        for (i = 0, cl = rb->bufs; cl; cl = cl->next, i++) {
            if (cl->buf->memory && cl->buf->pos == cl->buf->last) {
                dd("Found zero size buf in chain pos %d", i);
            }
        }
    }
#endif

    dd("last minute, chunks count: %d, chunks_total_size: %d",
            ctx->chunks_count, ctx->chunks_total_size);

#if 0
    size = 0;
    for (cl = rb->bufs; cl; cl = cl->next) {
        size += ngx_buf_size(cl->buf);
    }
    dd("data size: %d", size);
#endif

    rc = ngx_http_chunkin_set_content_length_header(r, ctx->chunks_total_size);

    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    rb->post_handler(r);

    return NGX_OK;
}
Пример #9
0
static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t *r)
{
    size_t                     size;
    ssize_t                    n;
    ngx_buf_t                 *b;
    ngx_connection_t          *c;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;
    int                        upload = 0;
    char                       bdbuf[128];

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

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

    if (r->headers_in.content_type->value.len > s_multipart.len
        && !memcmp(r->headers_in.content_type->value.data, s_multipart.data, s_multipart.len))
    {
        memset(bdbuf, 0, sizeof(bdbuf));
        memcpy(bdbuf, r->headers_in.content_type->value.data+s_multipart.len, r->headers_in.content_type->value.len - s_multipart.len);
        upload = 1;
    }

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

                /*if (1! = upload&&ngx_http_write_request_body(r, rb->to_write) != NGX_OK) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }*/
                writeUploadFile(r,upload,0);
                rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
                rb->buf->last = rb->buf->start;
            }

            size = rb->buf->end - rb->buf->last;

            if ((off_t) size > rb->rest) {
                size = (size_t) rb->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;
            rb->rest -= n;
            r->request_length += n;

            writeUploadFile(r,upload,n);
            if (r->request_length >= r->headers_in.content_length_n) {
                break;
            }

            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 (r->request_length >= r->headers_in.content_length_n) {
            break;
        }
        
        if (!c->read->ready) {
            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, rb->to_write) != NGX_OK) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

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

        if (rb->bufs->next) {
            rb->bufs->next->buf = b;

        } else {
            rb->bufs->buf = b;
        }
    }

    if (rb->bufs->next
        && (r->request_body_in_file_only || r->request_body_in_single_buf))
    {
        rb->bufs = rb->bufs->next;
    }

    r->read_event_handler = ngx_http_block_reading;

    rb->post_handler(r);

    return NGX_OK;
}
Пример #10
0
ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t *r,
    ngx_http_client_body_handler_pt post_handler)
{
		syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__);
    size_t                     preread;
    ssize_t                    size;
    ngx_int_t                  rc;
    ngx_buf_t                 *b;
    ngx_chain_t               *cl, **next;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;

    r->main->count++; //原始请求的引用计数加1

    if (r->request_body || r->discard_body) {//已经做过放弃包体或者接收包体的操作
        post_handler(r);//直接调用方法
        return NGX_OK;
    }

    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;
    }

    r->request_body = rb;

    if (r->headers_in.content_length_n < 0) {
        post_handler(r);
        return NGX_OK;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    if (r->headers_in.content_length_n == 0) {

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

        post_handler(r);

        return NGX_OK;
    }

    rb->post_handler = post_handler;

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->rest = 0;
     */

    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);

        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->bufs = ngx_alloc_chain_link(r->pool);
        if (rb->bufs == NULL) {
            rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
            goto done;
        }

        rb->bufs->buf = b;
        rb->bufs->next = NULL;

        rb->buf = b;

        if ((off_t) preread >= r->headers_in.content_length_n) {

            /* the whole request body was pre-read */

            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->request_length += r->headers_in.content_length_n;
            b->last = r->header_in->pos;

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

            post_handler(r);

            return NGX_OK;
        }

        /*
         * to not consider the body as pipelined request in
         * ngx_http_set_keepalive()
         */
        r->header_in->pos = r->header_in->last;

        r->request_length += preread;

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

        if (rb->rest <= (off_t) (b->end - b->last)) {

            /* the whole request body may be placed in r->header_in */

            rb->to_write = rb->bufs;

            r->read_event_handler = ngx_http_read_client_request_body_handler;

            rc = ngx_http_do_read_client_request_body(r);
            goto done;
        }

        next = &rb->bufs->next;

    } else {
        b = NULL;
        rb->rest = r->headers_in.content_length_n;
        next = &rb->bufs;
    }

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

    if (rb->rest < size) {
        size = (ssize_t) rb->rest;

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

    } else {
        size = clcf->client_body_buffer_size;

        /* disable copying buffer for r->request_body_in_single_buf */
        b = NULL;
    }

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

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

    cl->buf = rb->buf;
    cl->next = NULL;

    if (b && r->request_body_in_single_buf) {
        size = b->last - b->pos;
        ngx_memcpy(rb->buf->pos, b->pos, size);
        rb->buf->last += size;

        next = &rb->bufs;
    }

    *next = cl;

    if (r->request_body_in_file_only || r->request_body_in_single_buf) {
        rb->to_write = rb->bufs;

    } else {
        rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
    }

    r->read_event_handler = ngx_http_read_client_request_body_handler;

    rc = ngx_http_do_read_client_request_body(r);

done:

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

    return rc;
}
// 参数in实际上是ngx_http_request_body_length_filter里的out,即读取到的数据
// 从内存池里分配节点
// 拷贝in链表里的buf到rb->bufs里,不是直接连接
// 同样是指针操作,没有内存拷贝
// 如果要求写磁盘文件,那么调用ngx_http_write_request_body
ngx_int_t
ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
{
    ngx_buf_t                 *b;
    ngx_chain_t               *cl;
    ngx_http_request_body_t   *rb;

    // 请求体数据的结构体
    rb = r->request_body;

#if (NGX_DEBUG)

    for (cl = rb->bufs; cl; cl = cl->next) {
        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                       "http body old 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);
    }

    for (cl = in; cl; cl = cl->next) {
        ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
                       "http body new 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);
    }

#endif

    /* TODO: coalesce neighbouring buffers */

    // 从内存池里分配节点
    // 拷贝in链表里的buf到rb->bufs里,不是直接连接
    // 同样是指针操作,没有内存拷贝
    if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    if (r->request_body_no_buffering) {
        return NGX_OK;
    }

    if (rb->rest > 0) {

        if (rb->buf && rb->buf->last == rb->buf->end
            && ngx_http_write_request_body(r) != NGX_OK)
        {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        return NGX_OK;
    }

    /* rb->rest == 0 */

    // 如果要求写磁盘文件,那么调用ngx_http_write_request_body
    if (rb->temp_file || r->request_body_in_file_only) {

        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;
        }
    }

    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;
}
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_buf_t                 *b;
    ngx_chain_t               *cl, **next;
    ngx_temp_file_t           *tf;
    ngx_http_request_body_t   *rb;
    ngx_http_core_loc_conf_t  *clcf;
    
    //主请求引用+1
    r->main->count++;
    
    //请求体已经被读取或丢弃
    if (r->request_body || r->discard_body) {
        post_handler(r);
        return NGX_OK;
    }

    //检查是否有Expect: 100-continue头,该请求头表示客户端期望发送请求体,服务器回复“HTTP/1.1 100 Continue”允许客户端发送请求体
    if (ngx_http_test_expect(r) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    
    //分配ngx_http_request_body_t结构
    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    if (rb == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->request_body = rb;
    
    //无请求体
    if (r->headers_in.content_length_n < 0) {
        post_handler(r);
        return NGX_OK;
    }

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    
    //请求体长度为0
    if (r->headers_in.content_length_n == 0) {

        if (r->request_body_in_file_only) {
            //创建一个空的临时文件
            tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
            if (tf == NULL) {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }

            tf->file.fd = NGX_INVALID_FILE;
            tf->file.log = r->connection->log;
            tf->path = clcf->client_body_temp_path;
            tf->pool = r->pool;
            tf->warn = "a client request body is buffered to a temporary file";
            tf->log_level = r->request_body_file_log_level;
            tf->persistent = r->request_body_in_persistent_file;
            tf->clean = r->request_body_in_clean_file;

            if (r->request_body_file_group_access) {
                tf->access = 0660;
            }

            rb->temp_file = tf;

            if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
                                     tf->persistent, tf->clean, tf->access)
                != NGX_OK)
            {
                return NGX_HTTP_INTERNAL_SERVER_ERROR;
            }
        }

        post_handler(r);

        return NGX_OK;
    }
    
    //有请求体
    rb->post_handler = post_handler;

    /*
     * set by ngx_pcalloc():
     *
     *     rb->bufs = NULL;
     *     rb->buf = NULL;
     *     rb->rest = 0;
     */

    preread = r->header_in->last - r->header_in->pos;
    
    //header_in中有未处理数据,表明预读了请求体
    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);
        
        //分配空间存储预读的请求体
        b = ngx_calloc_buf(r->pool);
        if (b == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        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->bufs = ngx_alloc_chain_link(r->pool);
        if (rb->bufs == NULL) {
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        rb->bufs->buf = b;
        rb->bufs->next = NULL;

        rb->buf = b;
        
        //已预读了全部请求体
        if ((off_t) preread >= r->headers_in.content_length_n) {

            /* the whole request body was pre-read */

            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->request_length += r->headers_in.content_length_n;
            b->last = r->header_in->pos;

            if (r->request_body_in_file_only) {
                if (ngx_http_write_request_body(r, rb->bufs) != NGX_OK) {
                    return NGX_HTTP_INTERNAL_SERVER_ERROR;
                }
            }

            post_handler(r);

            return NGX_OK;
        }

        /*
         * to not consider the body as pipelined request in
         * ngx_http_set_keepalive()
         */
        r->header_in->pos = r->header_in->last;

        r->request_length += preread;

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

        if (rb->rest <= (off_t) (b->end - b->last)) {

            /* the whole request body may be placed in r->header_in */
            
            rb->to_write = rb->bufs;

            r->read_event_handler = ngx_http_read_client_request_body_handler;

            return ngx_http_do_read_client_request_body(r);
        }

        next = &rb->bufs->next;

    } else {
        b = NULL;
        rb->rest = r->headers_in.content_length_n;
        next = &rb->bufs;
    }

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

    if (rb->rest < size) {
        size = (ssize_t) rb->rest;

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

    } else {
        size = clcf->client_body_buffer_size;

        /* disable copying buffer for r->request_body_in_single_buf */
        b = NULL;
    }

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

    cl = ngx_alloc_chain_link(r->pool);
    if (cl == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    cl->buf = rb->buf;
    cl->next = NULL;

    if (b && r->request_body_in_single_buf) {
        size = b->last - b->pos;
        ngx_memcpy(rb->buf->pos, b->pos, size);
        rb->buf->last += size;

        next = &rb->bufs;
    }

    *next = cl;

    if (r->request_body_in_file_only || r->request_body_in_single_buf) {
        rb->to_write = rb->bufs;

    } else {
        rb->to_write = rb->bufs->next ? rb->bufs->next : rb->bufs;
    }

    //读完请求体后,调用该回调函数
    r->read_event_handler = ngx_http_read_client_request_body_handler;

    return ngx_http_do_read_client_request_body(r);
}