Exemplo n.º 1
0
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
		syslog(LOG_INFO, "[%s:%s:%d]", __FILE__, __func__, __LINE__);
    ssize_t       size;
    ngx_event_t  *rev;

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

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

    rev = r->connection->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

    if (rev->timer_set) {
        ngx_del_timer(rev);
    }

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

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

    if (size) {
        if (r->headers_in.content_length_n > size) {
            r->header_in->pos += size;
            r->headers_in.content_length_n -= size;

        } else {
            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->headers_in.content_length_n = 0;
            return NGX_OK;
        }
    }

    if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
        r->lingering_close = 0;
        return NGX_OK;
    }

    /* == NGX_AGAIN */

    r->read_event_handler = ngx_http_discarded_request_body_handler;

    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->count++;
    r->discard_body = 1;

    return NGX_OK;
}
Exemplo n.º 2
0
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
    ssize_t       size;
    ngx_event_t  *rev;

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

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

    rev = r->connection->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

    if (rev->timer_set) {
        ngx_del_timer(rev);
    }

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

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

    if (size) {
        if (r->headers_in.content_length_n > size) {
            r->headers_in.content_length_n -= size;

        } else {
            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->headers_in.content_length_n = 0;
            return NGX_OK;
        }
    }

    r->discard_body = 1;

    r->read_event_handler = ngx_http_read_discarded_request_body_handler;

    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->count++;
    (void) ngx_http_read_discarded_request_body(r);

    return NGX_OK;
}
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
    ssize_t       size;
    ngx_int_t     rc;
    ngx_event_t  *rev;



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

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

    rev = r->connection->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

    if (rev->timer_set) {
        ngx_del_timer(rev);
    }

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

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

    if (size || r->headers_in.chunked) {
        rc = ngx_http_discard_request_body_filter(r, r->header_in);

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

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

    rc = ngx_http_read_discarded_request_body(r);

    if (rc == NGX_OK) {
        r->lingering_close = 0;
        return NGX_OK;
    }

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

    /* rc == NGX_AGAIN */

    r->read_event_handler = ngx_http_discarded_request_body_handler;

    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    r->count++;
    r->discard_body = 1;

    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;
}
Exemplo n.º 5
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);
}
Exemplo n.º 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_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;
}
/* this function's implementation is borrowed from nginx 0.8.20
 * and modified a lot to work with the chunked encoding.
 * copyrighted (C) by Igor Sysoev */
ngx_int_t
ngx_http_chunkin_read_chunked_request_body(ngx_http_request_t *r,
    ngx_http_client_body_handler_pt post_handler)
{
    size_t                      preread;
    size_t                      size;
    ngx_http_request_body_t     *rb;
    ngx_http_core_loc_conf_t    *clcf;
    ngx_http_chunkin_ctx_t      *ctx;
    ngx_int_t                   rc;

    /* r->request_body_in_single_buf = 1; */
    /* r->request_body_in_file_only = 1; */

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

    if (ngx_http_test_expect(r) != NGX_OK) {
        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;

    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);

    rb->post_handler = post_handler;

    ctx = ngx_http_get_module_ctx(r, ngx_http_chunkin_filter_module);
    if (ctx == NULL) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    ctx->count++;

    ctx->saved_header_in_pos = r->header_in->pos;

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

    ngx_http_chunkin_init_chunked_parser(r, ctx);

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

        dd("raw chunked body %.*s", preread, r->header_in->pos);

        rc = ngx_http_chunkin_run_chunked_parser(r, ctx,
                &r->header_in->pos, r->header_in->last, "preread");

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

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

        if (rc == NGX_OK) {
            /* TODO: take r->request_body_in_file_only
             *       into account */

            dd("we have the whole chunked body in 'prepread'...");

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

            dd("chunks total size: %d", ctx->chunks_total_size);

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

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

            rb->bufs = ctx->chunks;
            if (rb->bufs) {
                rb->buf = ctx->chunks->buf;
            }

            dd("buf len: %d", rb->buf->last - rb->buf->pos);

            dd("buf left (len %d): %s",
                    (int) (r->header_in->last - r->header_in->pos),
                    r->header_in->pos);

            /* r->header_in->pos = r->header_in->last; */

            r->request_length += r->header_in->pos
                - ctx->saved_header_in_pos;

            ctx->raw_body_size += r->header_in->pos
                - ctx->saved_header_in_pos;

            post_handler(r);

            return NGX_OK;
        }

        if (rc != NGX_AGAIN) {
            /* this is impossible to reach... */
            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        size = r->header_in->last - r->header_in->pos;
        if (size) {
            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
                  "chunkin: internal assertion failed: %O bytes "
                  "left in the r->header_in buffer but "
                  "the parser returns NGX_AGAIN",
                  (off_t) size);

            return NGX_HTTP_INTERNAL_SERVER_ERROR;
        }

        dd("we need to read more chunked body in addition to 'prepread'...");

        ctx->just_after_preread = 1;

        /* r->header_in->pos = r->header_in->last; */

        r->request_length += preread;

        ctx->raw_body_size += preread;
    }

    size = clcf->client_body_buffer_size;
    if (ctx->chunks_total_size > size) {
        size = ctx->chunks_total_size;
    }

    dd("chunks total size after preread: %d, buf size: %d",
            (int)ctx->chunks_total_size, (int)size);

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

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

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

    r->read_event_handler = ngx_http_chunkin_read_chunked_request_body_handler;

    rc = ngx_http_chunkin_do_read_chunked_request_body(r);

    return rc;
}
Exemplo n.º 8
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;
}
// 要求nginx丢弃请求体数据
// 子请求不与客户端直接通信,不会有请求体的读取
// 已经设置了discard_body标志,表示已经调用了此函数
// request_body指针不空,表示已经调用了此函数
// 这三种情况就无需再启动读取handler,故直接返回成功
// 因为要丢弃数据,所以不需要检查超时,也就是说即使超时也不算是错误
// 如果头里的长度是0且不是chunked
// 说明没有请求体数据,那么就无需再读,直接返回成功
// *一直*读数据并解析,检查content_length_n,如果无数据可读就返回NGX_AGAIN
// 因为使用的是et模式,所以必须把数据读完
// 调用ngx_http_discard_request_body_filter检查收到的数据
// 使用回调ngx_http_discarded_request_body_handler读取数据
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
    ssize_t       size;
    ngx_int_t     rc;
    ngx_event_t  *rev;

    // 子请求不与客户端直接通信,不会有请求体的读取
    // 已经设置了discard_body标志,表示已经调用了此函数
    // request_body指针不空,表示已经调用了此函数
    // 这三种情况就无需再启动读取handler,故直接返回成功
    // discard_body在本函数最末尾设置,防止重入
    if (r != r->main || r->discard_body || r->request_body) {
        return NGX_OK;
    }

