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