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