comparison src/http/ngx_http_spdy_filter_module.c @ 5514:b7ee1bae0ffa

SPDY: implemented buffers chain splitting. It fixes "chain too big in spdy filter" alerts, and adds full support for rate limiting of SPDY streams.
author Valentin Bartenev <vbart@nginx.com>
date Tue, 14 Jan 2014 16:24:45 +0400
parents 311803b21504
children e5fb14e85040
comparison
equal deleted inserted replaced
5513:311803b21504 5514:b7ee1bae0ffa
32 ngx_chain_t *in, off_t limit); 32 ngx_chain_t *in, off_t limit);
33 33
34 static ngx_inline ngx_int_t ngx_http_spdy_filter_send( 34 static ngx_inline ngx_int_t ngx_http_spdy_filter_send(
35 ngx_connection_t *fc, ngx_http_spdy_stream_t *stream); 35 ngx_connection_t *fc, ngx_http_spdy_stream_t *stream);
36 36
37 static ngx_chain_t *ngx_http_spdy_filter_get_shadow(
38 ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, size_t offset,
39 size_t size);
37 static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame( 40 static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame(
38 ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first, 41 ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first,
39 ngx_chain_t *last); 42 ngx_chain_t *last);
40 43
41 static ngx_int_t ngx_http_spdy_syn_frame_handler( 44 static ngx_int_t ngx_http_spdy_syn_frame_handler(
616 619
617 620
618 static ngx_chain_t * 621 static ngx_chain_t *
619 ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) 622 ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit)
620 { 623 {
621 off_t size; 624 off_t size, offset;
622 ngx_buf_t *b; 625 size_t rest, frame_size;
623 ngx_chain_t *cl, *out, **ln; 626 ngx_chain_t *cl, *out, **ln;
624 ngx_http_request_t *r; 627 ngx_http_request_t *r;
625 ngx_http_spdy_stream_t *stream; 628 ngx_http_spdy_stream_t *stream;
626 ngx_http_spdy_out_frame_t *frame; 629 ngx_http_spdy_out_frame_t *frame;
627 630
637 } 640 }
638 641
639 return NULL; 642 return NULL;
640 } 643 }
641 644
642 size = 0; 645 size = ngx_buf_size(in->buf);
643 ln = &out; 646
644 647 if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
645 do {
646 b = in->buf;
647
648 cl = ngx_alloc_chain_link(r->pool); 648 cl = ngx_alloc_chain_link(r->pool);
649 if (cl == NULL) { 649 if (cl == NULL) {
650 return NGX_CHAIN_ERROR; 650 return NGX_CHAIN_ERROR;
651 } 651 }
652 652
653 size += ngx_buf_size(b); 653 cl->buf = in->buf;
654 cl->buf = b; 654 in->buf = cl->buf->shadow;
655 655
656 *ln = cl; 656 offset = ngx_buf_in_memory(in->buf)
657 ln = &cl->next; 657 ? (cl->buf->pos - in->buf->pos)
658 658 : (cl->buf->file_pos - in->buf->file_pos);
659 in = in->next; 659
660 660 cl->next = stream->free_bufs;
661 } while (in); 661 stream->free_bufs = cl;
662 662
663 if (size > NGX_SPDY_MAX_FRAME_SIZE) { 663 } else {
664 ngx_log_error(NGX_LOG_ALERT, fc->log, 0, 664 offset = 0;
665 "FIXME: chain too big in spdy filter: %O", size); 665 }
666 return NGX_CHAIN_ERROR; 666
667 } 667 frame_size = (limit && limit < NGX_SPDY_MAX_FRAME_SIZE)
668 668 ? limit : NGX_SPDY_MAX_FRAME_SIZE;
669 frame = ngx_http_spdy_filter_get_data_frame(stream, (size_t) size, 669
670 out, cl); 670 for ( ;; ) {
671 if (frame == NULL) { 671 ln = &out;
672 return NGX_CHAIN_ERROR; 672 rest = frame_size;
673 } 673
674 674 while ((off_t) rest >= size) {
675 ngx_http_spdy_queue_frame(stream->connection, frame); 675
676 676 if (offset) {
677 stream->queued++; 677 cl = ngx_http_spdy_filter_get_shadow(stream, in->buf,
678 offset, size);
679 if (cl == NULL) {
680 return NGX_CHAIN_ERROR;
681 }
682
683 offset = 0;
684
685 } else {
686 cl = ngx_alloc_chain_link(r->pool);
687 if (cl == NULL) {
688 return NGX_CHAIN_ERROR;
689 }
690
691 cl->buf = in->buf;
692 }
693
694 *ln = cl;
695 ln = &cl->next;
696
697 rest -= size;
698 in = in->next;
699
700 if (in == NULL) {
701 frame_size -= rest;
702 rest = 0;
703 break;
704 }
705
706 size = ngx_buf_size(in->buf);
707 }
708
709 if (rest) {
710 cl = ngx_http_spdy_filter_get_shadow(stream, in->buf,
711 offset, rest);
712 if (cl == NULL) {
713 return NGX_CHAIN_ERROR;
714 }
715
716 cl->buf->flush = 0;
717 cl->buf->last_buf = 0;
718
719 *ln = cl;
720
721 offset += rest;
722 size -= rest;
723 }
724
725 frame = ngx_http_spdy_filter_get_data_frame(stream, frame_size,
726 out, cl);
727 if (frame == NULL) {
728 return NGX_CHAIN_ERROR;
729 }
730
731 ngx_http_spdy_queue_frame(stream->connection, frame);
732
733 stream->queued++;
734
735 if (in == NULL) {
736 break;
737 }
738
739 if (limit) {
740 limit -= frame_size;
741
742 if (limit == 0) {
743 break;
744 }
745
746 if (limit < NGX_SPDY_MAX_FRAME_SIZE) {
747 frame_size = limit;
748 }
749 }
750 }
751
752 if (offset) {
753 cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size);
754 if (cl == NULL) {
755 return NGX_CHAIN_ERROR;
756 }
757
758 in->buf = cl->buf;
759 ngx_free_chain(r->pool, cl);
760 }
678 761
679 if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) { 762 if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) {
680 return NGX_CHAIN_ERROR; 763 return NGX_CHAIN_ERROR;
681 } 764 }
682 765
683 return NULL; 766 return in;
767 }
768
769
770 static ngx_chain_t *
771 ngx_http_spdy_filter_get_shadow(ngx_http_spdy_stream_t *stream, ngx_buf_t *buf,
772 size_t offset, size_t size)
773 {
774 ngx_buf_t *chunk;
775 ngx_chain_t *cl;
776
777 cl = ngx_chain_get_free_buf(stream->request->pool, &stream->free_bufs);
778 if (cl == NULL) {
779 return NULL;
780 }
781
782 chunk = cl->buf;
783
784 ngx_memcpy(chunk, buf, sizeof(ngx_buf_t));
785
786 chunk->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow;
787 chunk->shadow = buf;
788
789 if (ngx_buf_in_memory(chunk)) {
790 chunk->pos += offset;
791 chunk->last = chunk->pos + size;
792 }
793
794 if (chunk->in_file) {
795 chunk->file_pos += offset;
796 chunk->file_last = chunk->file_pos + size;
797 }
798
799 return cl;
684 } 800 }
685 801
686 802
687 static ngx_http_spdy_out_frame_t * 803 static ngx_http_spdy_out_frame_t *
688 ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream, 804 ngx_http_spdy_filter_get_data_frame(ngx_http_spdy_stream_t *stream,
745 p = ngx_spdy_frame_write_flags_and_len(p, flags, len); 861 p = ngx_spdy_frame_write_flags_and_len(p, flags, len);
746 862
747 buf->last = p; 863 buf->last = p;
748 buf->end = p; 864 buf->end = p;
749 865
750 buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_module; 866 buf->tag = (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame;
751 buf->memory = 1; 867 buf->memory = 1;
752 } 868 }
753 869
754 cl->next = first; 870 cl->next = first;
755 first = cl; 871 first = cl;
823 939
824 static ngx_int_t 940 static ngx_int_t
825 ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc, 941 ngx_http_spdy_data_frame_handler(ngx_http_spdy_connection_t *sc,
826 ngx_http_spdy_out_frame_t *frame) 942 ngx_http_spdy_out_frame_t *frame)
827 { 943 {
944 ngx_buf_t *buf;
828 ngx_chain_t *cl, *ln; 945 ngx_chain_t *cl, *ln;
829 ngx_http_spdy_stream_t *stream; 946 ngx_http_spdy_stream_t *stream;
830 947
831 stream = frame->stream; 948 stream = frame->stream;
832 949
833 cl = frame->first; 950 cl = frame->first;
834 951
835 if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_module) { 952 if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_data_frame) {
836 953
837 if (cl->buf->pos != cl->buf->last) { 954 if (cl->buf->pos != cl->buf->last) {
838 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0, 955 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, sc->connection->log, 0,
839 "spdy:%ui DATA frame %p was sent partially", 956 "spdy:%ui DATA frame %p was sent partially",
840 stream->id, frame); 957 stream->id, frame);
853 970
854 cl = ln; 971 cl = ln;
855 } 972 }
856 973
857 for ( ;; ) { 974 for ( ;; ) {
975 if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
976 buf = cl->buf->shadow;
977
978 if (ngx_buf_in_memory(buf)) {
979 buf->pos = cl->buf->pos;
980 }
981
982 if (buf->in_file) {
983 buf->file_pos = cl->buf->file_pos;
984 }
985 }
986
858 if (ngx_buf_size(cl->buf) != 0) { 987 if (ngx_buf_size(cl->buf) != 0) {
859 988
860 if (cl != frame->first) { 989 if (cl != frame->first) {
861 frame->first = cl; 990 frame->first = cl;
862 ngx_http_spdy_handle_stream(sc, stream); 991 ngx_http_spdy_handle_stream(sc, stream);
869 return NGX_AGAIN; 998 return NGX_AGAIN;
870 } 999 }
871 1000
872 ln = cl->next; 1001 ln = cl->next;
873 1002
874 ngx_free_chain(stream->request->pool, cl); 1003 if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) {
1004 cl->next = stream->free_bufs;
1005 stream->free_bufs = cl;
1006
1007 } else {
1008 ngx_free_chain(stream->request->pool, cl);
1009 }
875 1010
876 if (cl == frame->last) { 1011 if (cl == frame->last) {
877 goto done; 1012 goto done;
878 } 1013 }
879 1014