Bug Summary

File:http/ngx_http_request_body.c
Location:line 1141, column 13
Description:Dereference of null pointer

Annotated Source Code

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
13static void ngx_http_read_client_request_body_handler(ngx_http_request_t *r);
14static ngx_int_t ngx_http_do_read_client_request_body(ngx_http_request_t *r);
15static ngx_int_t ngx_http_write_request_body(ngx_http_request_t *r);
16static ngx_int_t ngx_http_read_discarded_request_body(ngx_http_request_t *r);
17static ngx_int_t ngx_http_discard_request_body_filter(ngx_http_request_t *r,
18 ngx_buf_t *b);
19static ngx_int_t ngx_http_test_expect(ngx_http_request_t *r);
20
21static ngx_int_t ngx_http_request_body_filter(ngx_http_request_t *r,
22 ngx_chain_t *in);
23static ngx_int_t ngx_http_request_body_length_filter(ngx_http_request_t *r,
24 ngx_chain_t *in);
25static ngx_int_t ngx_http_request_body_chunked_filter(ngx_http_request_t *r,
26 ngx_chain_t *in);
27
28
29ngx_int_t
30ngx_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_OK0;
47 }
48
49#if (NGX_HTTP_V2)
50 if (r->stream) {
51 rc = ngx_http_v2_read_request_body(r, post_handler);
52 goto done;
53 }
54#endif
55
56 if (ngx_http_test_expect(r) != NGX_OK0) {
57 rc = NGX_HTTP_INTERNAL_SERVER_ERROR500;
58 goto done;
59 }
60
61 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
62 if (rb == NULL((void*)0)) {
63 rc = NGX_HTTP_INTERNAL_SERVER_ERROR500;
64 goto done;
65 }
66
67 /*
68 * set by ngx_pcalloc():
69 *
70 * rb->bufs = NULL;
71 * rb->buf = NULL;
72 * rb->free = NULL;
73 * rb->busy = NULL;
74 * rb->chunked = NULL;
75 */
76
77 rb->rest = -1;
78 rb->post_handler = post_handler;
79
80 r->request_body = rb;
81
82 if (r->headers_in.content_length_n < 0 && !r->headers_in.chunked) {
83 r->request_body_no_buffering = 0;
84 post_handler(r);
85 return NGX_OK0;
86 }
87
88 preread = r->header_in->last - r->header_in->pos;
89
90 if (preread) {
91
92 /* there is the pre-read part of the request body */
93
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((void*)0);
99
100 rc = ngx_http_request_body_filter(r, &out);
101
102 if (rc != NGX_OK0) {
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)ngx_pcalloc(r->pool, sizeof(ngx_buf_t));
115 if (b == NULL((void*)0)) {
116 rc = NGX_HTTP_INTERNAL_SERVER_ERROR500;
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((void*)0)) != NGX_OK0) {
139 rc = NGX_HTTP_INTERNAL_SERVER_ERROR500;
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_OK0;
149 }
150
151 if (rb->rest < 0) {
152 ngx_log_error(NGX_LOG_ALERT, r->connection->log, 0,if ((r->connection->log)->log_level >= 2) ngx_log_error_core
(2, r->connection->log, 0, "negative request body rest"
)
153 "negative request body rest")if ((r->connection->log)->log_level >= 2) ngx_log_error_core
(2, r->connection->log, 0, "negative request body rest"
)
;
154 rc = NGX_HTTP_INTERNAL_SERVER_ERROR500;
155 goto done;
156 }
157
158 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module)(r)->loc_conf[ngx_http_core_module.ctx_index];
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((void*)0)) {
178 rc = NGX_HTTP_INTERNAL_SERVER_ERROR500;
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
187done:
188
189 if (r->request_body_no_buffering
190 && (rc == NGX_OK0 || rc == NGX_AGAIN-2))
191 {
192 if (rc == NGX_OK0) {
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_RESPONSE300) {
205 r->main->count--;
206 }
207
208 return rc;
209}
210
211
212ngx_int_t
213ngx_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_OK0) {
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_OUT408;
232 }
233
234 rc = ngx_http_do_read_client_request_body(r);
235
236 if (rc == NGX_OK0) {
237 r->reading_body = 0;
238 }
239
240 return rc;
241}
242
243
244static void
245ngx_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_OUT408);
252 return;
253 }
254
255 rc = ngx_http_do_read_client_request_body(r);
256
257 if (rc >= NGX_HTTP_SPECIAL_RESPONSE300) {
258 ngx_http_finalize_request(r, rc);
259 }
260}
261
262
263static ngx_int_t
264ngx_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((void*)0);
291
292 rc = ngx_http_request_body_filter(r, &out);
293
294 if (rc != NGX_OK0) {
295 return rc;
296 }
297
298 } else {
299
300 /* update chains */
301
302 rc = ngx_http_request_body_filter(r, NULL((void*)0));
303
304 if (rc != NGX_OK0) {
305 return rc;
306 }
307 }
308
309 if (rb->busy != NULL((void*)0)) {
310 if (r->request_body_no_buffering) {
311 if (c->read->timer_set) {
312 ngx_del_timerngx_event_del_timer(c->read);
313 }
314
315 if (ngx_handle_read_event(c->read, 0) != NGX_OK0) {
316 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
317 }
318
319 return NGX_AGAIN-2;
320 }
321
322 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
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-2) {
342 break;
343 }
344
345 if (n == 0) {
346 ngx_log_error(NGX_LOG_INFO, c->log, 0,if ((c->log)->log_level >= 7) ngx_log_error_core(7, c
->log, 0, "client prematurely closed connection")
347 "client prematurely closed connection")if ((c->log)->log_level >= 7) ngx_log_error_core(7, c
->log, 0, "client prematurely closed connection")
;
348 }
349
350 if (n == 0 || n == NGX_ERROR-1) {
351 c->error = 1;
352 return NGX_HTTP_BAD_REQUEST400;
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((void*)0);
363
364 rc = ngx_http_request_body_filter(r, &out);
365
366 if (rc != NGX_OK0) {
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((void*)0);
396
397 rc = ngx_http_request_body_filter(r, &out);
398
399 if (rc != NGX_OK0) {
400 return rc;
401 }
402 }
403
404 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module)(r)->loc_conf[ngx_http_core_module.ctx_index];
405 ngx_add_timerngx_event_add_timer(c->read, clcf->client_body_timeout);
406
407 if (ngx_handle_read_event(c->read, 0) != NGX_OK0) {
408 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
409 }
410
411 return NGX_AGAIN-2;
412 }
413 }
414
415 if (c->read->timer_set) {
416 ngx_del_timerngx_event_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_OK0;
425}
426
427
428static ngx_int_t
429ngx_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((void*)0)) {
443 tf = ngx_pcalloc(r->pool, sizeof(ngx_temp_file_t));
444 if (tf == NULL((void*)0)) {
445 return NGX_ERROR-1;
446 }
447
448 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module)(r)->loc_conf[ngx_http_core_module.ctx_index];
449
450 tf->file.fd = NGX_INVALID_FILE-1;
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((void*)0)) {
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_OK0)
471 {
472 return NGX_ERROR-1;
473 }
474
475 return NGX_OK0;
476 }
477 }
478
479 if (rb->bufs == NULL((void*)0)) {
480 return NGX_OK0;
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-1) {
488 return NGX_ERROR-1;
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)ln->next = r->pool->chain; r->pool->chain = ln;
502 }
503
504 rb->bufs = NULL((void*)0);
505
506 return NGX_OK0;
507}
508
509
510ngx_int_t
511ngx_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_OK0;
519 }
520
521#if (NGX_HTTP_V2)
522 if (r->stream) {
523 r->stream->skip_data = 1;
524 return NGX_OK0;
525 }
526#endif
527
528 if (ngx_http_test_expect(r) != NGX_OK0) {
529 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
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_timerngx_event_del_timer(rev);
538 }
539
540 if (r->headers_in.content_length_n <= 0 && !r->headers_in.chunked) {
541 return NGX_OK0;
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_OK0) {
550 return rc;
551 }
552
553 if (r->headers_in.content_length_n == 0) {
554 return NGX_OK0;
555 }
556 }
557
558 rc = ngx_http_read_discarded_request_body(r);
559
560 if (rc == NGX_OK0) {
561 r->lingering_close = 0;
562 return NGX_OK0;
563 }
564
565 if (rc >= NGX_HTTP_SPECIAL_RESPONSE300) {
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_OK0) {
574 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
575 }
576
577 r->count++;
578 r->discard_body = 1;
579
580 return NGX_OK0;
581}
582
583
584void
585ngx_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-1);
600 return;
601 }
602
603 if (r->lingering_time) {
604 timer = (ngx_msec_t) r->lingering_time - (ngx_msec_t) ngx_time()ngx_cached_time->sec;
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-1);
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_OK0) {
620 r->discard_body = 0;
621 r->lingering_close = 0;
622 ngx_http_finalize_request(r, NGX_DONE-4);
623 return;
624 }
625
626 if (rc >= NGX_HTTP_SPECIAL_RESPONSE300) {
627 c->error = 1;
628 ngx_http_finalize_request(r, NGX_ERROR-1);
629 return;
630 }
631
632 /* rc == NGX_AGAIN */
633
634 if (ngx_handle_read_event(rev, 0) != NGX_OK0) {
635 c->error = 1;
636 ngx_http_finalize_request(r, NGX_ERROR-1);
637 return;
638 }
639
640 if (timer) {
641
642 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module)(r)->loc_conf[ngx_http_core_module.ctx_index];
643
644 timer *= 1000;
645
646 if (timer > clcf->lingering_timeout) {
647 timer = clcf->lingering_timeout;
648 }
649
650 ngx_add_timerngx_event_add_timer(rev, timer);
651 }
652}
653
654
655static ngx_int_t
656ngx_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_SIZE4096];
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))(void) memset(&b, 0, 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_OK0;
675 }
676
677 if (!r->connection->read->ready) {
678 return NGX_AGAIN-2;
679 }
680
681 size = (size_t) ngx_min(r->headers_in.content_length_n,((r->headers_in.content_length_n > 4096) ? (4096) : (r->
headers_in.content_length_n))
682 NGX_HTTP_DISCARD_BUFFER_SIZE)((r->headers_in.content_length_n > 4096) ? (4096) : (r->
headers_in.content_length_n))
;
683
684 n = r->connection->recv(r->connection, buffer, size);
685
686 if (n == NGX_ERROR-1) {
687 r->connection->error = 1;
688 return NGX_OK0;
689 }
690
691 if (n == NGX_AGAIN-2) {
692 return NGX_AGAIN-2;
693 }
694
695 if (n == 0) {
696 return NGX_OK0;
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_OK0) {
705 return rc;
706 }
707 }
708}
709
710
711static ngx_int_t
712ngx_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((void*)0)) {
723
724 rb = ngx_pcalloc(r->pool, sizeof(ngx_http_request_body_t));
725 if (rb == NULL((void*)0)) {
726 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
727 }
728
729 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
730 if (rb->chunked == NULL((void*)0)) {
731 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
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_OK0) {
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-4) {
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-2) {
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,if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client sent invalid chunked body"
)
778 "client sent invalid chunked body")if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client sent invalid chunked body"
)
;
779
780 return NGX_HTTP_BAD_REQUEST400;
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_OK0;
797}
798
799
800static ngx_int_t
801ngx_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((void*)0)
808 || r->http_version < NGX_HTTP_VERSION_111001)
809 {
810 return NGX_OK0;
811 }
812
813 r->expect_tested = 1;
814
815 expect = &r->headers_in.expect->value;
816
817 if (expect->len != sizeof("100-continue") - 1
818 || ngx_strncasecmp(expect->data, (u_char *) "100-continue",
819 sizeof("100-continue") - 1)
820 != 0)
821 {
822 return NGX_OK0;
823 }
824
825 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
826 "send 100 Continue");
827
828 n = r->connection->send(r->connection,
829 (u_char *) "HTTP/1.1 100 Continue" CRLF"\r\n" CRLF"\r\n",
830 sizeof("HTTP/1.1 100 Continue" CRLF"\r\n" CRLF"\r\n") - 1);
831
832 if (n == sizeof("HTTP/1.1 100 Continue" CRLF"\r\n" CRLF"\r\n") - 1) {
833 return NGX_OK0;
834 }
835
836 /* we assume that such small packet should be send successfully */
837
838 return NGX_ERROR-1;
839}
840
841
842static ngx_int_t
843ngx_http_request_body_filter(ngx_http_request_t *r, ngx_chain_t *in)
844{
845 if (r->headers_in.chunked) {
846 return ngx_http_request_body_chunked_filter(r, in);
847
848 } else {
849 return ngx_http_request_body_length_filter(r, in);
850 }
851}
852
853
854static ngx_int_t
855ngx_http_request_body_length_filter(ngx_http_request_t *r, ngx_chain_t *in)
856{
857 size_t size;
858 ngx_int_t rc;
859 ngx_buf_t *b;
860 ngx_chain_t *cl, *tl, *out, **ll;
861 ngx_http_request_body_t *rb;
862
863 rb = r->request_body;
864
865 if (rb->rest == -1) {
866 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
867 "http request body content length filter");
868
869 rb->rest = r->headers_in.content_length_n;
870 }
871
872 out = NULL((void*)0);
873 ll = &out;
874
875 for (cl = in; cl; cl = cl->next) {
876
877 if (rb->rest == 0) {
878 break;
879 }
880
881 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
882 if (tl == NULL((void*)0)) {
883 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
884 }
885
886 b = tl->buf;
887
888 ngx_memzero(b, sizeof(ngx_buf_t))(void) memset(b, 0, sizeof(ngx_buf_t));
889
890 b->temporary = 1;
891 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
892 b->start = cl->buf->pos;
893 b->pos = cl->buf->pos;
894 b->last = cl->buf->last;
895 b->end = cl->buf->end;
896 b->flush = r->request_body_no_buffering;
897
898 size = cl->buf->last - cl->buf->pos;
899
900 if ((off_t) size < rb->rest) {
901 cl->buf->pos = cl->buf->last;
902 rb->rest -= size;
903
904 } else {
905 cl->buf->pos += (size_t) rb->rest;
906 rb->rest = 0;
907 b->last = cl->buf->pos;
908 b->last_buf = 1;
909 }
910
911 *ll = tl;
912 ll = &tl->next;
913 }
914
915 rc = ngx_http_top_request_body_filter(r, out);
916
917 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
918 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
919
920 return rc;
921}
922
923
924static ngx_int_t
925ngx_http_request_body_chunked_filter(ngx_http_request_t *r, ngx_chain_t *in)
926{
927 size_t size;
928 ngx_int_t rc;
929 ngx_buf_t *b;
930 ngx_chain_t *cl, *out, *tl, **ll;
931 ngx_http_request_body_t *rb;
932 ngx_http_core_loc_conf_t *clcf;
933
934 rb = r->request_body;
935
936 if (rb->rest == -1) {
937
938 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
939 "http request body chunked filter");
940
941 rb->chunked = ngx_pcalloc(r->pool, sizeof(ngx_http_chunked_t));
942 if (rb->chunked == NULL((void*)0)) {
943 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
944 }
945
946 r->headers_in.content_length_n = 0;
947 rb->rest = 3;
948 }
949
950 out = NULL((void*)0);
951 ll = &out;
952
953 for (cl = in; cl; cl = cl->next) {
954
955 for ( ;; ) {
956
957 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
958 "http body chunked buf "
959 "t:%d f:%d %p, pos %p, size: %z file: %O, size: %O",
960 cl->buf->temporary, cl->buf->in_file,
961 cl->buf->start, cl->buf->pos,
962 cl->buf->last - cl->buf->pos,
963 cl->buf->file_pos,
964 cl->buf->file_last - cl->buf->file_pos);
965
966 rc = ngx_http_parse_chunked(r, cl->buf, rb->chunked);
967
968 if (rc == NGX_OK0) {
969
970 /* a chunk has been parsed successfully */
971
972 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module)(r)->loc_conf[ngx_http_core_module.ctx_index];
973
974 if (clcf->client_max_body_size
975 && clcf->client_max_body_size
976 - r->headers_in.content_length_n < rb->chunked->size)
977 {
978 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client intended to send too large chunked "
"body: %O+%O bytes", r->headers_in.content_length_n, rb->
chunked->size)
979 "client intended to send too large chunked "if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client intended to send too large chunked "
"body: %O+%O bytes", r->headers_in.content_length_n, rb->
chunked->size)
980 "body: %O+%O bytes",if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client intended to send too large chunked "
"body: %O+%O bytes", r->headers_in.content_length_n, rb->
chunked->size)
981 r->headers_in.content_length_n,if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client intended to send too large chunked "
"body: %O+%O bytes", r->headers_in.content_length_n, rb->
chunked->size)
982 rb->chunked->size)if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client intended to send too large chunked "
"body: %O+%O bytes", r->headers_in.content_length_n, rb->
chunked->size)
;
983
984 r->lingering_close = 1;
985
986 return NGX_HTTP_REQUEST_ENTITY_TOO_LARGE413;
987 }
988
989 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
990 if (tl == NULL((void*)0)) {
991 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
992 }
993
994 b = tl->buf;
995
996 ngx_memzero(b, sizeof(ngx_buf_t))(void) memset(b, 0, sizeof(ngx_buf_t));
997
998 b->temporary = 1;
999 b->tag = (ngx_buf_tag_t) &ngx_http_read_client_request_body;
1000 b->start = cl->buf->pos;
1001 b->pos = cl->buf->pos;
1002 b->last = cl->buf->last;
1003 b->end = cl->buf->end;
1004 b->flush = r->request_body_no_buffering;
1005
1006 *ll = tl;
1007 ll = &tl->next;
1008
1009 size = cl->buf->last - cl->buf->pos;
1010
1011 if ((off_t) size > rb->chunked->size) {
1012 cl->buf->pos += (size_t) rb->chunked->size;
1013 r->headers_in.content_length_n += rb->chunked->size;
1014 rb->chunked->size = 0;
1015
1016 } else {
1017 rb->chunked->size -= size;
1018 r->headers_in.content_length_n += size;
1019 cl->buf->pos = cl->buf->last;
1020 }
1021
1022 b->last = cl->buf->pos;
1023
1024 continue;
1025 }
1026
1027 if (rc == NGX_DONE-4) {
1028
1029 /* a whole response has been parsed successfully */
1030
1031 rb->rest = 0;
1032
1033 tl = ngx_chain_get_free_buf(r->pool, &rb->free);
1034 if (tl == NULL((void*)0)) {
1035 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
1036 }
1037
1038 b = tl->buf;
1039
1040 ngx_memzero(b, sizeof(ngx_buf_t))(void) memset(b, 0, sizeof(ngx_buf_t));
1041
1042 b->last_buf = 1;
1043
1044 *ll = tl;
1045 ll = &tl->next;
1046
1047 break;
1048 }
1049
1050 if (rc == NGX_AGAIN-2) {
1051
1052 /* set rb->rest, amount of data we want to see next time */
1053
1054 rb->rest = rb->chunked->length;
1055
1056 break;
1057 }
1058
1059 /* invalid */
1060
1061 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client sent invalid chunked body"
)
1062 "client sent invalid chunked body")if ((r->connection->log)->log_level >= 4) ngx_log_error_core
(4, r->connection->log, 0, "client sent invalid chunked body"
)
;
1063
1064 return NGX_HTTP_BAD_REQUEST400;
1065 }
1066 }
1067
1068 rc = ngx_http_top_request_body_filter(r, out);
1069
1070 ngx_chain_update_chains(r->pool, &rb->free, &rb->busy, &out,
1071 (ngx_buf_tag_t) &ngx_http_read_client_request_body);
1072
1073 return rc;
1074}
1075
1076
1077ngx_int_t
1078ngx_http_request_body_save_filter(ngx_http_request_t *r, ngx_chain_t *in)
1079{
1080 ngx_buf_t *b;
1081 ngx_chain_t *cl;
1082 ngx_http_request_body_t *rb;
1083
1084 rb = r->request_body;
1085
1086#if (NGX_DEBUG)
1087
1088 for (cl = rb->bufs; cl; cl = cl->next) {
1089 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1090 "http body old buf t:%d f:%d %p, pos %p, size: %z "
1091 "file: %O, size: %O",
1092 cl->buf->temporary, cl->buf->in_file,
1093 cl->buf->start, cl->buf->pos,
1094 cl->buf->last - cl->buf->pos,
1095 cl->buf->file_pos,
1096 cl->buf->file_last - cl->buf->file_pos);
1097 }
1098
1099 for (cl = in; cl; cl = cl->next) {
1100 ngx_log_debug7(NGX_LOG_DEBUG_EVENT, r->connection->log, 0,
1101 "http body new buf t:%d f:%d %p, pos %p, size: %z "
1102 "file: %O, size: %O",
1103 cl->buf->temporary, cl->buf->in_file,
1104 cl->buf->start, cl->buf->pos,
1105 cl->buf->last - cl->buf->pos,
1106 cl->buf->file_pos,
1107 cl->buf->file_last - cl->buf->file_pos);
1108 }
1109
1110#endif
1111
1112 /* TODO: coalesce neighbouring buffers */
1113
1114 if (ngx_chain_add_copy(r->pool, &rb->bufs, in) != NGX_OK0) {
1
Value assigned to field 'temp_file'
2
Taking false branch
1115 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
1116 }
1117
1118 if (r->request_body_no_buffering) {
3
Taking false branch
1119 return NGX_OK0;
1120 }
1121
1122 if (rb->rest > 0) {
4
Taking false branch
1123
1124 if (rb->buf && rb->buf->last == rb->buf->end
1125 && ngx_http_write_request_body(r) != NGX_OK0)
1126 {
1127 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
1128 }
1129
1130 return NGX_OK0;
1131 }
1132
1133 /* rb->rest == 0 */
1134
1135 if (rb->temp_file || r->request_body_in_file_only) {
5
Assuming pointer value is null
6
Taking true branch
1136
1137 if (ngx_http_write_request_body(r) != NGX_OK0) {
7
Taking false branch
1138 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
1139 }
1140
1141 if (rb->temp_file->file.offset != 0) {
8
Dereference of null pointer
1142
1143 cl = ngx_chain_get_free_buf(r->pool, &rb->free);
1144 if (cl == NULL((void*)0)) {
1145 return NGX_HTTP_INTERNAL_SERVER_ERROR500;
1146 }
1147
1148 b = cl->buf;
1149
1150 ngx_memzero(b, sizeof(ngx_buf_t))(void) memset(b, 0, sizeof(ngx_buf_t));
1151
1152 b->in_file = 1;
1153 b->file_last = rb->temp_file->file.offset;
1154 b->file = &rb->temp_file->file;
1155
1156 rb->bufs = cl;
1157 }
1158 }
1159
1160 return NGX_OK0;
1161}