Ticket #907: body2.patch

File body2.patch, 26.2 KB (added by Valentin V. Bartenev, 11 years ago)

Thank you for testing. A fixed version of the patch is attached.

  • src/http/ngx_http_request.h

    diff -r ce946e0976dc -r edacc9766e8e src/http/ngx_http_request.h
    a b typedef struct {  
    284284    ngx_chain_t                      *bufs;
    285285    ngx_buf_t                        *buf;
    286286    off_t                             rest;
     287#if (NGX_HTTP_V2)
     288    off_t                             received;
     289#endif
    287290    ngx_chain_t                      *free;
    288291    ngx_chain_t                      *busy;
    289292    ngx_http_chunked_t               *chunked;
  • src/http/ngx_http_request_body.c

    diff -r ce946e0976dc -r edacc9766e8e src/http/ngx_http_request_body.c
    a b ngx_http_read_client_request_body(ngx_ht  
    3434    ssize_t                    size;
    3535    ngx_int_t                  rc;
    3636    ngx_buf_t                 *b;
    37     ngx_chain_t                out, *cl;
     37    ngx_chain_t                out;
    3838    ngx_http_request_body_t   *rb;
    3939    ngx_http_core_loc_conf_t  *clcf;
    4040
    4141    r->main->count++;
    4242
    43 #if (NGX_HTTP_V2)
    44     if (r->stream && r == r->main) {
    45         r->request_body_no_buffering = 0;
    46         rc = ngx_http_v2_read_request_body(r, post_handler);
    47         goto done;
    48     }
    49 #endif
    50 
    5143    if (r != r->main || r->request_body || r->discard_body) {
    5244        r->request_body_no_buffering = 0;
    5345        post_handler(r);
    5446        return NGX_OK;
    5547    }
    5648
     49#if (NGX_HTTP_V2)
     50    if (r->stream) {
     51        r->request_body_no_buffering = 0;
     52        rc = ngx_http_v2_read_request_body(r, post_handler);
     53        goto done;
     54    }
     55#endif
     56
    5757    if (ngx_http_test_expect(r) != NGX_OK) {
    5858        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    5959        goto done;
    6060    }
    6161
    62     if (r->request_body_no_buffering) {
    63         r->request_body_in_file_only = 0;
    64     }
    65 
    6662    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    6763    if (rb == NULL) {
    6864        rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    ngx_http_read_client_request_body(ngx_ht  
    148144
    149145    if (rb->rest == 0) {
    150146        /* the whole request body was pre-read */
    151 
    152         if (r->request_body_in_file_only) {
    153             if (ngx_http_write_request_body(r) != NGX_OK) {
    154                 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    155                 goto done;
    156             }
    157 
    158             if (rb->temp_file->file.offset != 0) {
    159 
    160                 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
    161                 if (cl == NULL) {
    162                     rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    163                     goto done;
    164                 }
    165 
    166                 b = cl->buf;
    167 
    168                 ngx_memzero(b, sizeof(ngx_buf_t));
    169 
    170                 b->in_file = 1;
    171                 b->file_last = rb->temp_file->file.offset;
    172                 b->file = &rb->temp_file->file;
    173 
    174                 rb->bufs = cl;
    175             }
    176         }
    177 
    178147        r->request_body_no_buffering = 0;
    179 
    180148        post_handler(r);
    181 
    182149        return NGX_OK;
    183150    }
    184151
    ngx_http_do_read_client_request_body(ngx  
    289256    size_t                     size;
    290257    ssize_t                    n;
    291258    ngx_int_t                  rc;
    292     ngx_buf_t                 *b;
    293     ngx_chain_t               *cl, out;
     259    ngx_chain_t                out;
    294260    ngx_connection_t          *c;
    295261    ngx_http_request_body_t   *rb;
    296262    ngx_http_core_loc_conf_t  *clcf;
    ngx_http_do_read_client_request_body(ngx  
    439405        ngx_del_timer(c->read);
    440406    }
    441407
    442     if (rb->temp_file || r->request_body_in_file_only) {
    443 
    444         /* save the last part */
    445 
    446         if (ngx_http_write_request_body(r) != NGX_OK) {
    447             return NGX_HTTP_INTERNAL_SERVER_ERROR;
    448         }
    449 
    450         if (rb->temp_file->file.offset != 0) {
    451 
    452             cl = ngx_chain_get_free_buf(r->pool, &rb->free);
    453             if (cl == NULL) {
    454                 return NGX_HTTP_INTERNAL_SERVER_ERROR;
    455             }
    456 
    457             b = cl->buf;
    458 
    459             ngx_memzero(b, sizeof(ngx_buf_t));
    460 
    461             b->in_file = 1;
    462             b->file_last = rb->temp_file->file.offset;
    463             b->file = &rb->temp_file->file;
    464 
    465             rb->bufs = cl;
    466         }
    467     }
    468 
    469408    if (!r->request_body_no_buffering) {
    470409        r->read_event_handler = ngx_http_block_reading;
    471410        rb->post_handler(r);
    ngx_http_discard_request_body(ngx_http_r  
    564503    ngx_int_t     rc;
    565504    ngx_event_t  *rev;
    566505
     506    if (r != r->main || r->discard_body || r->request_body) {
     507        return NGX_OK;
     508    }
     509
    567510#if (NGX_HTTP_V2)
    568     if (r->stream && r == r->main) {
    569         r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
     511    if (r->stream) {
     512        r->stream->skip_data = 1;
    570513        return NGX_OK;
    571514    }
    572515#endif
    573516
    574     if (r != r->main || r->discard_body || r->request_body) {
    575         return NGX_OK;
    576     }
    577 
    578517    if (ngx_http_test_expect(r) != NGX_OK) {
    579518        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    580519    }
    ngx_http_request_body_chunked_filter(ngx  
    11271066ngx_int_t
    11281067ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
    11291068{
    1130 #if (NGX_DEBUG)
     1069    ngx_buf_t                 *b;
    11311070    ngx_chain_t               *cl;
    1132 #endif
    11331071    ngx_http_request_body_t   *rb;
    11341072
    11351073    rb = r->request_body;
    ngx_http_request_body_save_filter(ngx_ht  
    11661104        return NGX_HTTP_INTERNAL_SERVER_ERROR;
    11671105    }
    11681106
    1169     if (rb->rest > 0
    1170         && rb->buf && rb->buf->last == rb->buf->end
    1171         && !r->request_body_no_buffering)
    1172     {
     1107    if (r->request_body_no_buffering) {
     1108        return NGX_OK;
     1109    }
     1110
     1111    if (rb->rest > 0) {
     1112
     1113        if (rb->buf && rb->buf->last == rb->buf->end
     1114            && ngx_http_write_request_body(r) != NGX_OK)
     1115        {
     1116            return NGX_HTTP_INTERNAL_SERVER_ERROR;
     1117        }
     1118
     1119        return NGX_OK;
     1120    }
     1121
     1122    /* rb->rest == 0 */
     1123
     1124    if (rb->temp_file || r->request_body_in_file_only) {
     1125
    11731126        if (ngx_http_write_request_body(r) != NGX_OK) {
    11741127            return NGX_HTTP_INTERNAL_SERVER_ERROR;
    11751128        }
     1129
     1130        if (rb->temp_file->file.offset != 0) {
     1131
     1132            cl = ngx_chain_get_free_buf(r->pool, &rb->free);
     1133            if (cl == NULL) {
     1134                return NGX_HTTP_INTERNAL_SERVER_ERROR;
     1135            }
     1136
     1137            b = cl->buf;
     1138
     1139            ngx_memzero(b, sizeof(ngx_buf_t));
     1140
     1141            b->in_file = 1;
     1142            b->file_last = rb->temp_file->file.offset;
     1143            b->file = &rb->temp_file->file;
     1144
     1145            rb->bufs = cl;
     1146        }
    11761147    }
    11771148
    11781149    return NGX_OK;
  • src/http/v2/ngx_http_v2.c

    diff -r ce946e0976dc -r edacc9766e8e src/http/v2/ngx_http_v2.c
    a b  
    5151#define NGX_HTTP_V2_MAX_WINDOW                   ((1U << 31) - 1)
    5252#define NGX_HTTP_V2_DEFAULT_WINDOW               65535
    5353
     54#define NGX_HTTP_V2_INITIAL_WINDOW               0
     55
    5456#define NGX_HTTP_V2_ROOT                         (void *) -1
    5557
    5658
    static ngx_int_t ngx_http_v2_cookie(ngx_  
    163165    ngx_http_v2_header_t *header);
    164166static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
    165167static void ngx_http_v2_run_request(ngx_http_request_t *r);
    166 static ngx_int_t ngx_http_v2_init_request_body(ngx_http_request_t *r);
     168static ngx_int_t ngx_http_v2_account_request_body(ngx_http_request_t *r,
     169    size_t size, ngx_uint_t last);
     170static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r,
     171    u_char *pos, size_t size, ngx_uint_t last);
    167172static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
    168173
    169174static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
    ngx_http_v2_state_head(ngx_http_v2_conne  
    754759static u_char *
    755760ngx_http_v2_state_data(ngx_http_v2_connection_t *h2c, u_char *pos, u_char *end)
    756761{
     762    ngx_int_t              rc;
    757763    ngx_http_v2_node_t    *node;
    758764    ngx_http_v2_stream_t  *stream;
    759765
    ngx_http_v2_state_data(ngx_http_v2_conne  
    845851
    846852    stream->recv_window -= h2c->state.length;
    847853
    848     if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) {
    849 
     854    if (stream->no_flow_control
     855        && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
     856    {
    850857        if (ngx_http_v2_send_window_update(h2c, node->id,
    851858                                           NGX_HTTP_V2_MAX_WINDOW
    852859                                           - stream->recv_window)
    ngx_http_v2_state_data(ngx_http_v2_conne  
    875882        return ngx_http_v2_state_skip_padded(h2c, pos, end);
    876883    }
    877884
     885    stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
     886
     887    rc = ngx_http_v2_account_request_body(stream->request, h2c->state.length,
     888                                          stream->in_closed);
     889    if (rc != NGX_OK) {
     890        stream->skip_data = 1;
     891        ngx_http_finalize_request(stream->request, rc);
     892        return ngx_http_v2_state_skip_padded(h2c, pos, end);
     893    }
     894
    878895    h2c->state.stream = stream;
    879896
    880897    return ngx_http_v2_state_read_data(h2c, pos, end);
    static u_char *  
    885902ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
    886903    u_char *end)
    887904{
    888     size_t                     size;
    889     ssize_t                    n;
    890     ngx_buf_t                 *buf;
    891     ngx_int_t                  rc;
    892     ngx_temp_file_t           *tf;
    893     ngx_connection_t          *fc;
    894     ngx_http_request_t        *r;
    895     ngx_http_v2_stream_t      *stream;
    896     ngx_http_request_body_t   *rb;
    897     ngx_http_core_loc_conf_t  *clcf;
     905    size_t                 size;
     906    ngx_int_t              rc;
     907    ngx_uint_t             last;
     908    ngx_http_v2_stream_t  *stream;
    898909
    899910    stream = h2c->state.stream;
    900911
    ngx_http_v2_state_read_data(ngx_http_v2_  
    903914    }
    904915
    905916    if (stream->skip_data) {
    906         stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
    907 
    908         ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
    909                        "skipping http2 DATA frame, reason: %d",
    910                        stream->skip_data);
     917        ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
     918                       "skipping http2 DATA frame");
    911919
    912920        return ngx_http_v2_state_skip_padded(h2c, pos, end);
    913921    }
    914922
     923    last = 0;
    915924    size = end - pos;
    916925
    917     if (size > h2c->state.length) {
     926    if (size >= h2c->state.length) {
    918927        size = h2c->state.length;
    919     }
    920 
    921     r = stream->request;
    922 
    923     if (r->request_body == NULL
    924         && ngx_http_v2_init_request_body(r) != NGX_OK)
    925     {
    926         stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR;
    927         return ngx_http_v2_state_skip_padded(h2c, pos, end);
    928     }
    929 
    930     fc = r->connection;
    931     rb = r->request_body;
    932     tf = rb->temp_file;
    933     buf = rb->buf;
    934 
    935     if (size) {
    936         rb->rest += size;
    937 
    938         if (r->headers_in.content_length_n != -1
    939             && r->headers_in.content_length_n < rb->rest)
    940         {
    941             ngx_log_error(NGX_LOG_INFO, fc->log, 0,
    942                           "client intended to send body data "
    943                           "larger than declared");
    944 
    945             stream->skip_data = NGX_HTTP_V2_DATA_ERROR;
    946             goto error;
    947 
    948         } else {
    949             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    950 
    951             if (clcf->client_max_body_size
    952                 && clcf->client_max_body_size < rb->rest)
    953             {
    954                 ngx_log_error(NGX_LOG_ERR, fc->log, 0,
    955                               "client intended to send "
    956                               "too large chunked body: %O bytes", rb->rest);
    957 
    958                 stream->skip_data = NGX_HTTP_V2_DATA_ERROR;
    959                 goto error;
    960             }
    961         }
    962 
    963         h2c->state.length -= size;
    964 
    965         if (tf) {
    966             buf->start = pos;
    967             buf->pos = pos;
    968 
    969             pos += size;
    970 
    971             buf->end = pos;
    972             buf->last = pos;
    973 
    974             n = ngx_write_chain_to_temp_file(tf, rb->bufs);
    975 
    976             /* TODO: n == 0 or not complete and level event */
    977 
    978             if (n == NGX_ERROR) {
    979                 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR;
    980                 goto error;
    981             }
    982 
    983             tf->offset += n;
    984 
    985         } else {
    986             buf->last = ngx_cpymem(buf->last, pos, size);
    987             pos += size;
    988         }
    989 
    990         r->request_length += size;
    991     }
     928        last = stream->in_closed;
     929    }
     930
     931    rc = ngx_http_v2_process_request_body(stream->request, pos, size, last);
     932    if (rc != NGX_OK) {
     933        stream->skip_data = 1;
     934        ngx_http_finalize_request(stream->request, rc);
     935    }
     936
     937    pos += size;
     938    h2c->state.length -= size;
    992939
    993940    if (h2c->state.length) {
    994         if (rb->post_handler) {
    995             clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    996             ngx_add_timer(fc->read, clcf->client_body_timeout);
    997         }
    998 
    999941        return ngx_http_v2_state_save(h2c, pos, end,
    1000942                                      ngx_http_v2_state_read_data);
    1001943    }
    1002944
    1003     if (h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG) {
    1004         stream->in_closed = 1;
    1005 
    1006         if (r->headers_in.content_length_n < 0) {
    1007             r->headers_in.content_length_n = rb->rest;
    1008 
    1009         } else if (r->headers_in.content_length_n != rb->rest) {
    1010             ngx_log_error(NGX_LOG_INFO, fc->log, 0,
    1011                           "client prematurely closed stream: "
    1012                           "only %O out of %O bytes of request body received",
    1013                           rb->rest, r->headers_in.content_length_n);
    1014 
    1015             stream->skip_data = NGX_HTTP_V2_DATA_ERROR;
    1016             goto error;
    1017         }
    1018 
    1019         if (tf) {
    1020             ngx_memzero(buf, sizeof(ngx_buf_t));
    1021 
    1022             buf->in_file = 1;
    1023             buf->file_last = tf->file.offset;
    1024             buf->file = &tf->file;
    1025 
    1026             rb->buf = NULL;
    1027         }
    1028 
    1029         if (rb->post_handler) {
    1030             if (fc->read->timer_set) {
    1031                 ngx_del_timer(fc->read);
    1032             }
    1033 
    1034             r->read_event_handler = ngx_http_block_reading;
    1035             rb->post_handler(r);
    1036         }
    1037 
    1038     } else if (rb->post_handler) {
    1039         clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    1040         ngx_add_timer(fc->read, clcf->client_body_timeout);
    1041     }
    1042 
    1043945    if (h2c->state.padding) {
    1044946        return ngx_http_v2_state_skip_padded(h2c, pos, end);
    1045947    }
    1046948
    1047949    return ngx_http_v2_state_complete(h2c, pos, end);
    1048 
    1049 error:
    1050 
    1051     if (rb->post_handler) {
    1052         if (fc->read->timer_set) {
    1053             ngx_del_timer(fc->read);
    1054         }
    1055 
    1056         if (stream->skip_data == NGX_HTTP_V2_DATA_ERROR) {
    1057             rc = (r->headers_in.content_length_n == -1)
    1058                  ? NGX_HTTP_REQUEST_ENTITY_TOO_LARGE : NGX_HTTP_BAD_REQUEST;
    1059 
    1060         } else {
    1061             rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
    1062         }
    1063 
    1064         ngx_http_finalize_request(r, rc);
    1065     }
    1066 
    1067     return ngx_http_v2_state_skip_padded(h2c, pos, end);
    1068950}
    1069951
    1070952
    ngx_http_v2_send_settings(ngx_http_v2_co  
    25562438        buf->last = ngx_http_v2_write_uint16(buf->last,
    25572439                                         NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING);
    25582440        buf->last = ngx_http_v2_write_uint32(buf->last,
    2559                                              NGX_HTTP_V2_MAX_WINDOW);
     2441                                             NGX_HTTP_V2_INITIAL_WINDOW);
    25602442
    25612443        buf->last = ngx_http_v2_write_uint16(buf->last,
    25622444                                           NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING);
    ngx_http_v2_create_stream(ngx_http_v2_co  
    28672749    stream->connection = h2c;
    28682750
    28692751    stream->send_window = h2c->init_window;
    2870     stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;
     2752    stream->recv_window = NGX_HTTP_V2_INITIAL_WINDOW;
    28712753
    28722754    h2c->processing++;
    28732755
    ngx_http_v2_run_request(ngx_http_request  
    35043386        ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
    35053387                      "client prematurely closed stream");
    35063388
    3507         r->stream->skip_data = NGX_HTTP_V2_DATA_ERROR;
     3389        r->stream->skip_data = 1;
    35083390
    35093391        ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
    35103392        return;
    ngx_http_v2_run_request(ngx_http_request  
    35143396}
    35153397
    35163398
    3517 static ngx_int_t
    3518 ngx_http_v2_init_request_body(ngx_http_request_t *r)
    3519 {
    3520     ngx_buf_t                 *buf;
    3521     ngx_temp_file_t           *tf;
    3522     ngx_http_request_body_t   *rb;
    3523     ngx_http_core_loc_conf_t  *clcf;
    3524 
    3525     rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
    3526     if (rb == NULL) {
    3527         return NGX_ERROR;
    3528     }
    3529 
    3530     r->request_body = rb;
    3531 
    3532     if (r->stream->in_closed) {
    3533         return NGX_OK;
    3534     }
    3535 
    3536     rb->rest = r->headers_in.content_length_n;
    3537 
    3538     clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    3539 
    3540     if (r->request_body_in_file_only
    3541         || rb->rest > (off_t) clcf->client_body_buffer_size
    3542         || rb->rest < 0)
    3543     {
    3544         tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
    3545         if (tf == NULL) {
    3546             return NGX_ERROR;
    3547         }
    3548 
    3549         tf->file.fd = NGX_INVALID_FILE;
    3550         tf->file.log = r->connection->log;
    3551         tf->path = clcf->client_body_temp_path;
    3552         tf->pool = r->pool;
    3553         tf->warn = "a client request body is buffered to a temporary file";
    3554         tf->log_level = r->request_body_file_log_level;
    3555         tf->persistent = r->request_body_in_persistent_file;
    3556         tf->clean = r->request_body_in_clean_file;
    3557 
    3558         if (r->request_body_file_group_access) {
    3559             tf->access = 0660;
    3560         }
    3561 
    3562         rb->temp_file = tf;
    3563 
    3564         if (r->stream->in_closed
    3565             && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
    3566                                     tf->persistent, tf->clean, tf->access)
    3567                != NGX_OK)
    3568         {
    3569             return NGX_ERROR;
    3570         }
    3571 
    3572         buf = ngx_calloc_buf(r->pool);
    3573         if (buf == NULL) {
    3574             return NGX_ERROR;
    3575         }
    3576 
    3577     } else {
    3578 
    3579         if (rb->rest == 0) {
    3580             return NGX_OK;
    3581         }
    3582 
    3583         buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
    3584         if (buf == NULL) {
    3585             return NGX_ERROR;
    3586         }
    3587     }
    3588 
    3589     rb->buf = buf;
    3590 
    3591     rb->bufs = ngx_alloc_chain_link(r->pool);
    3592     if (rb->bufs == NULL) {
    3593         return NGX_ERROR;
    3594     }
    3595 
    3596     rb->bufs->buf = buf;
    3597     rb->bufs->next = NULL;
    3598 
    3599     rb->rest = 0;
    3600 
    3601     return NGX_OK;
    3602 }
    3603 
    3604 
    36053399ngx_int_t
    36063400ngx_http_v2_read_request_body(ngx_http_request_t *r,
    36073401    ngx_http_client_body_handler_pt post_handler)
    36083402{
     3403    off_t                      len;
    36093404    ngx_http_v2_stream_t      *stream;
     3405    ngx_http_request_body_t   *rb;
    36103406    ngx_http_core_loc_conf_t  *clcf;
    36113407
    3612     ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
    3613                    "http2 read request body");
    3614 
    36153408    stream = r->stream;
    36163409
    3617     switch (stream->skip_data) {
    3618 
    3619     case NGX_HTTP_V2_DATA_DISCARD:
    3620         post_handler(r);
     3410    rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
     3411    if (rb == NULL) {
     3412        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     3413    }
     3414
     3415    /*
     3416     * set by ngx_pcalloc():
     3417     *
     3418     *     rb->bufs = NULL;
     3419     *     rb->buf = NULL;
     3420     *     rb->received = 0;
     3421     *     rb->free = NULL;
     3422     *     rb->busy = NULL;
     3423     */
     3424
     3425    rb->post_handler = post_handler;
     3426
     3427    r->request_body = rb;
     3428
     3429    if (stream->skip_data) {
     3430        return NGX_HTTP_BAD_REQUEST;
     3431    }
     3432
     3433    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     3434
     3435    len = r->headers_in.content_length_n;
     3436
     3437    if (stream->in_closed && len < 0) {
     3438        len = 0;
     3439    }
     3440
     3441    if (len != 0) {
     3442        if (len < 0
     3443            || len > (off_t) clcf->client_body_buffer_size
     3444            || r->request_body_in_file_only)
     3445        {
     3446            rb->buf = ngx_calloc_buf(r->pool);
     3447
     3448            if (rb->buf != NULL) {
     3449                rb->buf->memory = 1;
     3450                rb->buf->sync = 1;
     3451            }
     3452
     3453        } else {
     3454            rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
     3455        }
     3456
     3457        if (rb->buf == NULL) {
     3458            return NGX_HTTP_INTERNAL_SERVER_ERROR;
     3459        }
     3460    }
     3461
     3462    if (stream->in_closed) {
     3463        return ngx_http_v2_process_request_body(r, NULL, 0, 1);
     3464    }
     3465
     3466    stream->recv_window = NGX_HTTP_V2_MAX_WINDOW;
     3467
     3468    if (ngx_http_v2_send_window_update(stream->connection, stream->node->id,
     3469                                       stream->recv_window)
     3470        == NGX_ERROR)
     3471    {
     3472        return NGX_HTTP_INTERNAL_SERVER_ERROR;
     3473    }
     3474
     3475    stream->no_flow_control = 1;
     3476
     3477    ngx_add_timer(r->connection->read, clcf->client_body_timeout);
     3478
     3479    r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
     3480    r->write_event_handler = ngx_http_request_empty_handler;
     3481
     3482    return NGX_AGAIN;
     3483}
     3484
     3485
     3486static ngx_int_t
     3487ngx_http_v2_account_request_body(ngx_http_request_t *r, size_t size,
     3488    ngx_uint_t last)
     3489{
     3490    ngx_http_request_body_t   *rb;
     3491    ngx_http_core_loc_conf_t  *clcf;
     3492
     3493    rb = r->request_body;
     3494
     3495    if (rb == NULL) {
    36213496        return NGX_OK;
    3622 
    3623     case NGX_HTTP_V2_DATA_ERROR:
    3624         if (r->headers_in.content_length_n == -1) {
    3625             return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
    3626         } else {
     3497    }
     3498
     3499    if (size) {
     3500        r->request_length += size;
     3501        rb->received += size;
     3502
     3503        if (r->headers_in.content_length_n != -1
     3504            && r->headers_in.content_length_n < rb->received)
     3505        {
     3506            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
     3507                          "client intended to send body data "
     3508                          "larger than declared");
     3509
    36273510            return NGX_HTTP_BAD_REQUEST;
    36283511        }
    36293512
    3630     case NGX_HTTP_V2_DATA_INTERNAL_ERROR:
    3631         return NGX_HTTP_INTERNAL_SERVER_ERROR;
    3632     }
    3633 
    3634     if (!r->request_body && ngx_http_v2_init_request_body(r) != NGX_OK) {
    3635         stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR;
    3636         return NGX_HTTP_INTERNAL_SERVER_ERROR;
    3637     }
    3638 
    3639     if (stream->in_closed) {
    3640         post_handler(r);
     3513        clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
     3514
     3515        if (clcf->client_max_body_size
     3516            && clcf->client_max_body_size < rb->received)
     3517        {
     3518            ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
     3519                         "client intended to send too large chunked body: "
     3520                         "%O bytes", rb->received);
     3521
     3522            return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
     3523        }
     3524    }
     3525
     3526    if (last) {
     3527        if (r->headers_in.content_length_n != -1
     3528            && r->headers_in.content_length_n != rb->received)
     3529        {
     3530            ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
     3531                          "client prematurely closed stream: "
     3532                          "only %O out of %O bytes of request body received",
     3533                          rb->received, r->headers_in.content_length_n);
     3534
     3535            return NGX_HTTP_BAD_REQUEST;
     3536        }
     3537    }
     3538
     3539    return NGX_OK;
     3540}
     3541
     3542
     3543static ngx_int_t
     3544ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos,
     3545    size_t size, ngx_uint_t last)
     3546{
     3547    ngx_buf_t                 *buf;
     3548    ngx_int_t                  rc;
     3549    ngx_chain_t                out;
     3550    ngx_connection_t          *fc;
     3551    ngx_http_request_body_t   *rb;
     3552    ngx_http_core_loc_conf_t  *clcf;
     3553
     3554    fc = r->connection;
     3555    rb = r->request_body;
     3556
     3557    if (rb == NULL) {
    36413558        return NGX_OK;
    36423559    }
    36433560
    3644     r->request_body->post_handler = post_handler;
    3645 
    3646     r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
    3647     r->write_event_handler = ngx_http_request_empty_handler;
     3561    rb->rest = !last;
     3562
     3563    buf = rb->buf;
     3564
     3565    if (size) {
     3566        if (buf->sync) {
     3567            buf->start = pos;
     3568            buf->pos = pos;
     3569
     3570            pos += size;
     3571
     3572            buf->end = pos;
     3573            buf->last = pos;
     3574
     3575            buf->last_buf = last;
     3576
     3577            out.buf = buf;
     3578            out.next = NULL;
     3579
     3580            rc = ngx_http_top_request_body_filter(r, &out);
     3581
     3582            if (rc != NGX_OK) {
     3583                return rc;
     3584            }
     3585
     3586        } else {
     3587            buf->last = ngx_cpymem(buf->last, pos, size);
     3588        }
     3589    }
     3590
     3591    if (last) {
     3592        if (r->headers_in.content_length_n < 0) {
     3593            r->headers_in.content_length_n = rb->received;
     3594        }
     3595
     3596        if (buf) {
     3597            if (buf->sync) {
     3598                /* prevent reusing this buffer in the upstream module */
     3599                rb->buf = NULL;
     3600
     3601                rc = size ? NGX_OK : ngx_http_top_request_body_filter(r, NULL);
     3602
     3603            } else {
     3604                buf->last_buf = 1;
     3605
     3606                out.buf = buf;
     3607                out.next = NULL;
     3608
     3609                rc = ngx_http_top_request_body_filter(r, &out);
     3610            }
     3611
     3612        } else {
     3613            rc = ngx_http_top_request_body_filter(r, NULL);
     3614        }
     3615
     3616        if (rc != NGX_OK) {
     3617            return rc;
     3618        }
     3619
     3620        if (fc->read->timer_set) {
     3621            ngx_del_timer(fc->read);
     3622        }
     3623
     3624        r->read_event_handler = ngx_http_block_reading;
     3625        rb->post_handler(r);
     3626
     3627        return NGX_OK;
     3628    }
    36483629
    36493630    clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
    3650     ngx_add_timer(r->connection->read, clcf->client_body_timeout);
    3651 
    3652     return NGX_AGAIN;
     3631    ngx_add_timer(fc->read, clcf->client_body_timeout);
     3632
     3633    return NGX_OK;
    36533634}
    36543635
    36553636
    ngx_http_v2_read_client_request_body_han  
    36673648        ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
    36683649
    36693650        fc->timedout = 1;
    3670         r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
     3651        r->stream->skip_data = 1;
    36713652
    36723653        ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
    36733654        return;
    ngx_http_v2_read_client_request_body_han  
    36773658        ngx_log_error(NGX_LOG_INFO, fc->log, 0,
    36783659                      "client prematurely closed stream");
    36793660
    3680         r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD;
     3661        r->stream->skip_data = 1;
    36813662
    36823663        ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
    36833664        return;
  • src/http/v2/ngx_http_v2.h

    diff -r ce946e0976dc -r edacc9766e8e src/http/v2/ngx_http_v2.h
    a b struct ngx_http_v2_stream_s {  
    194194    unsigned                         exhausted:1;
    195195    unsigned                         in_closed:1;
    196196    unsigned                         out_closed:1;
    197     unsigned                         skip_data:2;
     197    unsigned                         no_flow_control:1;
     198    unsigned                         skip_data:1;
    198199};
    199200
    200201