Groonga 3.0.9 Source Code Document
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Macros Pages
ngx_http_request_body.c
Go to the documentation of this file.
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 static ngx_int_t ngx_http_request_body_save_filter(ngx_http_request_t *r,
28  ngx_chain_t *in);
29 
30 
34 {
35  size_t preread;
36  ssize_t size;
37  ngx_int_t rc;
38  ngx_buf_t *b;
39  ngx_chain_t out, *cl;
42 
43  r->main->count++;
44 
45 #if (NGX_HTTP_SPDY)
46  if (r->spdy_stream) {
47  rc = ngx_http_spdy_read_request_body(r, post_handler);
48  goto done;
49  }
50 #endif
51 
52  if (r != r->main || r->request_body || r->discard_body) {
53  post_handler(r);
54  return NGX_OK;
55  }
56 
57  if (ngx_http_test_expect(r) != NGX_OK) {
59  goto done;
60  }
61 
62  rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
63  if (rb == NULL) {
65  goto done;
66  }
67 
68  /*
69  * set by ngx_pcalloc():
70  *
71  * rb->bufs = NULL;
72  * rb->buf = NULL;
73  * rb->free = NULL;
74  * rb->busy = NULL;
75  * rb->chunked = NULL;
76  */
77 
78  rb->rest = -1;
79  rb->post_handler = post_handler;
80 
81  r->request_body = rb;
82 
83  if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
84  post_handler(r);
85  return NGX_OK;
86  }
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 
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) {
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;
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) {
140  goto done;
141  }
142  }
143 
144  if (rb->rest == 0) {
145  /* the whole request body was pre-read */
146 
147  if (r->request_body_in_file_only) {
148  if (ngx_http_write_request_body(r) != NGX_OK) {
150  goto done;
151  }
152 
153  cl = ngx_chain_get_free_buf(r->pool, &rb->free);
154  if (cl == NULL) {
156  }
157 
158  b = cl->buf;
159 
160  ngx_memzero(b, sizeof(ngx_buf_t));
161 
162  b->in_file = 1;
163  b->file_last = rb->temp_file->file.offset;
164  b->file = &rb->temp_file->file;
165 
166  rb->bufs = cl;
167  }
168 
169  post_handler(r);
170 
171  return NGX_OK;
172  }
173 
174  if (rb->rest < 0) {
176  "negative request body rest");
178  goto done;
179  }
180 
182 
183  size = clcf->client_body_buffer_size;
184  size += size >> 2;
185 
186  /* TODO: honor r->request_body_in_single_buf */
187 
188  if (!r->headers_in.chunked && rb->rest < size) {
189  size = (ssize_t) rb->rest;
190 
192  size += preread;
193  }
194 
195  } else {
196  size = clcf->client_body_buffer_size;
197  }
198 
199  rb->buf = ngx_create_temp_buf(r->pool, size);
200  if (rb->buf == NULL) {
202  goto done;
203  }
204 
205  r->read_event_handler = ngx_http_read_client_request_body_handler;
207 
208  rc = ngx_http_do_read_client_request_body(r);
209 
210 done:
211 
212  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
213  r->main->count--;
214  }
215 
216  return rc;
217 }
218 
219 
220 static void
221 ngx_http_read_client_request_body_handler(ngx_http_request_t *r)
222 {
223  ngx_int_t rc;
224 
225  if (r->connection->read->timedout) {
226  r->connection->timedout = 1;
228  return;
229  }
230 
231  rc = ngx_http_do_read_client_request_body(r);
232 
233  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
235  }
236 }
237 
238 
239 static ngx_int_t
240 ngx_http_do_read_client_request_body(ngx_http_request_t *r)
241 {
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;
251 
252  c = r->connection;
253  rb = r->request_body;
254 
256  "http read client request body");
257 
258  for ( ;; ) {
259  for ( ;; ) {
260  if (rb->buf->last == rb->buf->end) {
261 
262  /* pass buffer to request body filter chain */
263 
264  out.buf = rb->buf;
265  out.next = NULL;
266 
267  rc = ngx_http_request_body_filter(r, &out);
268 
269  if (rc != NGX_OK) {
270  return rc;
271  }
272 
273  /* write to file */
274 
275  if (ngx_http_write_request_body(r) != NGX_OK) {
277  }
278 
279  /* update chains */
280 
281  rc = ngx_http_request_body_filter(r, NULL);
282 
283  if (rc != NGX_OK) {
284  return rc;
285  }
286 
287  if (rb->busy != NULL) {
289  }
290 
291  rb->buf->pos = rb->buf->start;
292  rb->buf->last = rb->buf->start;
293  }
294 
295  size = rb->buf->end - rb->buf->last;
296  rest = rb->rest - (rb->buf->last - rb->buf->pos);
297 
298  if ((off_t) size > rest) {
299  size = (size_t) rest;
300  }
301 
302  n = c->recv(c, rb->buf->last, size);
303 
305  "http client request body recv %z", n);
306 
307  if (n == NGX_AGAIN) {
308  break;
309  }
310 
311  if (n == 0) {
313  "client prematurely closed connection");
314  }
315 
316  if (n == 0 || n == NGX_ERROR) {
317  c->error = 1;
318  return NGX_HTTP_BAD_REQUEST;
319  }
320 
321  rb->buf->last += n;
322  r->request_length += n;
323 
324  if (n == rest) {
325  /* pass buffer to request body filter chain */
326 
327  out.buf = rb->buf;
328  out.next = NULL;
329 
330  rc = ngx_http_request_body_filter(r, &out);
331 
332  if (rc != NGX_OK) {
333  return rc;
334  }
335  }
336 
337  if (rb->rest == 0) {
338  break;
339  }
340 
341  if (rb->buf->last < rb->buf->end) {
342  break;
343  }
344  }
345 
347  "http client request body rest %O", rb->rest);
348 
349  if (rb->rest == 0) {
350  break;
351  }
352 
353  if (!c->read->ready) {
356 
357  if (ngx_handle_read_event(c->read, 0) != NGX_OK) {
359  }
360 
361  return NGX_AGAIN;
362  }
363  }
364 
365  if (c->read->timer_set) {
366  ngx_del_timer(c->read);
367  }
368 
369  if (rb->temp_file || r->request_body_in_file_only) {
370 
371  /* save the last part */
372 
373  if (ngx_http_write_request_body(r) != NGX_OK) {
375  }
376 
377  cl = ngx_chain_get_free_buf(r->pool, &rb->free);
378  if (cl == NULL) {
380  }
381 
382  b = cl->buf;
383 
384  ngx_memzero(b, sizeof(ngx_buf_t));
385 
386  b->in_file = 1;
387  b->file_last = rb->temp_file->file.offset;
388  b->file = &rb->temp_file->file;
389 
390  rb->bufs = cl;
391  }
392 
394 
395  rb->post_handler(r);
396 
397  return NGX_OK;
398 }
399 
400 
401 static ngx_int_t
402 ngx_http_write_request_body(ngx_http_request_t *r)
403 {
404  ssize_t n;
405  ngx_chain_t *cl;
406  ngx_temp_file_t *tf;
409 
410  rb = r->request_body;
411 
413  "http write client request body, bufs %p", rb->bufs);
414 
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;
419  }
420 
422 
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";
431 
433  tf->access = 0660;
434  }
435 
436  rb->temp_file = tf;
437 
438  if (rb->bufs == NULL) {
439  /* empty body with r->request_body_in_file_only */
440 
441  if (ngx_create_temp_file(&tf->file, tf->path, tf->pool,
442  tf->persistent, tf->clean, tf->access)
443  != NGX_OK)
444  {
445  return NGX_ERROR;
446  }
447 
448  return NGX_OK;
449  }
450  }
451 
452  if (rb->bufs == NULL) {
453  return NGX_OK;
454  }
455 
457 
458  /* TODO: n == 0 or not complete and level event */
459 
460  if (n == NGX_ERROR) {
461  return NGX_ERROR;
462  }
463 
464  rb->temp_file->offset += n;
465 
466  /* mark all buffers as written */
467 
468  for (cl = rb->bufs; cl; cl = cl->next) {
469  cl->buf->pos = cl->buf->last;
470  }
471 
472  rb->bufs = NULL;
473 
474  return NGX_OK;
475 }
476 
477 
478 ngx_int_t
480 {
481  ssize_t size;
482  ngx_int_t rc;
483  ngx_event_t *rev;
484 
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;
489  }
490 #endif
491 
492  if (r != r->main || r->discard_body || r->request_body) {
493  return NGX_OK;
494  }
495 
496  if (ngx_http_test_expect(r) != NGX_OK) {
498  }
499 
500  rev = r->connection->read;
501 
502  ngx_log_debug0(NGX_LOG_DEBUG_HTTP, rev->log, 0, "http set discard body");
503 
504  if (rev->timer_set) {
505  ngx_del_timer(rev);
506  }
507 
508  if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
509  return NGX_OK;
510  }
511 
512  size = r->header_in->last - r->header_in->pos;
513 
514  if (size || r->headers_in.chunked) {
515  rc = ngx_http_discard_request_body_filter(r, r->header_in);
516 
517  if (rc != NGX_OK) {
518  return rc;
519  }
520 
521  if (r->headers_in.content_length_n == 0) {
522  return NGX_OK;
523  }
524  }
525 
526  rc = ngx_http_read_discarded_request_body(r);
527 
528  if (rc == NGX_OK) {
529  r->lingering_close = 0;
530  return NGX_OK;
531  }
532 
533  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
534  return rc;
535  }
536 
537  /* rc == NGX_AGAIN */
538 
540 
541  if (ngx_handle_read_event(rev, 0) != NGX_OK) {
543  }
544 
545  r->count++;
546  r->discard_body = 1;
547 
548  return NGX_OK;
549 }
550 
551 
552 void
554 {
555  ngx_int_t rc;
556  ngx_msec_t timer;
557  ngx_event_t *rev;
558  ngx_connection_t *c;
560 
561  c = r->connection;
562  rev = c->read;
563 
564  if (rev->timedout) {
565  c->timedout = 1;
566  c->error = 1;
568  return;
569  }
570 
571  if (r->lingering_time) {
572  timer = (ngx_msec_t) (r->lingering_time - ngx_time());
573 
574  if (timer <= 0) {
575  r->discard_body = 0;
576  r->lingering_close = 0;
578  return;
579  }
580 
581  } else {
582  timer = 0;
583  }
584 
585  rc = ngx_http_read_discarded_request_body(r);
586 
587  if (rc == NGX_OK) {
588  r->discard_body = 0;
589  r->lingering_close = 0;
591  return;
592  }
593 
594  if (rc >= NGX_HTTP_SPECIAL_RESPONSE) {
595  c->error = 1;
597  return;
598  }
599 
600  /* rc == NGX_AGAIN */
601 
602  if (ngx_handle_read_event(rev, 0) != NGX_OK) {
603  c->error = 1;
605  return;
606  }
607 
608  if (timer) {
609 
611 
612  timer *= 1000;
613 
614  if (timer > clcf->lingering_timeout) {
615  timer = clcf->lingering_timeout;
616  }
617 
618  ngx_add_timer(rev, timer);
619  }
620 }
621 
622 
623 static ngx_int_t
624 ngx_http_read_discarded_request_body(ngx_http_request_t *r)
625 {
626  size_t size;
627  ssize_t n;
628  ngx_int_t rc;
629  ngx_buf_t b;
631 
633  "http read discarded body");
634 
635  ngx_memzero(&b, sizeof(ngx_buf_t));
636 
637  b.temporary = 1;
638 
639  for ( ;; ) {
640  if (r->headers_in.content_length_n == 0) {
642  return NGX_OK;
643  }
644 
645  if (!r->connection->read->ready) {
646  return NGX_AGAIN;
647  }
648 
649  size = (size_t) ngx_min(r->headers_in.content_length_n,
651 
652  n = r->connection->recv(r->connection, buffer, size);
653 
654  if (n == NGX_ERROR) {
655  r->connection->error = 1;
656  return NGX_OK;
657  }
658 
659  if (n == NGX_AGAIN) {
660  return NGX_AGAIN;
661  }
662 
663  if (n == 0) {
664  return NGX_OK;
665  }
666 
667  b.pos = buffer;
668  b.last = buffer + n;
669 
670  rc = ngx_http_discard_request_body_filter(r, &b);
671 
672  if (rc != NGX_OK) {
673  return rc;
674  }
675  }
676 }
677 
678 
679 static ngx_int_t
680 ngx_http_discard_request_body_filter(ngx_http_request_t *r, ngx_buf_t *b)
681 {
682  size_t size;
683  ngx_int_t rc;
685 
686  if (r->headers_in.chunked) {
687 
688  rb = r->request_body;
689 
690  if (rb == NULL) {
691 
692  rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
693  if (rb == NULL) {
695  }
696 
697  rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
698  if (rb->chunked == NULL) {
700  }
701 
702  r->request_body = rb;
703  }
704 
705  for ( ;; ) {
706 
707  rc = ngx_http_parse_chunked(r, b, rb->chunked);
708 
709  if (rc == NGX_OK) {
710 
711  /* a chunk has been parsed successfully */
712 
713  size = b->last - b->pos;
714 
715  if ((off_t) size > rb->chunked->size) {
716  b->pos += rb->chunked->size;
717  rb->chunked->size = 0;
718 
719  } else {
720  rb->chunked->size -= size;
721  b->pos = b->last;
722  }
723 
724  continue;
725  }
726 
727  if (rc == NGX_DONE) {
728 
729  /* a whole response has been parsed successfully */
730 
732  break;
733  }
734 
735  if (rc == NGX_AGAIN) {
736 
737  /* set amount of data we want to see next time */
738 
740  break;
741  }
742 
743  /* invalid */
744 
746  "client sent invalid chunked body");
747 
748  return NGX_HTTP_BAD_REQUEST;
749  }
750 
751  } else {
752  size = b->last - b->pos;
753 
754  if ((off_t) size > r->headers_in.content_length_n) {
757 
758  } else {
759  b->pos = b->last;
760  r->headers_in.content_length_n -= size;
761  }
762  }
763 
764  return NGX_OK;
765 }
766 
767 
768 static ngx_int_t
769 ngx_http_test_expect(ngx_http_request_t *r)
770 {
771  ngx_int_t n;
772  ngx_str_t *expect;
773 
774  if (r->expect_tested
775  || r->headers_in.expect == NULL
777  {
778  return NGX_OK;
779  }
780 
781  r->expect_tested = 1;
782 
783  expect = &r->headers_in.expect->value;
784 
785  if (expect->len != sizeof("100-continue") - 1
786  || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
787  sizeof("100-continue") - 1)
788  != 0)
789  {
790  return NGX_OK;
791  }
792 
794  "send 100 Continue");
795 
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);
799 
800  if (n == sizeof("HTTP/1.1 100 Continue" CRLF CRLF) - 1) {
801  return NGX_OK;
802  }
803 
804  /* we assume that such small packet should be send successfully */
805 
806  return NGX_ERROR;
807 }
808 
809 
810 static ngx_int_t
811 ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
812 {
813  if (r->headers_in.chunked) {
814  return ngx_http_request_body_chunked_filter(r, in);
815 
816  } else {
817  return ngx_http_request_body_length_filter(r, in);
818  }
819 }
820 
821 
822 static ngx_int_t
823 ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
824 {
825  size_t size;
826  ngx_int_t rc;
827  ngx_buf_t *b;
828  ngx_chain_t *cl, *tl, *out, **ll;
830 
831  rb = r->request_body;
832 
833  if (rb->rest == -1) {
835  "http request body content length filter");
836 
838  }
839 
840  out = NULL;
841  ll = &out;
842 
843  for (cl = in; cl; cl = cl->next) {
844 
845  tl = ngx_chain_get_free_buf(r->pool, &rb->free);
846  if (tl == NULL) {
848  }
849 
850  b = tl->buf;
851 
852  ngx_memzero(b, sizeof(ngx_buf_t));
853 
854  b->temporary = 1;
856  b->start = cl->buf->pos;
857  b->pos = cl->buf->pos;
858  b->last = cl->buf->last;
859  b->end = cl->buf->end;
860 
861  size = cl->buf->last - cl->buf->pos;
862 
863  if ((off_t) size < rb->rest) {
864  cl->buf->pos = cl->buf->last;
865  rb->rest -= size;
866 
867  } else {
868  cl->buf->pos += rb->rest;
869  rb->rest = 0;
870  b->last = cl->buf->pos;
871  b->last_buf = 1;
872  }
873 
874  *ll = tl;
875  ll = &tl->next;
876  }
877 
878  rc = ngx_http_request_body_save_filter(r, out);
879 
880  ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
882 
883  return rc;
884 }
885 
886 
887 static ngx_int_t
888 ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
889 {
890  size_t size;
891  ngx_int_t rc;
892  ngx_buf_t *b;
893  ngx_chain_t *cl, *out, *tl, **ll;
896 
897  rb = r->request_body;
898 
899  if (rb->rest == -1) {
900 
902  "http request body chunked filter");
903 
904  rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
905  if (rb->chunked == NULL) {
907  }
908 
910  rb->rest = 3;
911  }
912 
913  out = NULL;
914  ll = &out;
915 
916  for (cl = in; cl; cl = cl->next) {
917 
918  for ( ;; ) {
919 
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);
928 
929  rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
930 
931  if (rc == NGX_OK) {
932 
933  /* a chunk has been parsed successfully */
934 
936 
937  if (clcf->client_max_body_size
938  && clcf->client_max_body_size
940  {
942  "client intended to send too large chunked "
943  "body: %O bytes",
945  + rb->chunked->size);
946 
947  r->lingering_close = 1;
948 
950  }
951 
952  tl = ngx_chain_get_free_buf(r->pool, &rb->free);
953  if (tl == NULL) {
955  }
956 
957  b = tl->buf;
958 
959  ngx_memzero(b, sizeof(ngx_buf_t));
960 
961  b->temporary = 1;
963  b->start = cl->buf->pos;
964  b->pos = cl->buf->pos;
965  b->last = cl->buf->last;
966  b->end = cl->buf->end;
967 
968  *ll = tl;
969  ll = &tl->next;
970 
971  size = cl->buf->last - cl->buf->pos;
972 
973  if ((off_t) size > rb->chunked->size) {
974  cl->buf->pos += rb->chunked->size;
976  rb->chunked->size = 0;
977 
978  } else {
979  rb->chunked->size -= size;
980  r->headers_in.content_length_n += size;
981  cl->buf->pos = cl->buf->last;
982  }
983 
984  b->last = cl->buf->pos;
985 
986  continue;
987  }
988 
989  if (rc == NGX_DONE) {
990 
991  /* a whole response has been parsed successfully */
992 
993  rb->rest = 0;
994 
995  tl = ngx_chain_get_free_buf(r->pool, &rb->free);
996  if (tl == NULL) {
998  }
999 
1000  b = tl->buf;
1001 
1002  ngx_memzero(b, sizeof(ngx_buf_t));
1003 
1004  b->last_buf = 1;
1005 
1006  *ll = tl;
1007  ll = &tl->next;
1008 
1009  break;
1010  }
1011 
1012  if (rc == NGX_AGAIN) {
1013 
1014  /* set rb->rest, amount of data we want to see next time */
1015 
1016  rb->rest = rb->chunked->length;
1017 
1018  break;
1019  }
1020 
1021  /* invalid */
1022 
1024  "client sent invalid chunked body");
1025 
1026  return NGX_HTTP_BAD_REQUEST;
1027  }
1028  }
1029 
1030  rc = ngx_http_request_body_save_filter(r, out);
1031 
1032  ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1034 
1035  return rc;
1036 }
1037 
1038 
1039 static ngx_int_t
1040 ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
1041 {
1042 #if (NGX_DEBUG)
1043  ngx_chain_t *cl;
1044 #endif
1046 
1047  rb = r->request_body;
1048 
1049 #if (NGX_DEBUG)
1050 
1051  for (cl = rb->bufs; cl; cl = cl->next) {
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);
1060  }
1061 
1062  for (cl = in; cl; cl = cl->next) {
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);
1071  }
1072 
1073 #endif
1074 
1075  /* TODO: coalesce neighbouring buffers */
1076 
1077  if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK) {
1079  }
1080 
1081  return NGX_OK;
1082 }