1
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
6
7
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
11
12
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);
15 static ngx_int_t ngx_http_copy_pipelined_header(ngx_http_request_t *r,
16 ngx_buf_t *buf);
17 static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
18 static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
19 static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
20 ngx_buf_t *b);
21 static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
22
23 static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
24 ngx_chain_t *in);
25 static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
26 ngx_chain_t *in);
27 static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
28 ngx_chain_t *in);
29
30
31 ngx_int_t
ngx_http_read_client_request_body(ngx_http_request_t * r,ngx_http_client_body_handler_pt post_handler)32 ngx_http_read_client_request_body(ngx_http_request_t *r,
33 ngx_http_client_body_handler_pt post_handler)
34 {
35 size_t preread;
36 ssize_t size;
37 ngx_int_t rc;
38 ngx_buf_t *b;
39 ngx_chain_t out;
40 ngx_http_request_body_t *rb;
41 ngx_http_core_loc_conf_t *clcf;
42
43 r->main->count++;
44
45 if (r != r->main || r->request_body || r->discard_body) {
46 r->request_body_no_buffering = 0;
47 post_handler(r);
48 return NGX_OK;
49 }
50
51 if (ngx_http_test_expect(r) != NGX_OK) {
52 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
53 goto done;
54 }
55
56 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
57 if (rb == NULL) {
58 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
59 goto done;
60 }
61
62 /*
63 * set by ngx_pcalloc():
64 *
65 * rb->temp_file = NULL;
66 * rb->bufs = NULL;
67 * rb->buf = NULL;
68 * rb->free = NULL;
69 * rb->busy = NULL;
70 * rb->chunked = NULL;
71 * rb->received = 0;
72 * rb->filter_need_buffering = 0;
73 * rb->last_sent = 0;
74 * rb->last_saved = 0;
75 */
76
77 rb->rest = -1;
78 rb->post_handler = post_handler;
79
80 r->request_body = rb;
81
82 if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
83 r->request_body_no_buffering = 0;
84 post_handler(r);
85 return NGX_OK;
86 }
87
88 #if (NGX_HTTP_V2)
89 if (r->stream) {
90 rc = ngx_http_v2_read_request_body(r);
91 goto done;
92 }
93 #endif
94
95 preread = r->header_in->last - r->header_in->pos;
96
97 if (preread) {
98
99 /* there is the pre-read part of the request body */
100
101 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
102 "http client request body preread %uz", preread);
103
104 out.buf = r->header_in;
105 out.next = NULL;
106
107 rc = ngx_http_request_body_filter(r, &out);
108
109 if (rc != NGX_OK) {
110 goto done;
111 }
112
113 r->request_length += preread - (r->header_in->last - r->header_in->pos);
114
115 if (!r->headers_in.chunked
116 && rb->rest > 0
117 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
118 {
119 /* the whole request body may be placed in r->header_in */
120
121 b = ngx_calloc_buf(r->pool);
122 if (b == NULL) {
123 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
124 goto done;
125 }
126
127 b->temporary = 1;
128 b->start = r->header_in->pos;
129 b->pos = r->header_in->pos;
130 b->last = r->header_in->last;
131 b->end = r->header_in->end;
132
133 rb->buf = b;
134
135 r->read_event_handler = ngx_http_read_client_request_body_handler;
136 r->write_event_handler = ngx_http_request_empty_handler;
137
138 rc = ngx_http_do_read_client_request_body(r);
139 goto done;
140 }
141
142 } else {
143 /* set rb->rest */
144
145 rc = ngx_http_request_body_filter(r, NULL);
146
147 if (rc != NGX_OK) {
148 goto done;
149 }
150 }
151
152 if (rb->rest == 0 && rb->last_saved) {
153 /* the whole request body was pre-read */
154 r->request_body_no_buffering = 0;
155 post_handler(r);
156 return NGX_OK;
157 }
158
159 if (rb->rest < 0) {
160 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
161 "negative request body rest");
162 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
163 goto done;
164 }
165
166 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
167
168 size = clcf->client_body_buffer_size;
169 size += size >> 2;
170
171 /* TODO: honor r->request_body_in_single_buf */
172
173 if (!r->headers_in.chunked && rb->rest < size) {
174 size = (ssize_t) rb->rest;
175
176 if (r->request_body_in_single_buf) {
177 size += preread;
178 }
179
180 if (size == 0) {
181 size++;
182 }
183
184 } else {
185 size = clcf->client_body_buffer_size;
186 }
187
188 rb->buf = ngx_create_temp_buf(r->pool, size);
189 if (rb->buf == NULL) {
190 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
191 goto done;
192 }
193
194 r->read_event_handler = ngx_http_read_client_request_body_handler;
195 r->write_event_handler = ngx_http_request_empty_handler;
196
197 rc = ngx_http_do_read_client_request_body(r);
198
199 done:
200
201 if (r->request_body_no_buffering
202 && (rc == NGX_OK || rc == NGX_AGAIN))
203 {
204 if (rc == NGX_OK) {
205 r->request_body_no_buffering = 0;
206
207 } else {
208 /* rc == NGX_AGAIN */
209 r->reading_body = 1;
210 }
211
212 r->read_event_handler = ngx_http_block_reading;
213 post_handler(r);
214 }
215
216 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
217 r->main->count--;
218 }
219
220 return rc;
221 }
222
223
224 ngx_int_t
ngx_http_read_unbuffered_request_body(ngx_http_request_t * r)225 ngx_http_read_unbuffered_request_body(ngx_http_request_t *r)
226 {
227 ngx_int_t rc;
228
229 #if (NGX_HTTP_V2)
230 if (r->stream) {
231 rc = ngx_http_v2_read_unbuffered_request_body(r);
232
233 if (rc == NGX_OK) {
234 r->reading_body = 0;
235 }
236
237 return rc;
238 }
239 #endif
240
241 if (r->connection->read->timedout) {
242 r->connection->timedout = 1;
243 return NGX_HTTP_REQUEST_TIME_OUT;
244 }
245
246 rc = ngx_http_do_read_client_request_body(r);
247
248 if (rc == NGX_OK) {
249 r->reading_body = 0;
250 }
251
252 return rc;
253 }
254
255
256 static void
ngx_http_read_client_request_body_handler(ngx_http_request_t * r)257 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
258 {
259 ngx_int_t rc;
260
261 if (r->connection->read->timedout) {
262 r->connection->timedout = 1;
263 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
264 return;
265 }
266
267 rc = ngx_http_do_read_client_request_body(r);
268
269 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
270 ngx_http_finalize_request(r, rc);
271 }
272 }
273
274
275 static ngx_int_t
ngx_http_do_read_client_request_body(ngx_http_request_t * r)276 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
277 {
278 off_t rest;
279 size_t size;
280 ssize_t n;
281 ngx_int_t rc;
282 ngx_uint_t flush;
283 ngx_chain_t out;
284 ngx_connection_t *c;
285 ngx_http_request_body_t *rb;
286 ngx_http_core_loc_conf_t *clcf;
287
288 c = r->connection;
289 rb = r->request_body;
290 flush = 1;
291
292 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
293 "http read client request body");
294
295 for ( ;; ) {
296 for ( ;; ) {
297 if (rb->rest == 0) {
298 break;
299 }
300
301 if (rb->buf->last == rb->buf->end) {
302
303 /* update chains */
304
305 rc = ngx_http_request_body_filter(r, NULL);
306
307 if (rc != NGX_OK) {
308 return rc;
309 }
310
311 if (rb->busy != NULL) {
312 if (r->request_body_no_buffering) {
313 if (c->read->timer_set) {
314 ngx_del_timer(c->read);
315 }
316
317 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
318 return NGX_HTTP_INTERNAL_SERVER_ERROR;
319 }
320
321 return NGX_AGAIN;
322 }
323
324 if (rb->filter_need_buffering) {
325 clcf = ngx_http_get_module_loc_conf(r,
326 ngx_http_core_module);
327 ngx_add_timer(c->read, clcf->client_body_timeout);
328
329 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
330 return NGX_HTTP_INTERNAL_SERVER_ERROR;
331 }
332
333 return NGX_AGAIN;
334 }
335
336 ngx_log_error(NGX_LOG_ALERT, c->log, 0,
337 "busy buffers after request body flush");
338
339 return NGX_HTTP_INTERNAL_SERVER_ERROR;
340 }
341
342 flush = 0;
343 rb->buf->pos = rb->buf->start;
344 rb->buf->last = rb->buf->start;
345 }
346
347 size = rb->buf->end - rb->buf->last;
348 rest = rb->rest - (rb->buf->last - rb->buf->pos);
349
350 if ((off_t) size > rest) {
351 size = (size_t) rest;
352 }
353
354 if (size == 0) {
355 break;
356 }
357
358 n = c->recv(c, rb->buf->last, size);
359
360 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
361 "http client request body recv %z", n);
362
363 if (n == NGX_AGAIN) {
364 break;
365 }
366
367 if (n == 0) {
368 ngx_log_error(NGX_LOG_INFO, c->log, 0,
369 "client prematurely closed connection");
370 }
371
372 if (n == 0 || n == NGX_ERROR) {
373 c->error = 1;
374 return NGX_HTTP_BAD_REQUEST;
375 }
376
377 rb->buf->last += n;
378 r->request_length += n;
379
380 /* pass buffer to request body filter chain */
381
382 flush = 0;
383 out.buf = rb->buf;
384 out.next = NULL;
385
386 rc = ngx_http_request_body_filter(r, &out);
387
388 if (rc != NGX_OK) {
389 return rc;
390 }
391
392 if (rb->rest == 0) {
393 break;
394 }
395
396 if (rb->buf->last < rb->buf->end) {
397 break;
398 }
399 }
400
401 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
402 "http client request body rest %O", rb->rest);
403
404 if (flush) {
405 rc = ngx_http_request_body_filter(r, NULL);
406
407 if (rc != NGX_OK) {
408 return rc;
409 }
410 }
411
412 if (rb->rest == 0 && rb->last_saved) {
413 break;
414 }
415
416 if (!c->read->ready || rb->rest == 0) {
417
418 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
419 ngx_add_timer(c->read, clcf->client_body_timeout);
420
421 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
422 return NGX_HTTP_INTERNAL_SERVER_ERROR;
423 }
424
425 return NGX_AGAIN;
426 }
427 }
428
429 if (ngx_http_copy_pipelined_header(r, rb->buf) != NGX_OK) {
430 return NGX_HTTP_INTERNAL_SERVER_ERROR;
431 }
432
433 if (c->read->timer_set) {
434 ngx_del_timer(c->read);
435 }
436
437 if (!r->request_body_no_buffering) {
438 r->read_event_handler = ngx_http_block_reading;
439 rb->post_handler(r);
440 }
441
442 return NGX_OK;
443 }
444
445
446 static ngx_int_t
ngx_http_copy_pipelined_header(ngx_http_request_t * r,ngx_buf_t * buf)447 ngx_http_copy_pipelined_header(ngx_http_request_t *r, ngx_buf_t *buf)
448 {
449 size_t n;
450 ngx_buf_t *b;
451 ngx_chain_t *cl;
452 ngx_http_connection_t *hc;
453 ngx_http_core_srv_conf_t *cscf;
454
455 b = r->header_in;
456 n = buf->last - buf->pos;
457
458 if (buf == b || n == 0) {
459 return NGX_OK;
460 }
461
462 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
463 "http body pipelined header: %uz", n);
464
465 /*
466 * if there is a pipelined request in the client body buffer,
467 * copy it to the r->header_in buffer if there is enough room,
468 * or allocate a large client header buffer
469 */
470
471 if (n > (size_t) (b->end - b->last)) {
472
473 hc = r->http_connection;
474
475 if (hc->free) {
476 cl = hc->free;
477 hc->free = cl->next;
478
479 b = cl->buf;
480
481 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
482 "http large header free: %p %uz",
483 b->pos, b->end - b->last);
484
485 } else {
486 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
487
488 b = ngx_create_temp_buf(r->connection->pool,
489 cscf->large_client_header_buffers.size);
490 if (b == NULL) {
491 return NGX_ERROR;
492 }
493
494 cl = ngx_alloc_chain_link(r->connection->pool);
495 if (cl == NULL) {
496 return NGX_ERROR;
497 }
498
499 cl->buf = b;
500
501 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
502 "http large header alloc: %p %uz",
503 b->pos, b->end - b->last);
504 }
505
506 cl->next = hc->busy;
507 hc->busy = cl;
508 hc->nbusy++;
509
510 r->header_in = b;
511
512 if (n > (size_t) (b->end - b->last)) {
513 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
514 "too large pipelined header after reading body");
515 return NGX_ERROR;
516 }
517 }
518
519 ngx_memcpy(b->last, buf->pos, n);
520
521 b->last += n;
522 r->request_length -= n;
523
524 return NGX_OK;
525 }
526
527
528 static ngx_int_t
ngx_http_write_request_body(ngx_http_request_t * r)529 ngx_http_write_request_body(ngx_http_request_t *r)
530 {
531 ssize_t n;
532 ngx_chain_t *cl, *ln;
533 ngx_temp_file_t *tf;
534 ngx_http_request_body_t *rb;
535 ngx_http_core_loc_conf_t *clcf;
536
537 rb = r->request_body;
538
539 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
540 "http write client request body, bufs %p", rb->bufs);
541
542 if (rb->temp_file == NULL) {
543 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
544 if (tf == NULL) {
545 return NGX_ERROR;
546 }
547
548 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
549
550 tf->file.fd = NGX_INVALID_FILE;
551 tf->file.log = r->connection->log;
552 tf->path = clcf->client_body_temp_path;
553 tf->pool = r->pool;
554 tf->warn = "a client request body is buffered to a temporary file";
555 tf->log_level = r->request_body_file_log_level;
556 tf->persistent = r->request_body_in_persistent_file;
557 tf->clean = r->request_body_in_clean_file;
558
559 if (r->request_body_file_group_access) {
560 tf->access = 0660;
561 }
562
563 rb->temp_file = tf;
564
565 if (rb->bufs == NULL) {
566 /* empty body with r->request_body_in_file_only */
567
568 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
569 tf->persistent, tf->clean, tf->access)
570 != NGX_OK)
571 {
572 return NGX_ERROR;
573 }
574
575 return NGX_OK;
576 }
577 }
578
579 if (rb->bufs == NULL) {
580 return NGX_OK;
581 }
582
583 n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs);
584
585 /* TODO: n == 0 or not complete and level event */
586
587 if (n == NGX_ERROR) {
588 return NGX_ERROR;
589 }
590
591 rb->temp_file->offset += n;
592
593 /* mark all buffers as written */
594
595 for (cl = rb->bufs; cl; /* void */) {
596
597 cl->buf->pos = cl->buf->last;
598
599 ln = cl;
600 cl = cl->next;
601 ngx_free_chain(r->pool, ln);
602 }
603
604 rb->bufs = NULL;
605
606 return NGX_OK;
607 }
608
609
610 ngx_int_t
ngx_http_discard_request_body(ngx_http_request_t * r)611 ngx_http_discard_request_body(ngx_http_request_t *r)
612 {
613 ssize_t size;
614 ngx_int_t rc;
615 ngx_event_t *rev;
616
617 if (r != r->main || r->discard_body || r->request_body) {
618 return NGX_OK;
619 }
620
621 #if (NGX_HTTP_V2)
622 if (r->stream) {
623 r->stream->skip_data = 1;
624 return NGX_OK;
625 }
626 #endif
627
628 if (ngx_http_test_expect(r) != NGX_OK) {
629 return NGX_HTTP_INTERNAL_SERVER_ERROR;
630 }
631
632 rev = r->connection->read;
633
634 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
635
636 if (rev->timer_set) {
637 ngx_del_timer(rev);
638 }
639
640 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
641 return NGX_OK;
642 }
643
644 size = r->header_in->last - r->header_in->pos;
645
646 if (size || r->headers_in.chunked) {
647 rc = ngx_http_discard_request_body_filter(r, r->header_in);
648
649 if (rc != NGX_OK) {
650 return rc;
651 }
652
653 if (r->headers_in.content_length_n == 0) {
654 return NGX_OK;
655 }
656 }
657
658 rc = ngx_http_read_discarded_request_body(r);
659
660 if (rc == NGX_OK) {
661 r->lingering_close = 0;
662 return NGX_OK;
663 }
664
665 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
666 return rc;
667 }
668
669 /* rc == NGX_AGAIN */
670
671 r->read_event_handler = ngx_http_discarded_request_body_handler;
672
673 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
674 return NGX_HTTP_INTERNAL_SERVER_ERROR;
675 }
676
677 r->count++;
678 r->discard_body = 1;
679
680 return NGX_OK;
681 }
682
683
684 void
ngx_http_discarded_request_body_handler(ngx_http_request_t * r)685 ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
686 {
687 ngx_int_t rc;
688 ngx_msec_t timer;
689 ngx_event_t *rev;
690 ngx_connection_t *c;
691 ngx_http_core_loc_conf_t *clcf;
692
693 c = r->connection;
694 rev = c->read;
695
696 if (rev->timedout) {
697 c->timedout = 1;
698 c->error = 1;
699 ngx_http_finalize_request(r, NGX_ERROR);
700 return;
701 }
702
703 if (r->lingering_time) {
704 timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time();
705
706 if ((ngx_msec_int_t) timer <= 0) {
707 r->discard_body = 0;
708 r->lingering_close = 0;
709 ngx_http_finalize_request(r, NGX_ERROR);
710 return;
711 }
712
713 } else {
714 timer = 0;
715 }
716
717 rc = ngx_http_read_discarded_request_body(r);
718
719 if (rc == NGX_OK) {
720 r->discard_body = 0;
721 r->lingering_close = 0;
722 r->lingering_time = 0;
723 ngx_http_finalize_request(r, NGX_DONE);
724 return;
725 }
726
727 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
728 c->error = 1;
729 ngx_http_finalize_request(r, NGX_ERROR);
730 return;
731 }
732
733 /* rc == NGX_AGAIN */
734
735 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
736 c->error = 1;
737 ngx_http_finalize_request(r, NGX_ERROR);
738 return;
739 }
740
741 if (timer) {
742
743 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
744
745 timer *= 1000;
746
747 if (timer > clcf->lingering_timeout) {
748 timer = clcf->lingering_timeout;
749 }
750
751 ngx_add_timer(rev, timer);
752 }
753 }
754
755
756 static ngx_int_t
ngx_http_read_discarded_request_body(ngx_http_request_t * r)757 ngx_http_read_discarded_request_body(ngx_http_request_t *r)
758 {
759 size_t size;
760 ssize_t n;
761 ngx_int_t rc;
762 ngx_buf_t b;
763 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
764
765 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
766 "http read discarded body");
767
768 ngx_memzero(&b, sizeof(ngx_buf_t));
769
770 b.temporary = 1;
771
772 for ( ;; ) {
773 if (r->headers_in.content_length_n == 0) {
774 break;
775 }
776
777 if (!r->connection->read->ready) {
778 return NGX_AGAIN;
779 }
780
781 size = (size_t) ngx_min(r->headers_in.content_length_n,
782 NGX_HTTP_DISCARD_BUFFER_SIZE);
783
784 n = r->connection->recv(r->connection, buffer, size);
785
786 if (n == NGX_ERROR) {
787 r->connection->error = 1;
788 return NGX_OK;
789 }
790
791 if (n == NGX_AGAIN) {
792 return NGX_AGAIN;
793 }
794
795 if (n == 0) {
796 return NGX_OK;
797 }
798
799 b.pos = buffer;
800 b.last = buffer + n;
801
802 rc = ngx_http_discard_request_body_filter(r, &b);
803
804 if (rc != NGX_OK) {
805 return rc;
806 }
807 }
808
809 if (ngx_http_copy_pipelined_header(r, &b) != NGX_OK) {
810 return NGX_HTTP_INTERNAL_SERVER_ERROR;
811 }
812
813 r->read_event_handler = ngx_http_block_reading;
814
815 return NGX_OK;
816 }
817
818
819 static ngx_int_t
ngx_http_discard_request_body_filter(ngx_http_request_t * r,ngx_buf_t * b)820 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
821 {
822 size_t size;
823 ngx_int_t rc;
824 ngx_http_request_body_t *rb;
825 ngx_http_core_srv_conf_t *cscf;
826
827 if (r->headers_in.chunked) {
828
829 rb = r->request_body;
830
831 if (rb == NULL) {
832
833 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
834 if (rb == NULL) {
835 return NGX_HTTP_INTERNAL_SERVER_ERROR;
836 }
837
838 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
839 if (rb->chunked == NULL) {
840 return NGX_HTTP_INTERNAL_SERVER_ERROR;
841 }
842
843 r->request_body = rb;
844 }
845
846 for ( ;; ) {
847
848 rc = ngx_http_parse_chunked(r, b, rb->chunked);
849
850 if (rc == NGX_OK) {
851
852 /* a chunk has been parsed successfully */
853
854 size = b->last - b->pos;
855
856 if ((off_t) size > rb->chunked->size) {
857 b->pos += (size_t) rb->chunked->size;
858 rb->chunked->size = 0;
859
860 } else {
861 rb->chunked->size -= size;
862 b->pos = b->last;
863 }
864
865 continue;
866 }
867
868 if (rc == NGX_DONE) {
869
870 /* a whole response has been parsed successfully */
871
872 r->headers_in.content_length_n = 0;
873 break;
874 }
875
876 if (rc == NGX_AGAIN) {
877
878 /* set amount of data we want to see next time */
879
880 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
881
882 r->headers_in.content_length_n = ngx_max(rb->chunked->length,
883 (off_t) cscf->large_client_header_buffers.size);
884 break;
885 }
886
887 /* invalid */
888
889 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
890 "client sent invalid chunked body");
891
892 return NGX_HTTP_BAD_REQUEST;
893 }
894
895 } else {
896 size = b->last - b->pos;
897
898 if ((off_t) size > r->headers_in.content_length_n) {
899 b->pos += (size_t) r->headers_in.content_length_n;
900 r->headers_in.content_length_n = 0;
901
902 } else {
903 b->pos = b->last;
904 r->headers_in.content_length_n -= size;
905 }
906 }
907
908 return NGX_OK;
909 }
910
911
912 static ngx_int_t
ngx_http_test_expect(ngx_http_request_t * r)913 ngx_http_test_expect(ngx_http_request_t *r)
914 {
915 ngx_int_t n;
916 ngx_str_t *expect;
917
918 if (r->expect_tested
919 || r->headers_in.expect == NULL
920 || r->http_version < NGX_HTTP_VERSION_11
921 #if (NGX_HTTP_V2)
922 || r->stream != NULL
923 #endif
924 )
925 {
926 return NGX_OK;
927 }
928
929 r->expect_tested = 1;
930
931 expect = &r->headers_in.expect->value;
932
933 if (expect->len != sizeof("100-continue") - 1
934 || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
935 sizeof("100-continue") - 1)
936 != 0)
937 {
938 return NGX_OK;
939 }
940
941 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
942 "send 100 Continue");
943
944 n = r->connection->send(r->connection,
945 (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
946 sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
947
948 if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
949 return NGX_OK;
950 }
951
952 /* we assume that such small packet should be send successfully */
953
954 r->connection->error = 1;
955
956 return NGX_ERROR;
957 }
958
959
960 static ngx_int_t
ngx_http_request_body_filter(ngx_http_request_t * r,ngx_chain_t * in)961 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
962 {
963 if (r->headers_in.chunked) {
964 return ngx_http_request_body_chunked_filter(r, in);
965
966 } else {
967 return ngx_http_request_body_length_filter(r, in);
968 }
969 }
970
971
972 static ngx_int_t
ngx_http_request_body_length_filter(ngx_http_request_t * r,ngx_chain_t * in)973 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
974 {
975 size_t size;
976 ngx_int_t rc;
977 ngx_buf_t *b;
978 ngx_chain_t *cl, *tl, *out, **ll;
979 ngx_http_request_body_t *rb;
980
981 rb = r->request_body;
982
983 out = NULL;
984 ll = &out;
985
986 if (rb->rest == -1) {
987 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
988 "http request body content length filter");
989
990 rb->rest = r->headers_in.content_length_n;
991
992 if (rb->rest == 0) {
993
994 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
995 if (tl == NULL) {
996 return NGX_HTTP_INTERNAL_SERVER_ERROR;
997 }
998
999 b = tl->buf;
1000
1001 ngx_memzero(b, sizeof(ngx_buf_t));
1002
1003 b->last_buf = 1;
1004
1005 *ll = tl;
1006 ll = &tl->next;
1007 }
1008 }
1009
1010 for (cl = in; cl; cl = cl->next) {
1011
1012 if (rb->rest == 0) {
1013 break;
1014 }
1015
1016 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1017 if (tl == NULL) {
1018 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1019 }
1020
1021 b = tl->buf;
1022
1023 ngx_memzero(b, sizeof(ngx_buf_t));
1024
1025 b->temporary = 1;
1026 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
1027 b->start = cl->buf->pos;
1028 b->pos = cl->buf->pos;
1029 b->last = cl->buf->last;
1030 b->end = cl->buf->end;
1031 b->flush = r->request_body_no_buffering;
1032
1033 size = cl->buf->last - cl->buf->pos;
1034
1035 if ((off_t) size < rb->rest) {
1036 cl->buf->pos = cl->buf->last;
1037 rb->rest -= size;
1038
1039 } else {
1040 cl->buf->pos += (size_t) rb->rest;
1041 rb->rest = 0;
1042 b->last = cl->buf->pos;
1043 b->last_buf = 1;
1044 }
1045
1046 *ll = tl;
1047 ll = &tl->next;
1048 }
1049
1050 rc = ngx_http_top_request_body_filter(r, out);
1051
1052 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1053 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
1054
1055 return rc;
1056 }
1057
1058
1059 static ngx_int_t
ngx_http_request_body_chunked_filter(ngx_http_request_t * r,ngx_chain_t * in)1060 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
1061 {
1062 size_t size;
1063 ngx_int_t rc;
1064 ngx_buf_t *b;
1065 ngx_chain_t *cl, *out, *tl, **ll;
1066 ngx_http_request_body_t *rb;
1067 ngx_http_core_loc_conf_t *clcf;
1068 ngx_http_core_srv_conf_t *cscf;
1069
1070 rb = r->request_body;
1071
1072 out = NULL;
1073 ll = &out;
1074
1075 if (rb->rest == -1) {
1076
1077 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1078 "http request body chunked filter");
1079
1080 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
1081 if (rb->chunked == NULL) {
1082 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1083 }
1084
1085 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1086
1087 r->headers_in.content_length_n = 0;
1088 rb->rest = cscf->large_client_header_buffers.size;
1089 }
1090
1091 for (cl = in; cl; cl = cl->next) {
1092
1093 b = NULL;
1094
1095 for ( ;; ) {
1096
1097 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1098 "http body chunked buf "
1099 "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
1100 cl->buf->temporary, cl->buf->in_file,
1101 cl->buf->start, cl->buf->pos,
1102 cl->buf->last - cl->buf->pos,
1103 cl->buf->file_pos,
1104 cl->buf->file_last - cl->buf->file_pos);
1105
1106 rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
1107
1108 if (rc == NGX_OK) {
1109
1110 /* a chunk has been parsed successfully */
1111
1112 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
1113
1114 if (clcf->client_max_body_size
1115 && clcf->client_max_body_size
1116 - r->headers_in.content_length_n < rb->chunked->size)
1117 {
1118 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1119 "client intended to send too large chunked "
1120 "body: %O+%O bytes",
1121 r->headers_in.content_length_n,
1122 rb->chunked->size);
1123
1124 r->lingering_close = 1;
1125
1126 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
1127 }
1128
1129 if (b
1130 && rb->chunked->size <= 128
1131 && cl->buf->last - cl->buf->pos >= rb->chunked->size)
1132 {
1133 r->headers_in.content_length_n += rb->chunked->size;
1134
1135 if (rb->chunked->size < 8) {
1136
1137 while (rb->chunked->size) {
1138 *b->last++ = *cl->buf->pos++;
1139 rb->chunked->size--;
1140 }
1141
1142 } else {
1143 ngx_memmove(b->last, cl->buf->pos, rb->chunked->size);
1144 b->last += rb->chunked->size;
1145 cl->buf->pos += rb->chunked->size;
1146 rb->chunked->size = 0;
1147 }
1148
1149 continue;
1150 }
1151
1152 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1153 if (tl == NULL) {
1154 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1155 }
1156
1157 b = tl->buf;
1158
1159 ngx_memzero(b, sizeof(ngx_buf_t));
1160
1161 b->temporary = 1;
1162 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
1163 b->start = cl->buf->pos;
1164 b->pos = cl->buf->pos;
1165 b->last = cl->buf->last;
1166 b->end = cl->buf->end;
1167 b->flush = r->request_body_no_buffering;
1168
1169 *ll = tl;
1170 ll = &tl->next;
1171
1172 size = cl->buf->last - cl->buf->pos;
1173
1174 if ((off_t) size > rb->chunked->size) {
1175 cl->buf->pos += (size_t) rb->chunked->size;
1176 r->headers_in.content_length_n += rb->chunked->size;
1177 rb->chunked->size = 0;
1178
1179 } else {
1180 rb->chunked->size -= size;
1181 r->headers_in.content_length_n += size;
1182 cl->buf->pos = cl->buf->last;
1183 }
1184
1185 b->last = cl->buf->pos;
1186
1187 continue;
1188 }
1189
1190 if (rc == NGX_DONE) {
1191
1192 /* a whole response has been parsed successfully */
1193
1194 rb->rest = 0;
1195
1196 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1197 if (tl == NULL) {
1198 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1199 }
1200
1201 b = tl->buf;
1202
1203 ngx_memzero(b, sizeof(ngx_buf_t));
1204
1205 b->last_buf = 1;
1206
1207 *ll = tl;
1208 ll = &tl->next;
1209
1210 break;
1211 }
1212
1213 if (rc == NGX_AGAIN) {
1214
1215 /* set rb->rest, amount of data we want to see next time */
1216
1217 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1218
1219 rb->rest = ngx_max(rb->chunked->length,
1220 (off_t) cscf->large_client_header_buffers.size);
1221
1222 break;
1223 }
1224
1225 /* invalid */
1226
1227 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1228 "client sent invalid chunked body");
1229
1230 return NGX_HTTP_BAD_REQUEST;
1231 }
1232 }
1233
1234 rc = ngx_http_top_request_body_filter(r, out);
1235
1236 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1237 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
1238
1239 return rc;
1240 }
1241
1242
1243 ngx_int_t
ngx_http_request_body_save_filter(ngx_http_request_t * r,ngx_chain_t * in)1244 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
1245 {
1246 ngx_buf_t *b;
1247 ngx_chain_t *cl, *tl, **ll;
1248 ngx_http_request_body_t *rb;
1249
1250 rb = r->request_body;
1251
1252 ll = &rb->bufs;
1253
1254 for (cl = rb->bufs; cl; cl = cl->next) {
1255
1256 #if 0
1257 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1258 "http body old buf t:%d f:%d %p, pos %p, size: %z "
1259 "file: %O, size: %O",
1260 cl->buf->temporary, cl->buf->in_file,
1261 cl->buf->start, cl->buf->pos,
1262 cl->buf->last - cl->buf->pos,
1263 cl->buf->file_pos,
1264 cl->buf->file_last - cl->buf->file_pos);
1265 #endif
1266
1267 ll = &cl->next;
1268 }
1269
1270 for (cl = in; cl; cl = cl->next) {
1271
1272 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1273 "http body new buf t:%d f:%d %p, pos %p, size: %z "
1274 "file: %O, size: %O",
1275 cl->buf->temporary, cl->buf->in_file,
1276 cl->buf->start, cl->buf->pos,
1277 cl->buf->last - cl->buf->pos,
1278 cl->buf->file_pos,
1279 cl->buf->file_last - cl->buf->file_pos);
1280
1281 if (cl->buf->last_buf) {
1282
1283 if (rb->last_saved) {
1284 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1285 "duplicate last buf in save filter");
1286 *ll = NULL;
1287 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1288 }
1289
1290 rb->last_saved = 1;
1291 }
1292
1293 tl = ngx_alloc_chain_link(r->pool);
1294 if (tl == NULL) {
1295 *ll = NULL;
1296 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1297 }
1298
1299 tl->buf = cl->buf;
1300 *ll = tl;
1301 ll = &tl->next;
1302 }
1303
1304 *ll = NULL;
1305
1306 if (r->request_body_no_buffering) {
1307 return NGX_OK;
1308 }
1309
1310 if (rb->rest > 0) {
1311
1312 if (rb->bufs && rb->buf && rb->buf->last == rb->buf->end
1313 && ngx_http_write_request_body(r) != NGX_OK)
1314 {
1315 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1316 }
1317
1318 return NGX_OK;
1319 }
1320
1321 if (!rb->last_saved) {
1322 return NGX_OK;
1323 }
1324
1325 if (rb->temp_file || r->request_body_in_file_only) {
1326
1327 if (rb->bufs && rb->bufs->buf->in_file) {
1328 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
1329 "body already in file");
1330 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1331 }
1332
1333 if (ngx_http_write_request_body(r) != NGX_OK) {
1334 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1335 }
1336
1337 if (rb->temp_file->file.offset != 0) {
1338
1339 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
1340 if (cl == NULL) {
1341 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1342 }
1343
1344 b = cl->buf;
1345
1346 ngx_memzero(b, sizeof(ngx_buf_t));
1347
1348 b->in_file = 1;
1349 b->file_last = rb->temp_file->file.offset;
1350 b->file = &rb->temp_file->file;
1351
1352 rb->bufs = cl;
1353 }
1354 }
1355
1356 return NGX_OK;
1357 }
1358