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