#if (NGX_HTTP_V2)
    if (r->stream) {
        r->stream->skip_data = 1;
        return NGX_OK;
    }
#endif

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

    // 从请求获取连接对象,再获得读事件
    rev = r->connection->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

    // 因为要丢弃数据,所以不需要检查超时,也就是说即使超时也不算是错误
    // 不检查读事件的超时,有数据就读
    if (rev->timer_set) {
        ngx_del_timer(rev);
    }

    // 如果头里的长度未设置、或者是0且不是chunked
    // 说明没有请求体数据,那么就无需再读,直接返回成功
    if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
        return NGX_OK;
    }

    // 检查缓冲区里在解析完头后是否还有数据
    // 也就是说之前可能读取了部分请求体数据
    size = r->header_in->last - r->header_in->pos;

    // 有数据,或者是chunked数据
    // 有可能已经读取了一些请求体数据,所以先检查一下
    if (size || r->headers_in.chunked) {
        // 检查请求结构体里的缓冲区数据,丢弃
        // 有content_length_n指定确切长度,那么只接收,不处理,移动缓冲区指针
        // chunked数据需要解析数据
        rc = ngx_http_discard_request_body_filter(r, r->header_in);

        // 不是ok表示出错,不能再读取数据
        if (rc != NGX_OK) {
            return rc;
        }

        // content_length_n==0表示数据已经全部读完
        // 就已经完成了丢弃任务,否则就要加入epoll读事件继续读
        if (r->headers_in.content_length_n == 0) {
            return NGX_OK;
        }
    }

    // 走到这里,表明content_length_n>=0,还有数据要读取
    // 接下来就读取请求体数据并丢弃
    // 使用固定的4k缓冲区接受丢弃的数据
    // 一直读数据并解析,检查content_length_n,如果无数据可读就返回NGX_AGAIN
    // 因为使用的是et模式,所以必须把数据读完
    // 需要使用回调ngx_http_discarded_request_body_handler读取数据
    rc = ngx_http_read_discarded_request_body(r);

    if (rc == NGX_OK) {
        r->lingering_close = 0;
        return NGX_OK;
    }

    // 出错
    if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
        return rc;
    }

    /* rc == NGX_AGAIN */

    // 读事件not ready,无数据可读,那么就要在epoll里加入读事件和handler
    // 注意,不再需要加入定时器
    // 之后再有数据来均由ngx_http_discarded_request_body_handler处理
    // 里面还是调用ngx_http_read_discarded_request_body读数据

    r->read_event_handler = ngx_http_discarded_request_body_handler;

    // 注意,读事件的handler实际上是ngx_http_request_handler
    // 但最终会调用r->read_event_handler
    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

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

    // 设置丢弃标志,防止再次进入本函数
    r->discard_body = 1;

    return NGX_OK;
}
// 要求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;
}
ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
    ssize_t       size;
    ngx_int_t     rc;
    ngx_event_t  *rev;

