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