Mercurial > hg > nginx
comparison src/http/ngx_http_request_body.c @ 8510:532fe796b0e2 quic
Merged with the default branch.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Tue, 18 Aug 2020 16:22:00 +0300 |
parents | e5d4f057a6cb f5a2af0e7079 |
children | 357b8afe915e |
comparison
equal
deleted
inserted
replaced
8509:bce9e9643444 | 8510:532fe796b0e2 |
---|---|
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | 11 |
12 | 12 |
13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); | 13 static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r); |
14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); | 14 static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r); |
15 static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r, | |
16 ngx_buf_t *buf); | |
15 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); | 17 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r); |
16 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); | 18 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r); |
17 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, | 19 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r, |
18 ngx_buf_t *b); | 20 ngx_buf_t *b); |
19 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); | 21 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r); |
280 | 282 |
281 for ( ;; ) { | 283 for ( ;; ) { |
282 for ( ;; ) { | 284 for ( ;; ) { |
283 if (rb->buf->last == rb->buf->end) { | 285 if (rb->buf->last == rb->buf->end) { |
284 | 286 |
285 if (rb->buf->pos != rb->buf->last) { | 287 /* update chains */ |
286 | 288 |
287 /* pass buffer to request body filter chain */ | 289 rc = ngx_http_request_body_filter(r, NULL); |
288 | 290 |
289 out.buf = rb->buf; | 291 if (rc != NGX_OK) { |
290 out.next = NULL; | 292 return rc; |
291 | |
292 rc = ngx_http_request_body_filter(r, &out); | |
293 | |
294 if (rc != NGX_OK) { | |
295 return rc; | |
296 } | |
297 | |
298 } else { | |
299 | |
300 /* update chains */ | |
301 | |
302 rc = ngx_http_request_body_filter(r, NULL); | |
303 | |
304 if (rc != NGX_OK) { | |
305 return rc; | |
306 } | |
307 } | 293 } |
308 | 294 |
309 if (rb->busy != NULL) { | 295 if (rb->busy != NULL) { |
310 if (r->request_body_no_buffering) { | 296 if (r->request_body_no_buffering) { |
311 if (c->read->timer_set) { | 297 if (c->read->timer_set) { |
352 } | 338 } |
353 | 339 |
354 rb->buf->last += n; | 340 rb->buf->last += n; |
355 r->request_length += n; | 341 r->request_length += n; |
356 | 342 |
357 if (n == rest || n == 0) { | 343 /* pass buffer to request body filter chain */ |
358 /* pass buffer to request body filter chain */ | 344 |
359 | 345 out.buf = rb->buf; |
360 out.buf = rb->buf; | 346 out.next = NULL; |
361 out.next = NULL; | 347 |
362 | 348 rc = ngx_http_request_body_filter(r, &out); |
363 rc = ngx_http_request_body_filter(r, &out); | 349 |
364 | 350 if (rc != NGX_OK) { |
365 if (rc != NGX_OK) { | 351 return rc; |
366 return rc; | |
367 } | |
368 } | 352 } |
369 | 353 |
370 if (rb->rest == 0) { | 354 if (rb->rest == 0) { |
371 break; | 355 break; |
372 } | 356 } |
383 break; | 367 break; |
384 } | 368 } |
385 | 369 |
386 if (!c->read->ready) { | 370 if (!c->read->ready) { |
387 | 371 |
388 if (r->request_body_no_buffering | |
389 && rb->buf->pos != rb->buf->last) | |
390 { | |
391 /* pass buffer to request body filter chain */ | |
392 | |
393 out.buf = rb->buf; | |
394 out.next = NULL; | |
395 | |
396 rc = ngx_http_request_body_filter(r, &out); | |
397 | |
398 if (rc != NGX_OK) { | |
399 return rc; | |
400 } | |
401 } | |
402 | |
403 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 372 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
404 ngx_add_timer(c->read, clcf->client_body_timeout); | 373 ngx_add_timer(c->read, clcf->client_body_timeout); |
405 | 374 |
406 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { | 375 if (ngx_handle_read_event(c->read, 0) != NGX_OK) { |
407 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 376 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
408 } | 377 } |
409 | 378 |
410 return NGX_AGAIN; | 379 return NGX_AGAIN; |
411 } | 380 } |
381 } | |
382 | |
383 if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) { | |
384 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
412 } | 385 } |
413 | 386 |
414 if (c->read->timer_set) { | 387 if (c->read->timer_set) { |
415 ngx_del_timer(c->read); | 388 ngx_del_timer(c->read); |
416 } | 389 } |
417 | 390 |
418 if (!r->request_body_no_buffering) { | 391 if (!r->request_body_no_buffering) { |
419 r->read_event_handler = ngx_http_block_reading; | 392 r->read_event_handler = ngx_http_block_reading; |
420 rb->post_handler(r); | 393 rb->post_handler(r); |
421 } | 394 } |
395 | |
396 return NGX_OK; | |
397 } | |
398 | |
399 | |
400 static ngx_int_t | |
401 ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf) | |
402 { | |
403 size_t n; | |
404 ngx_buf_t *b; | |
405 ngx_chain_t *cl; | |
406 ngx_http_connection_t *hc; | |
407 ngx_http_core_srv_conf_t *cscf; | |
408 | |
409 b = r->header_in; | |
410 n = buf->last - buf->pos; | |
411 | |
412 if (buf == b || n == 0) { | |
413 return NGX_OK; | |
414 } | |
415 | |
416 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
417 "http body pipelined header: %uz", n); | |
418 | |
419 /* | |
420 * if there is a pipelined request in the client body buffer, | |
421 * copy it to the r->header_in buffer if there is enough room, | |
422 * or allocate a large client header buffer | |
423 */ | |
424 | |
425 if (n > (size_t) (b->end - b->last)) { | |
426 | |
427 hc = r->http_connection; | |
428 | |
429 if (hc->free) { | |
430 cl = hc->free; | |
431 hc->free = cl->next; | |
432 | |
433 b = cl->buf; | |
434 | |
435 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
436 "http large header free: %p %uz", | |
437 b->pos, b->end - b->last); | |
438 | |
439 } else { | |
440 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
441 | |
442 b = ngx_create_temp_buf(r->connection->pool, | |
443 cscf->large_client_header_buffers.size); | |
444 if (b == NULL) { | |
445 return NGX_ERROR; | |
446 } | |
447 | |
448 cl = ngx_alloc_chain_link(r->connection->pool); | |
449 if (cl == NULL) { | |
450 return NGX_ERROR; | |
451 } | |
452 | |
453 cl->buf = b; | |
454 | |
455 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
456 "http large header alloc: %p %uz", | |
457 b->pos, b->end - b->last); | |
458 } | |
459 | |
460 cl->next = hc->busy; | |
461 hc->busy = cl; | |
462 hc->nbusy++; | |
463 | |
464 r->header_in = b; | |
465 | |
466 if (n > (size_t) (b->end - b->last)) { | |
467 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0, | |
468 "too large pipelined header after reading body"); | |
469 return NGX_ERROR; | |
470 } | |
471 } | |
472 | |
473 ngx_memcpy(b->last, buf->pos, n); | |
474 | |
475 b->last += n; | |
476 r->request_length -= n; | |
422 | 477 |
423 return NGX_OK; | 478 return NGX_OK; |
424 } | 479 } |
425 | 480 |
426 | 481 |
667 | 722 |
668 b.temporary = 1; | 723 b.temporary = 1; |
669 | 724 |
670 for ( ;; ) { | 725 for ( ;; ) { |
671 if (r->headers_in.content_length_n == 0) { | 726 if (r->headers_in.content_length_n == 0) { |
672 r->read_event_handler = ngx_http_block_reading; | 727 break; |
673 return NGX_OK; | |
674 } | 728 } |
675 | 729 |
676 if (!r->connection->read->ready) { | 730 if (!r->connection->read->ready) { |
677 return NGX_AGAIN; | 731 return NGX_AGAIN; |
678 } | 732 } |
702 | 756 |
703 if (rc != NGX_OK) { | 757 if (rc != NGX_OK) { |
704 return rc; | 758 return rc; |
705 } | 759 } |
706 } | 760 } |
761 | |
762 if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) { | |
763 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
764 } | |
765 | |
766 r->read_event_handler = ngx_http_block_reading; | |
767 | |
768 return NGX_OK; | |
707 } | 769 } |
708 | 770 |
709 | 771 |
710 static ngx_int_t | 772 static ngx_int_t |
711 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) | 773 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b) |
712 { | 774 { |
713 size_t size; | 775 size_t size; |
714 ngx_int_t rc; | 776 ngx_int_t rc; |
715 ngx_http_request_body_t *rb; | 777 ngx_http_request_body_t *rb; |
778 ngx_http_core_srv_conf_t *cscf; | |
716 | 779 |
717 if (r->headers_in.chunked) { | 780 if (r->headers_in.chunked) { |
718 | 781 |
719 rb = r->request_body; | 782 rb = r->request_body; |
720 | 783 |
774 | 837 |
775 if (rc == NGX_AGAIN) { | 838 if (rc == NGX_AGAIN) { |
776 | 839 |
777 /* set amount of data we want to see next time */ | 840 /* set amount of data we want to see next time */ |
778 | 841 |
779 r->headers_in.content_length_n = rb->chunked->length; | 842 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
843 | |
844 r->headers_in.content_length_n = ngx_max(rb->chunked->length, | |
845 (off_t) cscf->large_client_header_buffers.size); | |
780 break; | 846 break; |
781 } | 847 } |
782 | 848 |
783 /* invalid */ | 849 /* invalid */ |
784 | 850 |
943 ngx_int_t rc; | 1009 ngx_int_t rc; |
944 ngx_buf_t *b; | 1010 ngx_buf_t *b; |
945 ngx_chain_t *cl, *out, *tl, **ll; | 1011 ngx_chain_t *cl, *out, *tl, **ll; |
946 ngx_http_request_body_t *rb; | 1012 ngx_http_request_body_t *rb; |
947 ngx_http_core_loc_conf_t *clcf; | 1013 ngx_http_core_loc_conf_t *clcf; |
1014 ngx_http_core_srv_conf_t *cscf; | |
948 | 1015 |
949 rb = r->request_body; | 1016 rb = r->request_body; |
950 | 1017 |
951 if (rb->rest == -1) { | 1018 if (rb->rest == -1) { |
952 | 1019 |
956 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); | 1023 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t)); |
957 if (rb->chunked == NULL) { | 1024 if (rb->chunked == NULL) { |
958 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 1025 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
959 } | 1026 } |
960 | 1027 |
1028 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); | |
1029 | |
961 r->headers_in.content_length_n = 0; | 1030 r->headers_in.content_length_n = 0; |
1031 rb->rest = cscf->large_client_header_buffers.size; | |
962 | 1032 |
963 #if (NGX_HTTP_V3) | 1033 #if (NGX_HTTP_V3) |
964 if (r->http_version == NGX_HTTP_VERSION_30) { | 1034 if (r->http_version == NGX_HTTP_VERSION_30) { |
965 rb->rest = 1; | 1035 rb->rest = 1; |
966 | 1036 } |
967 } else | |
968 #endif | 1037 #endif |
969 { | |
970 rb->rest = 3; | |
971 } | |
972 } | 1038 } |
973 | 1039 |
974 out = NULL; | 1040 out = NULL; |
975 ll = &out; | 1041 ll = &out; |
976 | 1042 |
977 for (cl = in; cl; cl = cl->next) { | 1043 for (cl = in; cl; cl = cl->next) { |
1044 | |
1045 b = NULL; | |
978 | 1046 |
979 for ( ;; ) { | 1047 for ( ;; ) { |
980 | 1048 |
981 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, | 1049 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0, |
982 "http body chunked buf " | 1050 "http body chunked buf " |
1017 r->lingering_close = 1; | 1085 r->lingering_close = 1; |
1018 | 1086 |
1019 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; | 1087 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE; |
1020 } | 1088 } |
1021 | 1089 |
1090 if (b | |
1091 && rb->chunked->size <= 128 | |
1092 && cl->buf->last - cl->buf->pos >= rb->chunked->size) | |
1093 { | |
1094 r->headers_in.content_length_n += rb->chunked->size; | |
1095 | |
1096 if (rb->chunked->size < 8) { | |
1097 | |
1098 while (rb->chunked->size) { | |
1099 *b->last++ = *cl->buf->pos++; | |
1100 rb->chunked->size--; | |
1101 } | |
1102 | |
1103 } else { | |
1104 ngx_memmove(b->last, cl->buf->pos, rb->chunked->size); | |
1105 b->last += rb->chunked->size; | |
1106 cl->buf->pos += rb->chunked->size; | |
1107 rb->chunked->size = 0; | |
1108 } | |
1109 | |
1110 continue; | |
1111 } | |
1112 | |
1022 tl = ngx_chain_get_free_buf(r->pool, &rb->free); | 1113 tl = ngx_chain_get_free_buf(r->pool, &rb->free); |
1023 if (tl == NULL) { | 1114 if (tl == NULL) { |
1024 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 1115 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
1025 } | 1116 } |
1026 | 1117 |
1082 | 1173 |
1083 if (rc == NGX_AGAIN) { | 1174 if (rc == NGX_AGAIN) { |
1084 | 1175 |
1085 /* set rb->rest, amount of data we want to see next time */ | 1176 /* set rb->rest, amount of data we want to see next time */ |
1086 | 1177 |
1087 rb->rest = rb->chunked->length; | 1178 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module); |
1179 | |
1180 rb->rest = ngx_max(rb->chunked->length, | |
1181 (off_t) cscf->large_client_header_buffers.size); | |
1088 | 1182 |
1089 break; | 1183 break; |
1090 } | 1184 } |
1091 | 1185 |
1092 /* invalid */ | 1186 /* invalid */ |