Mercurial > hg > nginx
comparison src/event/ngx_event_pipe.c @ 4232:487ab473f393
Event pipe: fixes for complex protocols.
1. In ngx_event_pipe_write_chain_to_temp_file() make sure to fully write
all shadow buffers up to last_shadow. With this change recycled buffers
cannot appear in p->out anymore. This also fixes segmentation faults
observed due to ngx_event_pipe_write_chain_to_temp() not freeing any
raw buffers while still returning NGX_OK.
2. In ngx_event_pipe_write_to_downstream() we now properly check for busy
size as a size of buffers, not a size of data in these buffers. This
fixes situations where all available buffers became busy (including
segmentation faults due to this).
3. The ngx_event_pipe_free_shadow_raw_buf() function is dropped. It's
incorrect and not needed.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 31 Oct 2011 09:53:16 +0000 |
parents | 6b9b7e7ac4a9 |
children | aae172db7ac8 |
comparison
equal
deleted
inserted
replaced
4231:d50883ff2433 | 4232:487ab473f393 |
---|---|
13 static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p); | 13 static ngx_int_t ngx_event_pipe_read_upstream(ngx_event_pipe_t *p); |
14 static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p); | 14 static ngx_int_t ngx_event_pipe_write_to_downstream(ngx_event_pipe_t *p); |
15 | 15 |
16 static ngx_int_t ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p); | 16 static ngx_int_t ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p); |
17 static ngx_inline void ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf); | 17 static ngx_inline void ngx_event_pipe_remove_shadow_links(ngx_buf_t *buf); |
18 static ngx_inline void ngx_event_pipe_free_shadow_raw_buf(ngx_chain_t **free, | |
19 ngx_buf_t *buf); | |
20 static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p); | 18 static ngx_int_t ngx_event_pipe_drain_chains(ngx_event_pipe_t *p); |
21 | 19 |
22 | 20 |
23 ngx_int_t | 21 ngx_int_t |
24 ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) | 22 ngx_event_pipe(ngx_event_pipe_t *p, ngx_int_t do_write) |
574 | 572 |
575 for ( ;; ) { | 573 for ( ;; ) { |
576 if (p->out) { | 574 if (p->out) { |
577 cl = p->out; | 575 cl = p->out; |
578 | 576 |
579 if (cl->buf->recycled | 577 if (cl->buf->recycled) { |
580 && bsize + cl->buf->last - cl->buf->pos > p->busy_size) | 578 ngx_log_error(NGX_LOG_ALERT, p->log, 0, |
581 { | 579 "recycled buffer in pipe out chain"); |
582 flush = 1; | |
583 break; | |
584 } | 580 } |
585 | 581 |
586 p->out = p->out->next; | 582 p->out = p->out->next; |
587 | |
588 ngx_event_pipe_free_shadow_raw_buf(&p->free_raw_bufs, cl->buf); | |
589 | 583 |
590 } else if (!p->cacheable && p->in) { | 584 } else if (!p->cacheable && p->in) { |
591 cl = p->in; | 585 cl = p->in; |
592 | 586 |
593 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, | 587 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, |
594 "pipe write buf ls:%d %p %z", | 588 "pipe write buf ls:%d %p %z", |
595 cl->buf->last_shadow, | 589 cl->buf->last_shadow, |
596 cl->buf->pos, | 590 cl->buf->pos, |
597 cl->buf->last - cl->buf->pos); | 591 cl->buf->last - cl->buf->pos); |
598 | 592 |
599 if (cl->buf->recycled | 593 if (cl->buf->recycled && prev_last_shadow) { |
600 && cl->buf->last_shadow | 594 if (bsize + cl->buf->end - cl->buf->start > p->busy_size) { |
601 && bsize + cl->buf->last - cl->buf->pos > p->busy_size) | 595 flush = 1; |
602 { | 596 break; |
603 if (!prev_last_shadow) { | |
604 p->in = p->in->next; | |
605 | |
606 cl->next = NULL; | |
607 | |
608 if (out) { | |
609 *ll = cl; | |
610 } else { | |
611 out = cl; | |
612 } | |
613 } | 597 } |
614 | 598 |
615 flush = 1; | 599 bsize += cl->buf->end - cl->buf->start; |
616 break; | |
617 } | 600 } |
618 | 601 |
619 prev_last_shadow = cl->buf->last_shadow; | 602 prev_last_shadow = cl->buf->last_shadow; |
620 | 603 |
621 p->in = p->in->next; | 604 p->in = p->in->next; |
622 | 605 |
623 } else { | 606 } else { |
624 break; | 607 break; |
625 } | |
626 | |
627 if (cl->buf->recycled) { | |
628 bsize += cl->buf->last - cl->buf->pos; | |
629 } | 608 } |
630 | 609 |
631 cl->next = NULL; | 610 cl->next = NULL; |
632 | 611 |
633 if (out) { | 612 if (out) { |
701 static ngx_int_t | 680 static ngx_int_t |
702 ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) | 681 ngx_event_pipe_write_chain_to_temp_file(ngx_event_pipe_t *p) |
703 { | 682 { |
704 ssize_t size, bsize; | 683 ssize_t size, bsize; |
705 ngx_buf_t *b; | 684 ngx_buf_t *b; |
685 ngx_uint_t prev_last_shadow; | |
706 ngx_chain_t *cl, *tl, *next, *out, **ll, **last_free, fl; | 686 ngx_chain_t *cl, *tl, *next, *out, **ll, **last_free, fl; |
707 | 687 |
708 if (p->buf_to_file) { | 688 if (p->buf_to_file) { |
709 fl.buf = p->buf_to_file; | 689 fl.buf = p->buf_to_file; |
710 fl.next = p->in; | 690 fl.next = p->in; |
717 if (!p->cacheable) { | 697 if (!p->cacheable) { |
718 | 698 |
719 size = 0; | 699 size = 0; |
720 cl = out; | 700 cl = out; |
721 ll = NULL; | 701 ll = NULL; |
702 prev_last_shadow = 1; | |
722 | 703 |
723 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, | 704 ngx_log_debug1(NGX_LOG_DEBUG_EVENT, p->log, 0, |
724 "pipe offset: %O", p->temp_file->offset); | 705 "pipe offset: %O", p->temp_file->offset); |
725 | 706 |
726 do { | 707 do { |
727 bsize = cl->buf->last - cl->buf->pos; | 708 bsize = cl->buf->last - cl->buf->pos; |
728 | 709 |
729 ngx_log_debug3(NGX_LOG_DEBUG_EVENT, p->log, 0, | 710 ngx_log_debug4(NGX_LOG_DEBUG_EVENT, p->log, 0, |
730 "pipe buf %p, pos %p, size: %z", | 711 "pipe buf ls:%d %p, pos %p, size: %z", |
731 cl->buf->start, cl->buf->pos, bsize); | 712 cl->buf->last_shadow, cl->buf->start, |
732 | 713 cl->buf->pos, bsize); |
733 if ((size + bsize > p->temp_file_write_size) | 714 |
734 || (p->temp_file->offset + size + bsize > p->max_temp_file_size)) | 715 if (prev_last_shadow |
716 && ((size + bsize > p->temp_file_write_size) | |
717 || (p->temp_file->offset + size + bsize | |
718 > p->max_temp_file_size))) | |
735 { | 719 { |
736 break; | 720 break; |
737 } | 721 } |
722 | |
723 prev_last_shadow = cl->buf->last_shadow; | |
738 | 724 |
739 size += bsize; | 725 size += bsize; |
740 ll = &cl->next; | 726 ll = &cl->next; |
741 cl = cl->next; | 727 cl = cl->next; |
742 | 728 |
911 | 897 |
912 buf->shadow = NULL; | 898 buf->shadow = NULL; |
913 } | 899 } |
914 | 900 |
915 | 901 |
916 static ngx_inline void | |
917 ngx_event_pipe_free_shadow_raw_buf(ngx_chain_t **free, ngx_buf_t *buf) | |
918 { | |
919 ngx_buf_t *s; | |
920 ngx_chain_t *cl, **ll; | |
921 | |
922 if (buf->shadow == NULL) { | |
923 return; | |
924 } | |
925 | |
926 for (s = buf->shadow; !s->last_shadow; s = s->shadow) { /* void */ } | |
927 | |
928 ll = free; | |
929 | |
930 for (cl = *free; cl; cl = cl->next) { | |
931 if (cl->buf == s) { | |
932 *ll = cl->next; | |
933 break; | |
934 } | |
935 | |
936 if (cl->buf->shadow) { | |
937 break; | |
938 } | |
939 | |
940 ll = &cl->next; | |
941 } | |
942 } | |
943 | |
944 | |
945 ngx_int_t | 902 ngx_int_t |
946 ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b) | 903 ngx_event_pipe_add_free_buf(ngx_event_pipe_t *p, ngx_buf_t *b) |
947 { | 904 { |
948 ngx_chain_t *cl; | 905 ngx_chain_t *cl; |
949 | 906 |