Update and clean Tomato RAF files
[tomato.git] / release / src / router / nginx / src / http / ngx_http_request_body.c
blob2c612311d0a65b6e3fab06d2c21822edf98b6247
2 /*
3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
5 */
8 #include <ngx_config.h>
9 #include <ngx_core.h>
10 #include <ngx_http.h>
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);
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 static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
28 ngx_chain_t *in);
31 ngx_int_t
32 ngx_http_read_client_request_body(ngx_http_request_t *r,
33 ngx_http_client_body_handler_pt post_handler)
35 size_t preread;
36 ssize_t size;
37 ngx_int_t rc;
38 ngx_buf_t *b;
39 ngx_chain_t out, *cl;
40 ngx_http_request_body_t *rb;
41 ngx_http_core_loc_conf_t *clcf;
43 r->main->count++;
45 #if (NGX_HTTP_SPDY)
46 if (r->spdy_stream) {
47 rc = ngx_http_spdy_read_request_body(r, post_handler);
48 goto done;
50 #endif
52 if (r != r->main || r->request_body || r->discard_body) {
53 post_handler(r);
54 return NGX_OK;
57 if (ngx_http_test_expect(r) != NGX_OK) {
58 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
59 goto done;
62 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
63 if (rb == NULL) {
64 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
65 goto done;
69 * set by ngx_pcalloc():
71 * rb->bufs = NULL;
72 * rb->buf = NULL;
73 * rb->free = NULL;
74 * rb->busy = NULL;
75 * rb->chunked = NULL;
78 rb->rest = -1;
79 rb->post_handler = post_handler;
81 r->request_body = rb;
83 if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
84 post_handler(r);
85 return NGX_OK;
88 preread = r->header_in->last - r->header_in->pos;
90 if (preread) {
92 /* there is the pre-read part of the request body */
94 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
95 "http client request body preread %uz", preread);
97 out.buf = r->header_in;
98 out.next = NULL;
100 rc = ngx_http_request_body_filter(r, &out);
102 if (rc != NGX_OK) {
103 goto done;
106 r->request_length += preread - (r->header_in->last - r->header_in->pos);
108 if (!r->headers_in.chunked
109 && rb->rest > 0
110 && rb->rest <= (off_t) (r->header_in->end - r->header_in->last))
112 /* the whole request body may be placed in r->header_in */
114 b = ngx_calloc_buf(r->pool);
115 if (b == NULL) {
116 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
117 goto done;
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;
126 rb->buf = b;
128 r->read_event_handler = ngx_http_read_client_request_body_handler;
129 r->write_event_handler = ngx_http_request_empty_handler;
131 rc = ngx_http_do_read_client_request_body(r);
132 goto done;
135 } else {
136 /* set rb->rest */
138 if (ngx_http_request_body_filter(r, NULL) != NGX_OK) {
139 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
140 goto done;
144 if (rb->rest == 0) {
145 /* the whole request body was pre-read */
147 if (r->request_body_in_file_only) {
148 if (ngx_http_write_request_body(r) != NGX_OK) {
149 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
150 goto done;
153 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
154 if (cl == NULL) {
155 return NGX_HTTP_INTERNAL_SERVER_ERROR;
158 b = cl->buf;
160 ngx_memzero(b, sizeof(ngx_buf_t));
162 b->in_file = 1;
163 b->file_last = rb->temp_file->file.offset;
164 b->file = &rb->temp_file->file;
166 rb->bufs = cl;
169 post_handler(r);
171 return NGX_OK;
174 if (rb->rest < 0) {
175 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,
176 "negative request body rest");
177 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
178 goto done;
181 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
183 size = clcf->client_body_buffer_size;
184 size += size >> 2;
186 /* TODO: honor r->request_body_in_single_buf */
188 if (!r->headers_in.chunked && rb->rest < size) {
189 size = (ssize_t) rb->rest;
191 if (r->request_body_in_single_buf) {
192 size += preread;
195 } else {
196 size = clcf->client_body_buffer_size;
199 rb->buf = ngx_create_temp_buf(r->pool, size);
200 if (rb->buf == NULL) {
201 rc = NGX_HTTP_INTERNAL_SERVER_ERROR;
202 goto done;
205 r->read_event_handler = ngx_http_read_client_request_body_handler;
206 r->write_event_handler = ngx_http_request_empty_handler;
208 rc = ngx_http_do_read_client_request_body(r);
210 done:
212 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
213 r->main->count--;
216 return rc;
220 static void
221 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
223 ngx_int_t rc;
225 if (r->connection->read->timedout) {
226 r->connection->timedout = 1;
227 ngx_http_finalize_request(r, NGX_HTTP_REQUEST_TIME_OUT);
228 return;
231 rc = ngx_http_do_read_client_request_body(r);
233 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
234 ngx_http_finalize_request(r, rc);
239 static ngx_int_t
240 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
242 off_t rest;
243 size_t size;
244 ssize_t n;
245 ngx_int_t rc;
246 ngx_buf_t *b;
247 ngx_chain_t *cl, out;
248 ngx_connection_t *c;
249 ngx_http_request_body_t *rb;
250 ngx_http_core_loc_conf_t *clcf;
252 c = r->connection;
253 rb = r->request_body;
255 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
256 "http read client request body");
258 for ( ;; ) {
259 for ( ;; ) {
260 if (rb->buf->last == rb->buf->end) {
262 /* pass buffer to request body filter chain */
264 out.buf = rb->buf;
265 out.next = NULL;
267 rc = ngx_http_request_body_filter(r, &out);
269 if (rc != NGX_OK) {
270 return rc;
273 /* write to file */
275 if (ngx_http_write_request_body(r) != NGX_OK) {
276 return NGX_HTTP_INTERNAL_SERVER_ERROR;
279 /* update chains */
281 rc = ngx_http_request_body_filter(r, NULL);
283 if (rc != NGX_OK) {
284 return rc;
287 if (rb->busy != NULL) {
288 return NGX_HTTP_INTERNAL_SERVER_ERROR;
291 rb->buf->pos = rb->buf->start;
292 rb->buf->last = rb->buf->start;
295 size = rb->buf->end - rb->buf->last;
296 rest = rb->rest - (rb->buf->last - rb->buf->pos);
298 if ((off_t) size > rest) {
299 size = (size_t) rest;
302 n = c->recv(c, rb->buf->last, size);
304 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
305 "http client request body recv %z", n);
307 if (n == NGX_AGAIN) {
308 break;
311 if (n == 0) {
312 ngx_log_error(NGX_LOG_INFO, c->log, 0,
313 "client prematurely closed connection");
316 if (n == 0 || n == NGX_ERROR) {
317 c->error = 1;
318 return NGX_HTTP_BAD_REQUEST;
321 rb->buf->last += n;
322 r->request_length += n;
324 if (n == rest) {
325 /* pass buffer to request body filter chain */
327 out.buf = rb->buf;
328 out.next = NULL;
330 rc = ngx_http_request_body_filter(r, &out);
332 if (rc != NGX_OK) {
333 return rc;
337 if (rb->rest == 0) {
338 break;
341 if (rb->buf->last < rb->buf->end) {
342 break;
346 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, c->log, 0,
347 "http client request body rest %O", rb->rest);
349 if (rb->rest == 0) {
350 break;
353 if (!c->read->ready) {
354 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
355 ngx_add_timer(c->read, clcf->client_body_timeout);
357 if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
358 return NGX_HTTP_INTERNAL_SERVER_ERROR;
361 return NGX_AGAIN;
365 if (c->read->timer_set) {
366 ngx_del_timer(c->read);
369 if (rb->temp_file || r->request_body_in_file_only) {
371 /* save the last part */
373 if (ngx_http_write_request_body(r) != NGX_OK) {
374 return NGX_HTTP_INTERNAL_SERVER_ERROR;
377 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
378 if (cl == NULL) {
379 return NGX_HTTP_INTERNAL_SERVER_ERROR;
382 b = cl->buf;
384 ngx_memzero(b, sizeof(ngx_buf_t));
386 b->in_file = 1;
387 b->file_last = rb->temp_file->file.offset;
388 b->file = &rb->temp_file->file;
390 rb->bufs = cl;
393 r->read_event_handler = ngx_http_block_reading;
395 rb->post_handler(r);
397 return NGX_OK;
401 static ngx_int_t
402 ngx_http_write_request_body(ngx_http_request_t *r)
404 ssize_t n;
405 ngx_chain_t *cl;
406 ngx_temp_file_t *tf;
407 ngx_http_request_body_t *rb;
408 ngx_http_core_loc_conf_t *clcf;
410 rb = r->request_body;
412 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
413 "http write client request body, bufs %p", rb->bufs);
415 if (rb->temp_file == NULL) {
416 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
417 if (tf == NULL) {
418 return NGX_ERROR;
421 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
423 tf->file.fd = NGX_INVALID_FILE;
424 tf->file.log = r->connection->log;
425 tf->path = clcf->client_body_temp_path;
426 tf->pool = r->pool;
427 tf->warn = "a client request body is buffered to a temporary file";
428 tf->log_level = r->request_body_file_log_level;
429 tf->persistent = r->request_body_in_persistent_file;
430 tf->clean = r->request_body_in_clean_file;
432 if (r->request_body_file_group_access) {
433 tf->access = 0660;
436 rb->temp_file = tf;
438 if (rb->bufs == NULL) {
439 /* empty body with r->request_body_in_file_only */
441 if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
442 tf->persistent, tf->clean, tf->access)
443 != NGX_OK)
445 return NGX_ERROR;
448 return NGX_OK;
452 if (rb->bufs == NULL) {
453 return NGX_OK;
456 n = ngx_write_chain_to_temp_file(rb->temp_file, rb->bufs);
458 /* TODO: n == 0 or not complete and level event */
460 if (n == NGX_ERROR) {
461 return NGX_ERROR;
464 rb->temp_file->offset += n;
466 /* mark all buffers as written */
468 for (cl = rb->bufs; cl; cl = cl->next) {
469 cl->buf->pos = cl->buf->last;
472 rb->bufs = NULL;
474 return NGX_OK;
478 ngx_int_t
479 ngx_http_discard_request_body(ngx_http_request_t *r)
481 ssize_t size;
482 ngx_int_t rc;
483 ngx_event_t *rev;
485 #if (NGX_HTTP_SPDY)
486 if (r->spdy_stream && r == r->main) {
487 r->spdy_stream->skip_data = NGX_SPDY_DATA_DISCARD;
488 return NGX_OK;
490 #endif
492 if (r != r->main || r->discard_body || r->request_body) {
493 return NGX_OK;
496 if (ngx_http_test_expect(r) != NGX_OK) {
497 return NGX_HTTP_INTERNAL_SERVER_ERROR;
500 rev = r->connection->read;
502 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
504 if (rev->timer_set) {
505 ngx_del_timer(rev);
508 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
509 return NGX_OK;
512 size = r->header_in->last - r->header_in->pos;
514 if (size || r->headers_in.chunked) {
515 rc = ngx_http_discard_request_body_filter(r, r->header_in);
517 if (rc != NGX_OK) {
518 return rc;
521 if (r->headers_in.content_length_n == 0) {
522 return NGX_OK;
526 rc = ngx_http_read_discarded_request_body(r);
528 if (rc == NGX_OK) {
529 r->lingering_close = 0;
530 return NGX_OK;
533 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
534 return rc;
537 /* rc == NGX_AGAIN */
539 r->read_event_handler = ngx_http_discarded_request_body_handler;
541 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
542 return NGX_HTTP_INTERNAL_SERVER_ERROR;
545 r->count++;
546 r->discard_body = 1;
548 return NGX_OK;
552 void
553 ngx_http_discarded_request_body_handler(ngx_http_request_t *r)
555 ngx_int_t rc;
556 ngx_msec_t timer;
557 ngx_event_t *rev;
558 ngx_connection_t *c;
559 ngx_http_core_loc_conf_t *clcf;
561 c = r->connection;
562 rev = c->read;
564 if (rev->timedout) {
565 c->timedout = 1;
566 c->error = 1;
567 ngx_http_finalize_request(r, NGX_ERROR);
568 return;
571 if (r->lingering_time) {
572 timer = (ngx_msec_t) (r->lingering_time - ngx_time());
574 if (timer <= 0) {
575 r->discard_body = 0;
576 r->lingering_close = 0;
577 ngx_http_finalize_request(r, NGX_ERROR);
578 return;
581 } else {
582 timer = 0;
585 rc = ngx_http_read_discarded_request_body(r);
587 if (rc == NGX_OK) {
588 r->discard_body = 0;
589 r->lingering_close = 0;
590 ngx_http_finalize_request(r, NGX_DONE);
591 return;
594 if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
595 c->error = 1;
596 ngx_http_finalize_request(r, NGX_ERROR);
597 return;
600 /* rc == NGX_AGAIN */
602 if (ngx_handle_read_event(rev, 0) != NGX_OK) {
603 c->error = 1;
604 ngx_http_finalize_request(r, NGX_ERROR);
605 return;
608 if (timer) {
610 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
612 timer *= 1000;
614 if (timer > clcf->lingering_timeout) {
615 timer = clcf->lingering_timeout;
618 ngx_add_timer(rev, timer);
623 static ngx_int_t
624 ngx_http_read_discarded_request_body(ngx_http_request_t *r)
626 size_t size;
627 ssize_t n;
628 ngx_int_t rc;
629 ngx_buf_t b;
630 u_char buffer[NGX_HTTP_DISCARD_BUFFER_SIZE];
632 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
633 "http read discarded body");
635 ngx_memzero(&b, sizeof(ngx_buf_t));
637 b.temporary = 1;
639 for ( ;; ) {
640 if (r->headers_in.content_length_n == 0) {
641 r->read_event_handler = ngx_http_block_reading;
642 return NGX_OK;
645 if (!r->connection->read->ready) {
646 return NGX_AGAIN;
649 size = (size_t) ngx_min(r->headers_in.content_length_n,
650 NGX_HTTP_DISCARD_BUFFER_SIZE);
652 n = r->connection->recv(r->connection, buffer, size);
654 if (n == NGX_ERROR) {
655 r->connection->error = 1;
656 return NGX_OK;
659 if (n == NGX_AGAIN) {
660 return NGX_AGAIN;
663 if (n == 0) {
664 return NGX_OK;
667 b.pos = buffer;
668 b.last = buffer + n;
670 rc = ngx_http_discard_request_body_filter(r, &b);
672 if (rc != NGX_OK) {
673 return rc;
679 static ngx_int_t
680 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
682 size_t size;
683 ngx_int_t rc;
684 ngx_http_request_body_t *rb;
686 if (r->headers_in.chunked) {
688 rb = r->request_body;
690 if (rb == NULL) {
692 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
693 if (rb == NULL) {
694 return NGX_HTTP_INTERNAL_SERVER_ERROR;
697 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
698 if (rb->chunked == NULL) {
699 return NGX_HTTP_INTERNAL_SERVER_ERROR;
702 r->request_body = rb;
705 for ( ;; ) {
707 rc = ngx_http_parse_chunked(r, b, rb->chunked);
709 if (rc == NGX_OK) {
711 /* a chunk has been parsed successfully */
713 size = b->last - b->pos;
715 if ((off_t) size > rb->chunked->size) {
716 b->pos += rb->chunked->size;
717 rb->chunked->size = 0;
719 } else {
720 rb->chunked->size -= size;
721 b->pos = b->last;
724 continue;
727 if (rc == NGX_DONE) {
729 /* a whole response has been parsed successfully */
731 r->headers_in.content_length_n = 0;
732 break;
735 if (rc == NGX_AGAIN) {
737 /* set amount of data we want to see next time */
739 r->headers_in.content_length_n = rb->chunked->length;
740 break;
743 /* invalid */
745 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
746 "client sent invalid chunked body");
748 return NGX_HTTP_BAD_REQUEST;
751 } else {
752 size = b->last - b->pos;
754 if ((off_t) size > r->headers_in.content_length_n) {
755 b->pos += r->headers_in.content_length_n;
756 r->headers_in.content_length_n = 0;
758 } else {
759 b->pos = b->last;
760 r->headers_in.content_length_n -= size;
764 return NGX_OK;
768 static ngx_int_t
769 ngx_http_test_expect(ngx_http_request_t *r)
771 ngx_int_t n;
772 ngx_str_t *expect;
774 if (r->expect_tested
775 || r->headers_in.expect == NULL
776 || r->http_version < NGX_HTTP_VERSION_11)
778 return NGX_OK;
781 r->expect_tested = 1;
783 expect = &r->headers_in.expect->value;
785 if (expect->len != sizeof("100-continue") - 1
786 || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
787 sizeof("100-continue") - 1)
788 != 0)
790 return NGX_OK;
793 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
794 "send 100 Continue");
796 n = r->connection->send(r->connection,
797 (u_char *) "HTTP/1.1 100 Continue" CRLF CRLF,
798 sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1);
800 if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
801 return NGX_OK;
804 /* we assume that such small packet should be send successfully */
806 return NGX_ERROR;
810 static ngx_int_t
811 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
813 if (r->headers_in.chunked) {
814 return ngx_http_request_body_chunked_filter(r, in);
816 } else {
817 return ngx_http_request_body_length_filter(r, in);
822 static ngx_int_t
823 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
825 size_t size;
826 ngx_int_t rc;
827 ngx_buf_t *b;
828 ngx_chain_t *cl, *tl, *out, **ll;
829 ngx_http_request_body_t *rb;
831 rb = r->request_body;
833 if (rb->rest == -1) {
834 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
835 "http request body content length filter");
837 rb->rest = r->headers_in.content_length_n;
840 out = NULL;
841 ll = &out;
843 for (cl = in; cl; cl = cl->next) {
845 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
846 if (tl == NULL) {
847 return NGX_HTTP_INTERNAL_SERVER_ERROR;
850 b = tl->buf;
852 ngx_memzero(b, sizeof(ngx_buf_t));
854 b->temporary = 1;
855 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
856 b->start = cl->buf->pos;
857 b->pos = cl->buf->pos;
858 b->last = cl->buf->last;
859 b->end = cl->buf->end;
861 size = cl->buf->last - cl->buf->pos;
863 if ((off_t) size < rb->rest) {
864 cl->buf->pos = cl->buf->last;
865 rb->rest -= size;
867 } else {
868 cl->buf->pos += rb->rest;
869 rb->rest = 0;
870 b->last = cl->buf->pos;
871 b->last_buf = 1;
874 *ll = tl;
875 ll = &tl->next;
878 rc = ngx_http_request_body_save_filter(r, out);
880 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
881 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
883 return rc;
887 static ngx_int_t
888 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
890 size_t size;
891 ngx_int_t rc;
892 ngx_buf_t *b;
893 ngx_chain_t *cl, *out, *tl, **ll;
894 ngx_http_request_body_t *rb;
895 ngx_http_core_loc_conf_t *clcf;
897 rb = r->request_body;
899 if (rb->rest == -1) {
901 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
902 "http request body chunked filter");
904 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
905 if (rb->chunked == NULL) {
906 return NGX_HTTP_INTERNAL_SERVER_ERROR;
909 r->headers_in.content_length_n = 0;
910 rb->rest = 3;
913 out = NULL;
914 ll = &out;
916 for (cl = in; cl; cl = cl->next) {
918 for ( ;; ) {
920 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
921 "http body chunked buf "
922 "t:%d f:%d %p, pos %p, size: %z file: %O, size: %z",
923 cl->buf->temporary, cl->buf->in_file,
924 cl->buf->start, cl->buf->pos,
925 cl->buf->last - cl->buf->pos,
926 cl->buf->file_pos,
927 cl->buf->file_last - cl->buf->file_pos);
929 rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
931 if (rc == NGX_OK) {
933 /* a chunk has been parsed successfully */
935 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module);
937 if (clcf->client_max_body_size
938 && clcf->client_max_body_size
939 < r->headers_in.content_length_n + rb->chunked->size)
941 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
942 "client intended to send too large chunked "
943 "body: %O bytes",
944 r->headers_in.content_length_n
945 + rb->chunked->size);
947 r->lingering_close = 1;
949 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE;
952 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
953 if (tl == NULL) {
954 return NGX_HTTP_INTERNAL_SERVER_ERROR;
957 b = tl->buf;
959 ngx_memzero(b, sizeof(ngx_buf_t));
961 b->temporary = 1;
962 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
963 b->start = cl->buf->pos;
964 b->pos = cl->buf->pos;
965 b->last = cl->buf->last;
966 b->end = cl->buf->end;
968 *ll = tl;
969 ll = &tl->next;
971 size = cl->buf->last - cl->buf->pos;
973 if ((off_t) size > rb->chunked->size) {
974 cl->buf->pos += rb->chunked->size;
975 r->headers_in.content_length_n += rb->chunked->size;
976 rb->chunked->size = 0;
978 } else {
979 rb->chunked->size -= size;
980 r->headers_in.content_length_n += size;
981 cl->buf->pos = cl->buf->last;
984 b->last = cl->buf->pos;
986 continue;
989 if (rc == NGX_DONE) {
991 /* a whole response has been parsed successfully */
993 rb->rest = 0;
995 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
996 if (tl == NULL) {
997 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1000 b = tl->buf;
1002 ngx_memzero(b, sizeof(ngx_buf_t));
1004 b->last_buf = 1;
1006 *ll = tl;
1007 ll = &tl->next;
1009 break;
1012 if (rc == NGX_AGAIN) {
1014 /* set rb->rest, amount of data we want to see next time */
1016 rb->rest = rb->chunked->length;
1018 break;
1021 /* invalid */
1023 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1024 "client sent invalid chunked body");
1026 return NGX_HTTP_BAD_REQUEST;
1030 rc = ngx_http_request_body_save_filter(r, out);
1032 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1033 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
1035 return rc;
1039 static ngx_int_t
1040 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
1042 #if (NGX_DEBUG)
1043 ngx_chain_t *cl;
1044 #endif
1045 ngx_http_request_body_t *rb;
1047 rb = r->request_body;
1049 #if (NGX_DEBUG)
1051 for (cl = rb->bufs; cl; cl = cl->next) {
1052 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1053 "http body old buf t:%d f:%d %p, pos %p, size: %z "
1054 "file: %O, size: %z",
1055 cl->buf->temporary, cl->buf->in_file,
1056 cl->buf->start, cl->buf->pos,
1057 cl->buf->last - cl->buf->pos,
1058 cl->buf->file_pos,
1059 cl->buf->file_last - cl->buf->file_pos);
1062 for (cl = in; cl; cl = cl->next) {
1063 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1064 "http body new buf t:%d f:%d %p, pos %p, size: %z "
1065 "file: %O, size: %z",
1066 cl->buf->temporary, cl->buf->in_file,
1067 cl->buf->start, cl->buf->pos,
1068 cl->buf->last - cl->buf->pos,
1069 cl->buf->file_pos,
1070 cl->buf->file_last - cl->buf->file_pos);
1073 #endif
1075 /* TODO: coalesce neighbouring buffers */
1077 if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
1078 return NGX_HTTP_INTERNAL_SERVER_ERROR;
1081 return NGX_OK;