comparison src/http/v2/ngx_http_v2.c @ 6496:887cca40ba6a

HTTP/2: rewritten handling of request body. There are two improvements: 1. Support for request body filters; 2. Receiving of request body is started only after the ngx_http_read_client_request_body() call. The last one fixes the problem when the client_max_body_size value might not be respected from the right location if the location was changed either during the process of receiving body or after the whole body had been received.
author Valentin Bartenev <vbart@nginx.com>
date Fri, 01 Apr 2016 15:56:03 +0300
parents 92464ebace8e
children 9d66d7ed2abb
comparison
equal deleted inserted replaced
6495:92464ebace8e 6496:887cca40ba6a
48 48
49 #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14) 49 #define NGX_HTTP_V2_DEFAULT_FRAME_SIZE (1 << 14)
50 50
51 #define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1) 51 #define NGX_HTTP_V2_MAX_WINDOW ((1U << 31) - 1)
52 #define NGX_HTTP_V2_DEFAULT_WINDOW 65535 52 #define NGX_HTTP_V2_DEFAULT_WINDOW 65535
53
54 #define NGX_HTTP_V2_INITIAL_WINDOW 0
53 55
54 #define NGX_HTTP_V2_ROOT (void *) -1 56 #define NGX_HTTP_V2_ROOT (void *) -1
55 57
56 58
57 static void ngx_http_v2_read_handler(ngx_event_t *rev); 59 static void ngx_http_v2_read_handler(ngx_event_t *rev);
161 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r); 163 static ngx_int_t ngx_http_v2_construct_request_line(ngx_http_request_t *r);
162 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r, 164 static ngx_int_t ngx_http_v2_cookie(ngx_http_request_t *r,
163 ngx_http_v2_header_t *header); 165 ngx_http_v2_header_t *header);
164 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r); 166 static ngx_int_t ngx_http_v2_construct_cookie_header(ngx_http_request_t *r);
165 static void ngx_http_v2_run_request(ngx_http_request_t *r); 167 static 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); 168 static ngx_int_t ngx_http_v2_process_request_body(ngx_http_request_t *r,
169 u_char *pos, size_t size, ngx_uint_t last);
170 static ngx_int_t ngx_http_v2_filter_request_body(ngx_http_request_t *r);
167 static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r); 171 static void ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r);
168 172
169 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c, 173 static ngx_int_t ngx_http_v2_terminate_stream(ngx_http_v2_connection_t *h2c,
170 ngx_http_v2_stream_t *stream, ngx_uint_t status); 174 ngx_http_v2_stream_t *stream, ngx_uint_t status);
171 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev); 175 static void ngx_http_v2_close_stream_handler(ngx_event_t *ev);
760 if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) { 764 if (h2c->state.flags & NGX_HTTP_V2_PADDED_FLAG) {
761 765
762 if (h2c->state.length == 0) { 766 if (h2c->state.length == 0) {
763 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0, 767 ngx_log_error(NGX_LOG_INFO, h2c->connection->log, 0,
764 "client sent padded DATA frame " 768 "client sent padded DATA frame "
765 "with incorrect length: %uz", 769 "with incorrect length: 0");
766 h2c->state.length);
767 770
768 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR); 771 return ngx_http_v2_connection_error(h2c, NGX_HTTP_V2_SIZE_ERROR);
769 } 772 }
770 773
771 if (end - pos == 0) { 774 if (end - pos == 0) {
843 return ngx_http_v2_state_skip_padded(h2c, pos, end); 846 return ngx_http_v2_state_skip_padded(h2c, pos, end);
844 } 847 }
845 848
846 stream->recv_window -= h2c->state.length; 849 stream->recv_window -= h2c->state.length;
847 850
848 if (stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4) { 851 if (stream->no_flow_control
849 852 && stream->recv_window < NGX_HTTP_V2_MAX_WINDOW / 4)
853 {
850 if (ngx_http_v2_send_window_update(h2c, node->id, 854 if (ngx_http_v2_send_window_update(h2c, node->id,
851 NGX_HTTP_V2_MAX_WINDOW 855 NGX_HTTP_V2_MAX_WINDOW
852 - stream->recv_window) 856 - stream->recv_window)
853 == NGX_ERROR) 857 == NGX_ERROR)
854 { 858 {
873 } 877 }
874 878
875 return ngx_http_v2_state_skip_padded(h2c, pos, end); 879 return ngx_http_v2_state_skip_padded(h2c, pos, end);
876 } 880 }
877 881
882 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG;
883
878 h2c->state.stream = stream; 884 h2c->state.stream = stream;
879 885
880 return ngx_http_v2_state_read_data(h2c, pos, end); 886 return ngx_http_v2_state_read_data(h2c, pos, end);
881 } 887 }
882 888
883 889
884 static u_char * 890 static u_char *
885 ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos, 891 ngx_http_v2_state_read_data(ngx_http_v2_connection_t *h2c, u_char *pos,
886 u_char *end) 892 u_char *end)
887 { 893 {
888 size_t size; 894 size_t size;
889 ssize_t n; 895 ngx_int_t rc;
890 ngx_buf_t *buf; 896 ngx_uint_t last;
891 ngx_int_t rc; 897 ngx_http_v2_stream_t *stream;
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;
898 898
899 stream = h2c->state.stream; 899 stream = h2c->state.stream;
900 900
901 if (stream == NULL) { 901 if (stream == NULL) {
902 return ngx_http_v2_state_skip_padded(h2c, pos, end); 902 return ngx_http_v2_state_skip_padded(h2c, pos, end);
903 } 903 }
904 904
905 if (stream->skip_data) { 905 if (stream->skip_data) {
906 stream->in_closed = h2c->state.flags & NGX_HTTP_V2_END_STREAM_FLAG; 906 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
907 907 "skipping http2 DATA frame");
908 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0,
909 "skipping http2 DATA frame, reason: %d",
910 stream->skip_data);
911 908
912 return ngx_http_v2_state_skip_padded(h2c, pos, end); 909 return ngx_http_v2_state_skip_padded(h2c, pos, end);
913 } 910 }
914 911
915 size = end - pos; 912 size = end - pos;
916 913
917 if (size > h2c->state.length) { 914 if (size >= h2c->state.length) {
918 size = h2c->state.length; 915 size = h2c->state.length;
919 } 916 last = stream->in_closed;
920 917
921 r = stream->request; 918 } else {
922 919 last = 0;
923 if (r->request_body == NULL 920 }
924 && ngx_http_v2_init_request_body(r) != NGX_OK) 921
925 { 922 rc = ngx_http_v2_process_request_body(stream->request, pos, size, last);
926 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; 923
927 return ngx_http_v2_state_skip_padded(h2c, pos, end); 924 if (rc != NGX_OK) {
928 } 925 stream->skip_data = 1;
929 926 ngx_http_finalize_request(stream->request, rc);
930 fc = r->connection; 927 }
931 rb = r->request_body; 928
932 tf = rb->temp_file; 929 pos += size;
933 buf = rb->buf; 930 h2c->state.length -= size;
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 }
992 931
993 if (h2c->state.length) { 932 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
999 return ngx_http_v2_state_save(h2c, pos, end, 933 return ngx_http_v2_state_save(h2c, pos, end,
1000 ngx_http_v2_state_read_data); 934 ngx_http_v2_state_read_data);
1001 } 935 }
1002 936
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
1043 if (h2c->state.padding) { 937 if (h2c->state.padding) {
1044 return ngx_http_v2_state_skip_padded(h2c, pos, end); 938 return ngx_http_v2_state_skip_padded(h2c, pos, end);
1045 } 939 }
1046 940
1047 return ngx_http_v2_state_complete(h2c, pos, end); 941 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);
1068 } 942 }
1069 943
1070 944
1071 static u_char * 945 static u_char *
1072 ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos, 946 ngx_http_v2_state_headers(ngx_http_v2_connection_t *h2c, u_char *pos,
2554 h2scf->concurrent_streams); 2428 h2scf->concurrent_streams);
2555 2429
2556 buf->last = ngx_http_v2_write_uint16(buf->last, 2430 buf->last = ngx_http_v2_write_uint16(buf->last,
2557 NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING); 2431 NGX_HTTP_V2_INIT_WINDOW_SIZE_SETTING);
2558 buf->last = ngx_http_v2_write_uint32(buf->last, 2432 buf->last = ngx_http_v2_write_uint32(buf->last,
2559 NGX_HTTP_V2_MAX_WINDOW); 2433 NGX_HTTP_V2_INITIAL_WINDOW);
2560 2434
2561 buf->last = ngx_http_v2_write_uint16(buf->last, 2435 buf->last = ngx_http_v2_write_uint16(buf->last,
2562 NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING); 2436 NGX_HTTP_V2_MAX_FRAME_SIZE_SETTING);
2563 buf->last = ngx_http_v2_write_uint32(buf->last, 2437 buf->last = ngx_http_v2_write_uint32(buf->last,
2564 NGX_HTTP_V2_MAX_FRAME_SIZE); 2438 NGX_HTTP_V2_MAX_FRAME_SIZE);
2876 2750
2877 stream->request = r; 2751 stream->request = r;
2878 stream->connection = h2c; 2752 stream->connection = h2c;
2879 2753
2880 stream->send_window = h2c->init_window; 2754 stream->send_window = h2c->init_window;
2881 stream->recv_window = NGX_HTTP_V2_MAX_WINDOW; 2755 stream->recv_window = NGX_HTTP_V2_INITIAL_WINDOW;
2882 2756
2883 h2c->processing++; 2757 h2c->processing++;
2884 2758
2885 return stream; 2759 return stream;
2886 } 2760 }
3513 3387
3514 if (r->headers_in.content_length_n > 0 && r->stream->in_closed) { 3388 if (r->headers_in.content_length_n > 0 && r->stream->in_closed) {
3515 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0, 3389 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3516 "client prematurely closed stream"); 3390 "client prematurely closed stream");
3517 3391
3518 r->stream->skip_data = NGX_HTTP_V2_DATA_ERROR; 3392 r->stream->skip_data = 1;
3519 3393
3520 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST); 3394 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
3521 return; 3395 return;
3522 } 3396 }
3523 3397
3524 ngx_http_process_request(r); 3398 ngx_http_process_request(r);
3525 }
3526
3527
3528 static ngx_int_t
3529 ngx_http_v2_init_request_body(ngx_http_request_t *r)
3530 {
3531 ngx_buf_t *buf;
3532 ngx_temp_file_t *tf;
3533 ngx_http_request_body_t *rb;
3534 ngx_http_core_loc_conf_t *clcf;
3535
3536 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
3537 if (rb == NULL) {
3538 return NGX_ERROR;
3539 }
3540
3541 r->request_body = rb;
3542
3543 if (r->stream->in_closed) {
3544 return NGX_OK;
3545 }
3546
3547 rb->rest = r->headers_in.content_length_n;
3548
3549 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3550
3551 if (r->request_body_in_file_only
3552 || rb->rest > (off_t) clcf->client_body_buffer_size
3553 || rb->rest < 0)
3554 {
3555 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
3556 if (tf == NULL) {
3557 return NGX_ERROR;
3558 }
3559
3560 tf->file.fd = NGX_INVALID_FILE;
3561 tf->file.log = r->connection->log;
3562 tf->path = clcf->client_body_temp_path;
3563 tf->pool = r->pool;
3564 tf->warn = "a client request body is buffered to a temporary file";
3565 tf->log_level = r->request_body_file_log_level;
3566 tf->persistent = r->request_body_in_persistent_file;
3567 tf->clean = r->request_body_in_clean_file;
3568
3569 if (r->request_body_file_group_access) {
3570 tf->access = 0660;
3571 }
3572
3573 rb->temp_file = tf;
3574
3575 if (r->stream->in_closed
3576 && ngx_create_temp_file(&tf->file, tf->path, tf->pool,
3577 tf->persistent, tf->clean, tf->access)
3578 != NGX_OK)
3579 {
3580 return NGX_ERROR;
3581 }
3582
3583 buf = ngx_calloc_buf(r->pool);
3584 if (buf == NULL) {
3585 return NGX_ERROR;
3586 }
3587
3588 } else {
3589
3590 if (rb->rest == 0) {
3591 return NGX_OK;
3592 }
3593
3594 buf = ngx_create_temp_buf(r->pool, (size_t) rb->rest);
3595 if (buf == NULL) {
3596 return NGX_ERROR;
3597 }
3598 }
3599
3600 rb->buf = buf;
3601
3602 rb->bufs = ngx_alloc_chain_link(r->pool);
3603 if (rb->bufs == NULL) {
3604 return NGX_ERROR;
3605 }
3606
3607 rb->bufs->buf = buf;
3608 rb->bufs->next = NULL;
3609
3610 rb->rest = 0;
3611
3612 return NGX_OK;
3613 } 3399 }
3614 3400
3615 3401
3616 ngx_int_t 3402 ngx_int_t
3617 ngx_http_v2_read_request_body(ngx_http_request_t *r, 3403 ngx_http_v2_read_request_body(ngx_http_request_t *r,
3618 ngx_http_client_body_handler_pt post_handler) 3404 ngx_http_client_body_handler_pt post_handler)
3619 { 3405 {
3406 off_t len;
3620 ngx_http_v2_stream_t *stream; 3407 ngx_http_v2_stream_t *stream;
3408 ngx_http_request_body_t *rb;
3621 ngx_http_core_loc_conf_t *clcf; 3409 ngx_http_core_loc_conf_t *clcf;
3622 3410
3623 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
3624 "http2 read request body");
3625
3626 stream = r->stream; 3411 stream = r->stream;
3627 3412
3628 switch (stream->skip_data) { 3413 if (stream->skip_data) {
3629 3414 r->request_body_no_buffering = 0;
3630 case NGX_HTTP_V2_DATA_DISCARD:
3631 post_handler(r); 3415 post_handler(r);
3632 return NGX_OK; 3416 return NGX_OK;
3633 3417 }
3634 case NGX_HTTP_V2_DATA_ERROR: 3418
3635 if (r->headers_in.content_length_n == -1) { 3419 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
3636 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; 3420 if (rb == NULL) {
3637 } else {
3638 return NGX_HTTP_BAD_REQUEST;
3639 }
3640
3641 case NGX_HTTP_V2_DATA_INTERNAL_ERROR:
3642 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3421 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3643 } 3422 }
3644 3423
3645 if (!r->request_body && ngx_http_v2_init_request_body(r) != NGX_OK) { 3424 /*
3646 stream->skip_data = NGX_HTTP_V2_DATA_INTERNAL_ERROR; 3425 * set by ngx_pcalloc():
3426 *
3427 * rb->bufs = NULL;
3428 * rb->buf = NULL;
3429 * rb->received = 0;
3430 * rb->free = NULL;
3431 * rb->busy = NULL;
3432 */
3433
3434 rb->rest = 1;
3435 rb->post_handler = post_handler;
3436
3437 r->request_body = rb;
3438
3439 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3440
3441 len = r->headers_in.content_length_n;
3442
3443 if (len >= 0 && len <= (off_t) clcf->client_body_buffer_size
3444 && !r->request_body_in_file_only)
3445 {
3446 rb->buf = ngx_create_temp_buf(r->pool, (size_t) len);
3447
3448 } else {
3449 rb->buf = ngx_calloc_buf(r->pool);
3450
3451 if (rb->buf != NULL) {
3452 rb->buf->sync = 1;
3453 }
3454 }
3455
3456 if (rb->buf == NULL) {
3647 return NGX_HTTP_INTERNAL_SERVER_ERROR; 3457 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3648 } 3458 }
3649 3459
3650 if (stream->in_closed) { 3460 if (stream->in_closed) {
3651 post_handler(r); 3461 return ngx_http_v2_process_request_body(r, NULL, 0, 1);
3652 return NGX_OK; 3462 }
3653 } 3463
3654 3464 stream->no_flow_control = 1;
3655 r->request_body->post_handler = post_handler; 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 ngx_add_timer(r->connection->read, clcf->client_body_timeout);
3656 3476
3657 r->read_event_handler = ngx_http_v2_read_client_request_body_handler; 3477 r->read_event_handler = ngx_http_v2_read_client_request_body_handler;
3658 r->write_event_handler = ngx_http_request_empty_handler; 3478 r->write_event_handler = ngx_http_request_empty_handler;
3659 3479
3480 return NGX_AGAIN;
3481 }
3482
3483
3484 static ngx_int_t
3485 ngx_http_v2_process_request_body(ngx_http_request_t *r, u_char *pos,
3486 size_t size, ngx_uint_t last)
3487 {
3488 ngx_buf_t *buf;
3489 ngx_int_t rc;
3490 ngx_connection_t *fc;
3491 ngx_http_request_body_t *rb;
3492 ngx_http_core_loc_conf_t *clcf;
3493
3494 rb = r->request_body;
3495
3496 if (rb == NULL) {
3497 return NGX_OK;
3498 }
3499
3500 fc = r->connection;
3501 buf = rb->buf;
3502
3503 if (size) {
3504 if (buf->sync) {
3505 buf->pos = buf->start = pos;
3506 buf->last = buf->end = pos + size;
3507
3508 } else {
3509 if (size > (size_t) (buf->end - buf->last)) {
3510 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
3511 "client intended to send body data "
3512 "larger than declared");
3513
3514 return NGX_HTTP_BAD_REQUEST;
3515 }
3516
3517 buf->last = ngx_cpymem(buf->last, pos, size);
3518 }
3519 }
3520
3521 if (last) {
3522 rb->rest = 0;
3523
3524 if (fc->read->timer_set) {
3525 ngx_del_timer(fc->read);
3526 }
3527
3528 rc = ngx_http_v2_filter_request_body(r);
3529
3530 if (rc != NGX_OK) {
3531 return rc;
3532 }
3533
3534 if (buf->sync) {
3535 /* prevent reusing this buffer in the upstream module */
3536 rb->buf = NULL;
3537 }
3538
3539 if (r->headers_in.content_length_n == -1) {
3540 r->headers_in.content_length_n = rb->received;
3541 }
3542
3543 r->read_event_handler = ngx_http_block_reading;
3544 rb->post_handler(r);
3545
3546 return NGX_OK;
3547 }
3548
3549 if (size == 0) {
3550 return NGX_OK;
3551 }
3552
3660 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); 3553 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3661 ngx_add_timer(r->connection->read, clcf->client_body_timeout); 3554 ngx_add_timer(fc->read, clcf->client_body_timeout);
3662 3555
3663 return NGX_AGAIN; 3556 if (buf->sync) {
3557 return ngx_http_v2_filter_request_body(r);
3558 }
3559
3560 return NGX_OK;
3561 }
3562
3563
3564 static ngx_int_t
3565 ngx_http_v2_filter_request_body(ngx_http_request_t *r)
3566 {
3567 ngx_buf_t *b, *buf;
3568 ngx_int_t rc;
3569 ngx_chain_t *cl;
3570 ngx_http_request_body_t *rb;
3571 ngx_http_core_loc_conf_t *clcf;
3572
3573 rb = r->request_body;
3574 buf = rb->buf;
3575
3576 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
3577 if (cl == NULL) {
3578 return NGX_HTTP_INTERNAL_SERVER_ERROR;
3579 }
3580
3581 b = cl->buf;
3582
3583 ngx_memzero(b, sizeof(ngx_buf_t));
3584
3585 if (buf->pos != buf->last) {
3586 r->request_length += buf->last - buf->pos;
3587 rb->received += buf->last - buf->pos;
3588
3589 if (r->headers_in.content_length_n != -1) {
3590 if (rb->received > r->headers_in.content_length_n) {
3591 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3592 "client intended to send body data "
3593 "larger than declared");
3594
3595 return NGX_HTTP_BAD_REQUEST;
3596 }
3597
3598 } else {
3599 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
3600
3601 if (clcf->client_max_body_size
3602 && rb->received > clcf->client_max_body_size)
3603 {
3604 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
3605 "client intended to send too large chunked body: "
3606 "%O bytes", rb->received);
3607
3608 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
3609 }
3610 }
3611
3612 b->temporary = 1;
3613 b->pos = buf->pos;
3614 b->last = buf->last;
3615 b->start = b->pos;
3616 b->end = b->last;
3617
3618 buf->pos = buf->last;
3619 }
3620
3621 if (!rb->rest) {
3622 if (r->headers_in.content_length_n != -1
3623 && r->headers_in.content_length_n != rb->received)
3624 {
3625 ngx_log_error(NGX_LOG_INFO, r->connection->log, 0,
3626 "client prematurely closed stream: "
3627 "only %O out of %O bytes of request body received",
3628 rb->received, r->headers_in.content_length_n);
3629
3630 return NGX_HTTP_BAD_REQUEST;
3631 }
3632
3633 b->last_buf = 1;
3634 }
3635
3636 b->tag = (ngx_buf_tag_t) &ngx_http_v2_filter_request_body;
3637
3638 rc = ngx_http_top_request_body_filter(r, cl);
3639
3640 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &cl,
3641 (ngx_buf_tag_t) &ngx_http_v2_filter_request_body);
3642
3643 return rc;
3664 } 3644 }
3665 3645
3666 3646
3667 static void 3647 static void
3668 ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r) 3648 ngx_http_v2_read_client_request_body_handler(ngx_http_request_t *r)
3676 3656
3677 if (fc->read->timedout) { 3657 if (fc->read->timedout) {
3678 ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out"); 3658 ngx_log_error(NGX_LOG_INFO, fc->log, NGX_ETIMEDOUT, "client timed out");
3679 3659
3680 fc->timedout = 1; 3660 fc->timedout = 1;
3681 r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; 3661 r->stream->skip_data = 1;
3682 3662
3683 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT); 3663 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
3684 return; 3664 return;
3685 } 3665 }
3686 3666
3687 if (fc->error) { 3667 if (fc->error) {
3688 ngx_log_error(NGX_LOG_INFO, fc->log, 0, 3668 ngx_log_error(NGX_LOG_INFO, fc->log, 0,
3689 "client prematurely closed stream"); 3669 "client prematurely closed stream");
3690 3670
3691 r->stream->skip_data = NGX_HTTP_V2_DATA_DISCARD; 3671 r->stream->skip_data = 1;
3692 3672
3693 ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST); 3673 ngx_http_finalize_request(r, NGX_HTTP_CLIENT_CLOSED_REQUEST);
3694 return; 3674 return;
3695 } 3675 }
3696 } 3676 }