Mercurial > hg > nginx
comparison src/http/ngx_http_spdy_filter_module.c @ 5549:39d7eef2e332
SPDY: protocol implementation switched to spdy/3.1.
author | Valentin Bartenev <vbart@nginx.com> |
---|---|
date | Fri, 31 Jan 2014 19:17:26 +0400 |
parents | 827e53c136b0 |
children | 2bc609a4b516 |
comparison
equal
deleted
inserted
replaced
5548:4d47722d76b2 | 5549:39d7eef2e332 |
---|---|
15 | 15 |
16 | 16 |
17 #define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1) | 17 #define ngx_http_spdy_nv_nsize(h) (NGX_SPDY_NV_NLEN_SIZE + sizeof(h) - 1) |
18 #define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1) | 18 #define ngx_http_spdy_nv_vsize(h) (NGX_SPDY_NV_VLEN_SIZE + sizeof(h) - 1) |
19 | 19 |
20 #define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint16 | 20 #define ngx_http_spdy_nv_write_num ngx_spdy_frame_write_uint32 |
21 #define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint16 | 21 #define ngx_http_spdy_nv_write_nlen ngx_spdy_frame_write_uint32 |
22 #define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint16 | 22 #define ngx_http_spdy_nv_write_vlen ngx_spdy_frame_write_uint32 |
23 | 23 |
24 #define ngx_http_spdy_nv_write_name(p, h) \ | 24 #define ngx_http_spdy_nv_write_name(p, h) \ |
25 ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1) | 25 ngx_cpymem(ngx_http_spdy_nv_write_nlen(p, sizeof(h) - 1), h, sizeof(h) - 1) |
26 | 26 |
27 #define ngx_http_spdy_nv_write_val(p, h) \ | 27 #define ngx_http_spdy_nv_write_val(p, h) \ |
31 static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc, | 31 static ngx_chain_t *ngx_http_spdy_send_chain(ngx_connection_t *fc, |
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 static ngx_inline ngx_int_t ngx_http_spdy_flow_control( | |
37 ngx_http_spdy_connection_t *sc, ngx_http_spdy_stream_t *stream); | |
38 static void ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, | |
39 ngx_http_spdy_stream_t *stream); | |
36 | 40 |
37 static ngx_chain_t *ngx_http_spdy_filter_get_shadow( | 41 static ngx_chain_t *ngx_http_spdy_filter_get_shadow( |
38 ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size); | 42 ngx_http_spdy_stream_t *stream, ngx_buf_t *buf, off_t offset, off_t size); |
39 static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame( | 43 static ngx_http_spdy_out_frame_t *ngx_http_spdy_filter_get_data_frame( |
40 ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first, | 44 ngx_http_spdy_stream_t *stream, size_t len, ngx_chain_t *first, |
160 r->headers_out.last_modified_time = -1; | 164 r->headers_out.last_modified_time = -1; |
161 r->headers_out.last_modified = NULL; | 165 r->headers_out.last_modified = NULL; |
162 } | 166 } |
163 | 167 |
164 len = NGX_SPDY_NV_NUM_SIZE | 168 len = NGX_SPDY_NV_NUM_SIZE |
165 + ngx_http_spdy_nv_nsize("version") | 169 + ngx_http_spdy_nv_nsize(":version") |
166 + ngx_http_spdy_nv_vsize("HTTP/1.1") | 170 + ngx_http_spdy_nv_vsize("HTTP/1.1") |
167 + ngx_http_spdy_nv_nsize("status") | 171 + ngx_http_spdy_nv_nsize(":status") |
168 + (r->headers_out.status_line.len | 172 + (r->headers_out.status_line.len |
169 ? NGX_SPDY_NV_VLEN_SIZE + r->headers_out.status_line.len | 173 ? NGX_SPDY_NV_VLEN_SIZE + r->headers_out.status_line.len |
170 : ngx_http_spdy_nv_vsize("418")); | 174 : ngx_http_spdy_nv_vsize("418")); |
171 | 175 |
172 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 176 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
303 return NGX_ERROR; | 307 return NGX_ERROR; |
304 } | 308 } |
305 | 309 |
306 last = buf + NGX_SPDY_NV_NUM_SIZE; | 310 last = buf + NGX_SPDY_NV_NUM_SIZE; |
307 | 311 |
308 last = ngx_http_spdy_nv_write_name(last, "version"); | 312 last = ngx_http_spdy_nv_write_name(last, ":version"); |
309 last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1"); | 313 last = ngx_http_spdy_nv_write_val(last, "HTTP/1.1"); |
310 | 314 |
311 last = ngx_http_spdy_nv_write_name(last, "status"); | 315 last = ngx_http_spdy_nv_write_name(last, ":status"); |
312 | 316 |
313 if (r->headers_out.status_line.len) { | 317 if (r->headers_out.status_line.len) { |
314 last = ngx_http_spdy_nv_write_vlen(last, | 318 last = ngx_http_spdy_nv_write_vlen(last, |
315 r->headers_out.status_line.len); | 319 r->headers_out.status_line.len); |
316 last = ngx_cpymem(last, r->headers_out.status_line.data, | 320 last = ngx_cpymem(last, r->headers_out.status_line.data, |
455 | 459 |
456 if (header[i].hash == 0 || header[i].hash == 2) { | 460 if (header[i].hash == 0 || header[i].hash == 2) { |
457 continue; | 461 continue; |
458 } | 462 } |
459 | 463 |
460 if ((header[i].key.len == 6 | |
461 && ngx_strncasecmp(header[i].key.data, | |
462 (u_char *) "status", 6) == 0) | |
463 || (header[i].key.len == 7 | |
464 && ngx_strncasecmp(header[i].key.data, | |
465 (u_char *) "version", 7) == 0)) | |
466 { | |
467 header[i].hash = 0; | |
468 continue; | |
469 } | |
470 | |
471 last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len); | 464 last = ngx_http_spdy_nv_write_nlen(last, header[i].key.len); |
472 | 465 |
473 ngx_strlow(last, header[i].key.data, header[i].key.len); | 466 ngx_strlow(last, header[i].key.data, header[i].key.len); |
474 last += header[i].key.len; | 467 last += header[i].key.len; |
475 | 468 |
618 | 611 |
619 | 612 |
620 static ngx_chain_t * | 613 static ngx_chain_t * |
621 ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) | 614 ngx_http_spdy_send_chain(ngx_connection_t *fc, ngx_chain_t *in, off_t limit) |
622 { | 615 { |
623 off_t size, offset; | 616 off_t size, offset; |
624 size_t rest, frame_size; | 617 size_t rest, frame_size; |
625 ngx_chain_t *cl, *out, **ln; | 618 ngx_chain_t *cl, *out, **ln; |
626 ngx_http_request_t *r; | 619 ngx_http_request_t *r; |
627 ngx_http_spdy_stream_t *stream; | 620 ngx_http_spdy_stream_t *stream; |
628 ngx_http_spdy_loc_conf_t *slcf; | 621 ngx_http_spdy_loc_conf_t *slcf; |
629 ngx_http_spdy_out_frame_t *frame; | 622 ngx_http_spdy_out_frame_t *frame; |
623 ngx_http_spdy_connection_t *sc; | |
630 | 624 |
631 r = fc->data; | 625 r = fc->data; |
632 stream = r->spdy_stream; | 626 stream = r->spdy_stream; |
633 | 627 |
634 if (in == NULL) { | 628 if (in == NULL) { |
640 } | 634 } |
641 | 635 |
642 return NULL; | 636 return NULL; |
643 } | 637 } |
644 | 638 |
639 sc = stream->connection; | |
640 | |
645 size = ngx_buf_size(in->buf); | 641 size = ngx_buf_size(in->buf); |
642 | |
643 if (size && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) { | |
644 fc->write->delayed = 1; | |
645 return in; | |
646 } | |
647 | |
648 if (limit == 0 || limit > (off_t) sc->send_window) { | |
649 limit = sc->send_window; | |
650 } | |
651 | |
652 if (limit > stream->send_window) { | |
653 limit = (stream->send_window > 0) ? stream->send_window : 0; | |
654 } | |
646 | 655 |
647 if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { | 656 if (in->buf->tag == (ngx_buf_tag_t) &ngx_http_spdy_filter_get_shadow) { |
648 cl = ngx_alloc_chain_link(r->pool); | 657 cl = ngx_alloc_chain_link(r->pool); |
649 if (cl == NULL) { | 658 if (cl == NULL) { |
650 return NGX_CHAIN_ERROR; | 659 return NGX_CHAIN_ERROR; |
668 cl = NULL; | 677 cl = NULL; |
669 #endif | 678 #endif |
670 | 679 |
671 slcf = ngx_http_get_module_loc_conf(r, ngx_http_spdy_module); | 680 slcf = ngx_http_get_module_loc_conf(r, ngx_http_spdy_module); |
672 | 681 |
673 frame_size = (limit && limit <= (off_t) slcf->chunk_size) | 682 frame_size = (limit <= (off_t) slcf->chunk_size) ? (size_t) limit |
674 ? (size_t) limit | 683 : slcf->chunk_size; |
675 : slcf->chunk_size; | |
676 | 684 |
677 for ( ;; ) { | 685 for ( ;; ) { |
678 ln = &out; | 686 ln = &out; |
679 rest = frame_size; | 687 rest = frame_size; |
680 | 688 |
733 out, cl); | 741 out, cl); |
734 if (frame == NULL) { | 742 if (frame == NULL) { |
735 return NGX_CHAIN_ERROR; | 743 return NGX_CHAIN_ERROR; |
736 } | 744 } |
737 | 745 |
738 ngx_http_spdy_queue_frame(stream->connection, frame); | 746 ngx_http_spdy_queue_frame(sc, frame); |
739 | 747 |
748 sc->send_window -= frame_size; | |
749 | |
750 stream->send_window -= frame_size; | |
740 stream->queued++; | 751 stream->queued++; |
741 | 752 |
742 if (in == NULL) { | 753 if (in == NULL) { |
743 break; | 754 break; |
744 } | 755 } |
745 | 756 |
746 if (limit) { | 757 limit -= frame_size; |
747 limit -= frame_size; | 758 |
748 | 759 if (limit == 0) { |
749 if (limit == 0) { | 760 break; |
750 break; | 761 } |
751 } | 762 |
752 | 763 if (limit < (off_t) slcf->chunk_size) { |
753 if (limit < (off_t) slcf->chunk_size) { | 764 frame_size = (size_t) limit; |
754 frame_size = (size_t) limit; | |
755 } | |
756 } | 765 } |
757 } | 766 } |
758 | 767 |
759 if (offset) { | 768 if (offset) { |
760 cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size); | 769 cl = ngx_http_spdy_filter_get_shadow(stream, in->buf, offset, size); |
766 ngx_free_chain(r->pool, cl); | 775 ngx_free_chain(r->pool, cl); |
767 } | 776 } |
768 | 777 |
769 if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) { | 778 if (ngx_http_spdy_filter_send(fc, stream) == NGX_ERROR) { |
770 return NGX_CHAIN_ERROR; | 779 return NGX_CHAIN_ERROR; |
780 } | |
781 | |
782 if (in && ngx_http_spdy_flow_control(sc, stream) == NGX_DECLINED) { | |
783 fc->write->delayed = 1; | |
771 } | 784 } |
772 | 785 |
773 return in; | 786 return in; |
774 } | 787 } |
775 | 788 |
874 buf->memory = 1; | 887 buf->memory = 1; |
875 } | 888 } |
876 | 889 |
877 cl->next = first; | 890 cl->next = first; |
878 first = cl; | 891 first = cl; |
892 | |
893 last->buf->flush = 1; | |
879 } | 894 } |
880 | 895 |
881 frame->first = first; | 896 frame->first = first; |
882 frame->last = last; | 897 frame->last = last; |
883 frame->handler = ngx_http_spdy_data_frame_handler; | 898 frame->handler = ngx_http_spdy_data_frame_handler; |
913 | 928 |
914 return NGX_OK; | 929 return NGX_OK; |
915 } | 930 } |
916 | 931 |
917 | 932 |
933 static ngx_inline ngx_int_t | |
934 ngx_http_spdy_flow_control(ngx_http_spdy_connection_t *sc, | |
935 ngx_http_spdy_stream_t *stream) | |
936 { | |
937 if (stream->send_window <= 0) { | |
938 stream->exhausted = 1; | |
939 return NGX_DECLINED; | |
940 } | |
941 | |
942 if (sc->send_window == 0) { | |
943 ngx_http_spdy_waiting_queue(sc, stream); | |
944 return NGX_DECLINED; | |
945 } | |
946 | |
947 return NGX_OK; | |
948 } | |
949 | |
950 | |
951 static void | |
952 ngx_http_spdy_waiting_queue(ngx_http_spdy_connection_t *sc, | |
953 ngx_http_spdy_stream_t *stream) | |
954 { | |
955 ngx_queue_t *q; | |
956 ngx_http_spdy_stream_t *s; | |
957 | |
958 if (stream->handled) { | |
959 return; | |
960 } | |
961 | |
962 stream->handled = 1; | |
963 | |
964 for (q = ngx_queue_last(&sc->waiting); | |
965 q != ngx_queue_sentinel(&sc->waiting); | |
966 q = ngx_queue_prev(q)) | |
967 { | |
968 s = ngx_queue_data(q, ngx_http_spdy_stream_t, queue); | |
969 | |
970 if (s->priority >= stream->priority) { | |
971 break; | |
972 } | |
973 } | |
974 | |
975 ngx_queue_insert_after(q, &stream->queue); | |
976 } | |
977 | |
978 | |
918 static ngx_int_t | 979 static ngx_int_t |
919 ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc, | 980 ngx_http_spdy_syn_frame_handler(ngx_http_spdy_connection_t *sc, |
920 ngx_http_spdy_out_frame_t *frame) | 981 ngx_http_spdy_out_frame_t *frame) |
921 { | 982 { |
922 ngx_buf_t *buf; | 983 ngx_buf_t *buf; |
1061 ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc, | 1122 ngx_http_spdy_handle_stream(ngx_http_spdy_connection_t *sc, |
1062 ngx_http_spdy_stream_t *stream) | 1123 ngx_http_spdy_stream_t *stream) |
1063 { | 1124 { |
1064 ngx_event_t *wev; | 1125 ngx_event_t *wev; |
1065 | 1126 |
1066 if (stream->handled || stream->blocked) { | 1127 if (stream->handled || stream->blocked || stream->exhausted) { |
1067 return; | 1128 return; |
1068 } | 1129 } |
1069 | 1130 |
1070 wev = stream->request->connection->write; | 1131 wev = stream->request->connection->write; |
1071 | 1132 |
1081 static void | 1142 static void |
1082 ngx_http_spdy_filter_cleanup(void *data) | 1143 ngx_http_spdy_filter_cleanup(void *data) |
1083 { | 1144 { |
1084 ngx_http_spdy_stream_t *stream = data; | 1145 ngx_http_spdy_stream_t *stream = data; |
1085 | 1146 |
1086 ngx_http_spdy_out_frame_t *frame, **fn; | 1147 size_t delta; |
1148 ngx_http_spdy_out_frame_t *frame, **fn; | |
1149 ngx_http_spdy_connection_t *sc; | |
1150 | |
1151 if (stream->handled) { | |
1152 stream->handled = 0; | |
1153 ngx_queue_remove(&stream->queue); | |
1154 } | |
1087 | 1155 |
1088 if (stream->queued == 0) { | 1156 if (stream->queued == 0) { |
1089 return; | 1157 return; |
1090 } | 1158 } |
1091 | 1159 |
1092 fn = &stream->connection->last_out; | 1160 delta = 0; |
1161 sc = stream->connection; | |
1162 fn = &sc->last_out; | |
1093 | 1163 |
1094 for ( ;; ) { | 1164 for ( ;; ) { |
1095 frame = *fn; | 1165 frame = *fn; |
1096 | 1166 |
1097 if (frame == NULL) { | 1167 if (frame == NULL) { |
1098 break; | 1168 break; |
1099 } | 1169 } |
1100 | 1170 |
1101 if (frame->stream == stream && !frame->blocked) { | 1171 if (frame->stream == stream && !frame->blocked) { |
1102 stream->queued--; | |
1103 | |
1104 *fn = frame->next; | 1172 *fn = frame->next; |
1173 | |
1174 delta += frame->length; | |
1175 | |
1176 if (--stream->queued == 0) { | |
1177 break; | |
1178 } | |
1179 | |
1105 continue; | 1180 continue; |
1106 } | 1181 } |
1107 | 1182 |
1108 fn = &frame->next; | 1183 fn = &frame->next; |
1109 } | 1184 } |
1185 | |
1186 if (sc->send_window == 0 && delta && !ngx_queue_empty(&sc->waiting)) { | |
1187 ngx_queue_add(&sc->posted, &sc->waiting); | |
1188 ngx_queue_init(&sc->waiting); | |
1189 } | |
1190 | |
1191 sc->send_window += delta; | |
1110 } | 1192 } |
1111 | 1193 |
1112 | 1194 |
1113 static ngx_int_t | 1195 static ngx_int_t |
1114 ngx_http_spdy_filter_init(ngx_conf_t *cf) | 1196 ngx_http_spdy_filter_init(ngx_conf_t *cf) |