#if (NGX_HTTP_SPDY)
    if (r->spdy_stream && r == r->main) {
        r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD;
        return NGX_OK;
    }
#endif

    /*
     首先检查当前请求是一个子请求还是原始请求。为什么要检查这个呢?因为对于子请求而言,它木是来自客户端的请求,所以不存在处理HTTP
     请求包体的概念。如果当前请求是原始请求,则继续执行;如果它是子请求,则直接返回NGX_OK表示丢弃包体成功。检查ngx_http_request_t结构
     体的request_body成员,如果它已经被赋值过且不再为NULL空指针,则说明已经接收过包体了,这时也需要返回NGX_OK表示成功。
     */
    if (r != r->main || r->discard_body || r->request_body) {
        return NGX_OK;
    }

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

    rev = r->connection->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

    /*
    检查请求连接上的读事件是否在定时器中,这是因为丢弃包体不用考虑超时问题(linger_timer例外,本章不考虑此情况)。如果读事件
    的timer set标志位为1,则从定时器中移除此事件。还要检查content-length头部,如果它的值小于或等于0,同样意味着可以直接返回
    NGX一OK,表示成功丢弃了全部包体。
     */
    if (rev->timer_set) {
        ngx_del_timer(rev, NGX_FUNC_LINE);
    }
    if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
        return NGX_OK;
    }


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

    if (size || r->headers_in.chunked) {
        rc = ngx_http_discard_request_body_filter(r, r->header_in);

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

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

    /*
      在接收HTTP头部时,还是要检查是否凑巧已经接收到完整的包体(如果包体很小,那么这是非常可能发生的事),如果已经接收到完整的包
    体,则直接返回NGX OK,表示丢弃包体成功,否则,说明需要多次的调度才能完成丢弃包体这一动作,此时把请求的read_event_handler
    成员设置为ngx_http_discarded_request_body_handler方法。
      */
    rc = ngx_http_read_discarded_request_body(r);

    if (rc == NGX_OK) {
        /* 返回NGX一OK表示已经接收到完整的包体了,这时将请求的lingering_close延时关闭标志位设为0,表示不需要为了包体的接收而
        延时关闭了,同时返回NGX―OK表示丢弃包体成功。 */
        r->lingering_close = 0;
        return NGX_OK;
    }

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

    //返回非NGX_OK表示Nginx的事件框架触发事件需要多次调度才能完成丢弃包体这一动作

    /* rc == NGX_AGAIN */

    r->read_event_handler = ngx_http_discarded_request_body_handler; //下次读事件到来时通过ngx_http_request_handler来调用

    if (ngx_handle_read_event(rev, 0, NGX_FUNC_LINE) != NGX_OK) { //调用ngx_handle_read_event方法把读事件添加到epoll中  handle为ngx_http_request_handler
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }

    /*
    返回非NGX_ OK表示Nginx的事件框架触发事件需要多次调度才能完成丢弃包体这一动作,于是先把引用计数加1,防止这边还在丢弃包体,
    而其他事件却已让请求意外销毁,引发严重错误。同时把ngx_http_request_t结构体的discard_body标志位置为1,表示正在丢弃包体,并
    返回NGX―OK,当然,达时的NGX OK绝不表示已经成功地接收完包体,只是说明ngx_http_discard_request_body执行完毕而已。
     */
    r->count++;
    r->discard_body = 1;

    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_int_t
ngx_http_discard_request_body(ngx_http_request_t *r)
{
    ssize_t       size;
    ngx_event_t  *rev;

    //子请求不需处理
    if (r != r->main || r->discard_body) {
        return NGX_OK;
    }

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

    rev = r->connection->read;

    ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");

    if (rev->timer_set) {
        //删除读事件定时器
        ngx_del_timer(rev);
    }

    if (r->headers_in.content_length_n <= 0 || r->request_body) {
        //无请求体或已读完直接返回
        return NGX_OK;
    }

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

    if (size) {
        //丢弃预读数据
        if (r->headers_in.content_length_n > size) {
            r->header_in->pos += size;
            r->headers_in.content_length_n -= size;

        } else {
            r->header_in->pos += (size_t) r->headers_in.content_length_n;
            r->headers_in.content_length_n = 0;
            return NGX_OK;
        }
    }

    //设置读事件回调函数并挂在读事件
    r->read_event_handler = ngx_http_discarded_request_body_handler;

    if (ngx_handle_read_event(rev, 0) != NGX_OK) {
        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    }
    
    //读取并丢弃请求体
    if (ngx_http_read_discarded_request_body(r) == NGX_OK) {
        r->lingering_close = 0;

    } else {
        //客户端没有一次发完请求体,在下一次读事件是,通过ngx_http_discarded_request_body_handler函数处理
        r->count++;     //可能在请求处理完后仍未发送完请求体,防止处理完请求后直接释放请求
        r->discard_body = 1;
    }

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