Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2_filter_module.c @ 7201:641306096f5b
HTTP/2: server push.
Resources to be pushed are configured with the "http2_push" directive.
Also, preload links from the Link response headers, as described in
https://www.w3.org/TR/preload/#server-push-http-2, can be pushed, if
enabled with the "http2_push_preload" directive.
Only relative URIs with absolute paths can be pushed.
The number of concurrent pushes is normally limited by a client, but
cannot exceed a hard limit set by the "http2_max_concurrent_pushes"
directive.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Thu, 08 Feb 2018 09:55:03 +0300 |
parents | 61d276dcd493 |
children | a49af443656f |
comparison
equal
deleted
inserted
replaced
7200:cadb43014c7c | 7201:641306096f5b |
---|---|
1 | 1 |
2 /* | 2 /* |
3 * Copyright (C) Nginx, Inc. | 3 * Copyright (C) Nginx, Inc. |
4 * Copyright (C) Valentin V. Bartenev | 4 * Copyright (C) Valentin V. Bartenev |
5 * Copyright (C) Ruslan Ermilov | |
5 */ | 6 */ |
6 | 7 |
7 | 8 |
8 #include <ngx_config.h> | 9 #include <ngx_config.h> |
9 #include <ngx_core.h> | 10 #include <ngx_core.h> |
30 #define ngx_http_v2_write_value(dst, src, len, tmp) \ | 31 #define ngx_http_v2_write_value(dst, src, len, tmp) \ |
31 ngx_http_v2_string_encode(dst, src, len, tmp, 0) | 32 ngx_http_v2_string_encode(dst, src, len, tmp, 0) |
32 | 33 |
33 #define NGX_HTTP_V2_ENCODE_RAW 0 | 34 #define NGX_HTTP_V2_ENCODE_RAW 0 |
34 #define NGX_HTTP_V2_ENCODE_HUFF 0x80 | 35 #define NGX_HTTP_V2_ENCODE_HUFF 0x80 |
36 | |
37 #define NGX_HTTP_V2_AUTHORITY_INDEX 1 | |
38 #define NGX_HTTP_V2_METHOD_GET_INDEX 2 | |
39 #define NGX_HTTP_V2_PATH_INDEX 4 | |
40 | |
41 #define NGX_HTTP_V2_SCHEME_HTTP_INDEX 6 | |
42 #define NGX_HTTP_V2_SCHEME_HTTPS_INDEX 7 | |
35 | 43 |
36 #define NGX_HTTP_V2_STATUS_INDEX 8 | 44 #define NGX_HTTP_V2_STATUS_INDEX 8 |
37 #define NGX_HTTP_V2_STATUS_200_INDEX 8 | 45 #define NGX_HTTP_V2_STATUS_200_INDEX 8 |
38 #define NGX_HTTP_V2_STATUS_204_INDEX 9 | 46 #define NGX_HTTP_V2_STATUS_204_INDEX 9 |
39 #define NGX_HTTP_V2_STATUS_206_INDEX 10 | 47 #define NGX_HTTP_V2_STATUS_206_INDEX 10 |
51 #define NGX_HTTP_V2_VARY_INDEX 59 | 59 #define NGX_HTTP_V2_VARY_INDEX 59 |
52 | 60 |
53 #define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 | 61 #define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 |
54 | 62 |
55 | 63 |
64 static ngx_int_t ngx_http_v2_push_resources(ngx_http_request_t *r); | |
65 static ngx_int_t ngx_http_v2_push_resource(ngx_http_request_t *r, | |
66 ngx_str_t *path, ngx_str_t *authority); | |
67 | |
56 static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, | 68 static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, |
57 u_char *tmp, ngx_uint_t lower); | 69 u_char *tmp, ngx_uint_t lower); |
58 static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, | 70 static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, |
59 ngx_uint_t value); | 71 ngx_uint_t value); |
60 static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame( | 72 static ngx_http_v2_out_frame_t *ngx_http_v2_create_headers_frame( |
61 ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin); | 73 ngx_http_request_t *r, u_char *pos, u_char *end, ngx_uint_t fin); |
74 static ngx_http_v2_out_frame_t *ngx_http_v2_create_push_frame( | |
75 ngx_http_request_t *r, u_char *pos, u_char *end); | |
62 static ngx_http_v2_out_frame_t *ngx_http_v2_create_trailers_frame( | 76 static ngx_http_v2_out_frame_t *ngx_http_v2_create_trailers_frame( |
63 ngx_http_request_t *r); | 77 ngx_http_request_t *r); |
64 | 78 |
65 static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, | 79 static ngx_chain_t *ngx_http_v2_send_chain(ngx_connection_t *fc, |
66 ngx_chain_t *in, off_t limit); | 80 ngx_chain_t *in, off_t limit); |
78 | 92 |
79 static ngx_inline ngx_int_t ngx_http_v2_filter_send( | 93 static ngx_inline ngx_int_t ngx_http_v2_filter_send( |
80 ngx_connection_t *fc, ngx_http_v2_stream_t *stream); | 94 ngx_connection_t *fc, ngx_http_v2_stream_t *stream); |
81 | 95 |
82 static ngx_int_t ngx_http_v2_headers_frame_handler( | 96 static ngx_int_t ngx_http_v2_headers_frame_handler( |
97 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); | |
98 static ngx_int_t ngx_http_v2_push_frame_handler( | |
83 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); | 99 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); |
84 static ngx_int_t ngx_http_v2_data_frame_handler( | 100 static ngx_int_t ngx_http_v2_data_frame_handler( |
85 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); | 101 ngx_http_v2_connection_t *h2c, ngx_http_v2_out_frame_t *frame); |
86 static ngx_inline void ngx_http_v2_handle_frame( | 102 static ngx_inline void ngx_http_v2_handle_frame( |
87 ngx_http_v2_stream_t *stream, ngx_http_v2_out_frame_t *frame); | 103 ngx_http_v2_stream_t *stream, ngx_http_v2_out_frame_t *frame); |
239 } | 255 } |
240 } | 256 } |
241 | 257 |
242 h2c = stream->connection; | 258 h2c = stream->connection; |
243 | 259 |
260 if (!h2c->push_disabled && !h2c->goaway | |
261 && stream->node->id % 2 == 1 | |
262 && r->method != NGX_HTTP_HEAD) | |
263 { | |
264 if (ngx_http_v2_push_resources(r) != NGX_OK) { | |
265 return NGX_ERROR; | |
266 } | |
267 } | |
268 | |
244 len = h2c->table_update ? 1 : 0; | 269 len = h2c->table_update ? 1 : 0; |
245 | 270 |
246 len += status ? 1 : 1 + ngx_http_v2_literal_size("418"); | 271 len += status ? 1 : 1 + ngx_http_v2_literal_size("418"); |
247 | 272 |
248 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); | 273 clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); |
636 return NGX_ERROR; | 661 return NGX_ERROR; |
637 } | 662 } |
638 | 663 |
639 ngx_http_v2_queue_blocked_frame(h2c, frame); | 664 ngx_http_v2_queue_blocked_frame(h2c, frame); |
640 | 665 |
641 stream->queued = 1; | 666 stream->queued++; |
642 | 667 |
643 cln = ngx_http_cleanup_add(r, 0); | 668 cln = ngx_http_cleanup_add(r, 0); |
644 if (cln == NULL) { | 669 if (cln == NULL) { |
645 return NGX_ERROR; | 670 return NGX_ERROR; |
646 } | 671 } |
650 | 675 |
651 fc->send_chain = ngx_http_v2_send_chain; | 676 fc->send_chain = ngx_http_v2_send_chain; |
652 fc->need_last_buf = 1; | 677 fc->need_last_buf = 1; |
653 | 678 |
654 return ngx_http_v2_filter_send(fc, stream); | 679 return ngx_http_v2_filter_send(fc, stream); |
680 } | |
681 | |
682 | |
683 static ngx_int_t | |
684 ngx_http_v2_push_resources(ngx_http_request_t *r) | |
685 { | |
686 u_char *start, *end, *last; | |
687 ngx_int_t rc; | |
688 ngx_str_t path, authority; | |
689 ngx_uint_t i, push; | |
690 ngx_table_elt_t **h; | |
691 ngx_connection_t *fc; | |
692 ngx_http_v2_stream_t *stream; | |
693 ngx_http_v2_loc_conf_t *h2lcf; | |
694 ngx_http_v2_connection_t *h2c; | |
695 ngx_http_complex_value_t *pushes; | |
696 | |
697 fc = r->connection; | |
698 | |
699 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 push resources"); | |
700 | |
701 stream = r->stream; | |
702 h2c = stream->connection; | |
703 | |
704 ngx_str_null(&authority); | |
705 | |
706 h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module); | |
707 | |
708 if (h2lcf->pushes) { | |
709 pushes = h2lcf->pushes->elts; | |
710 | |
711 for (i = 0; i < h2lcf->pushes->nelts; i++) { | |
712 | |
713 if (ngx_http_complex_value(r, &pushes[i], &path) != NGX_OK) { | |
714 return NGX_ERROR; | |
715 } | |
716 | |
717 if (path.len == 0) { | |
718 continue; | |
719 } | |
720 | |
721 if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) { | |
722 continue; | |
723 } | |
724 | |
725 rc = ngx_http_v2_push_resource(r, &path, &authority); | |
726 | |
727 if (rc == NGX_ERROR) { | |
728 return NGX_ERROR; | |
729 } | |
730 | |
731 if (rc == NGX_ABORT) { | |
732 return NGX_OK; | |
733 } | |
734 | |
735 /* NGX_OK, NGX_DECLINED */ | |
736 } | |
737 } | |
738 | |
739 if (!h2lcf->push_preload) { | |
740 return NGX_OK; | |
741 } | |
742 | |
743 h = r->headers_out.link.elts; | |
744 | |
745 for (i = 0; i < r->headers_out.link.nelts; i++) { | |
746 | |
747 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
748 "http2 parse link: \"%V\"", &h[i]->value); | |
749 | |
750 start = h[i]->value.data; | |
751 end = h[i]->value.data + h[i]->value.len; | |
752 | |
753 next_link: | |
754 | |
755 while (start < end && *start == ' ') { start++; } | |
756 | |
757 if (start == end || *start++ != '<') { | |
758 continue; | |
759 } | |
760 | |
761 while (start < end && *start == ' ') { start++; } | |
762 | |
763 for (last = start; last < end && *last != '>'; last++) { | |
764 /* void */ | |
765 } | |
766 | |
767 if (last == start || last == end) { | |
768 continue; | |
769 } | |
770 | |
771 path.len = last - start; | |
772 path.data = start; | |
773 | |
774 start = last + 1; | |
775 | |
776 while (start < end && *start == ' ') { start++; } | |
777 | |
778 if (start == end) { | |
779 continue; | |
780 } | |
781 | |
782 if (*start == ',') { | |
783 start++; | |
784 goto next_link; | |
785 } | |
786 | |
787 if (*start++ != ';') { | |
788 continue; | |
789 } | |
790 | |
791 last = ngx_strlchr(start, end, ','); | |
792 | |
793 if (last == NULL) { | |
794 last = end; | |
795 } | |
796 | |
797 push = 0; | |
798 | |
799 for ( ;; ) { | |
800 | |
801 while (start < last && *start == ' ') { start++; } | |
802 | |
803 if (last - start >= 6 | |
804 && ngx_strncasecmp(start, (u_char *) "nopush", 6) == 0) | |
805 { | |
806 start += 6; | |
807 | |
808 if (start == last || *start == ' ' || *start == ';') { | |
809 push = 0; | |
810 break; | |
811 } | |
812 | |
813 goto next_param; | |
814 } | |
815 | |
816 if (last - start >= 11 | |
817 && ngx_strncasecmp(start, (u_char *) "rel=preload", 11) == 0) | |
818 { | |
819 start += 11; | |
820 | |
821 if (start == last || *start == ' ' || *start == ';') { | |
822 push = 1; | |
823 } | |
824 | |
825 goto next_param; | |
826 } | |
827 | |
828 if (last - start >= 4 | |
829 && ngx_strncasecmp(start, (u_char *) "rel=", 4) == 0) | |
830 { | |
831 start += 4; | |
832 | |
833 while (start < last && *start == ' ') { start++; } | |
834 | |
835 if (start == last || *start++ != '"') { | |
836 goto next_param; | |
837 } | |
838 | |
839 for ( ;; ) { | |
840 | |
841 while (start < last && *start == ' ') { start++; } | |
842 | |
843 if (last - start >= 7 | |
844 && ngx_strncasecmp(start, (u_char *) "preload", 7) == 0) | |
845 { | |
846 start += 7; | |
847 | |
848 if (start < last && (*start == ' ' || *start == '"')) { | |
849 push = 1; | |
850 break; | |
851 } | |
852 } | |
853 | |
854 while (start < last && *start != ' ' && *start != '"') { | |
855 start++; | |
856 } | |
857 | |
858 if (start == last) { | |
859 break; | |
860 } | |
861 | |
862 if (*start == '"') { | |
863 break; | |
864 } | |
865 | |
866 start++; | |
867 } | |
868 } | |
869 | |
870 next_param: | |
871 | |
872 start = ngx_strlchr(start, last, ';'); | |
873 | |
874 if (start == NULL) { | |
875 break; | |
876 } | |
877 | |
878 start++; | |
879 } | |
880 | |
881 if (push) { | |
882 while (path.len && path.data[path.len - 1] == ' ') { | |
883 path.len--; | |
884 } | |
885 } | |
886 | |
887 if (push && path.len | |
888 && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/')) | |
889 { | |
890 rc = ngx_http_v2_push_resource(r, &path, &authority); | |
891 | |
892 if (rc == NGX_ERROR) { | |
893 return NGX_ERROR; | |
894 } | |
895 | |
896 if (rc == NGX_ABORT) { | |
897 return NGX_OK; | |
898 } | |
899 | |
900 /* NGX_OK, NGX_DECLINED */ | |
901 } | |
902 | |
903 if (last < end) { | |
904 start = last + 1; | |
905 goto next_link; | |
906 } | |
907 } | |
908 | |
909 return NGX_OK; | |
910 } | |
911 | |
912 | |
913 static ngx_int_t | |
914 ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, | |
915 ngx_str_t *authority) | |
916 { | |
917 u_char *start, *pos, *tmp; | |
918 size_t len; | |
919 ngx_table_elt_t *host; | |
920 ngx_connection_t *fc; | |
921 ngx_http_v2_stream_t *stream; | |
922 ngx_http_v2_out_frame_t *frame; | |
923 ngx_http_v2_connection_t *h2c; | |
924 | |
925 fc = r->connection; | |
926 | |
927 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 push resource"); | |
928 | |
929 stream = r->stream; | |
930 h2c = stream->connection; | |
931 | |
932 if (!ngx_path_separator(path->data[0])) { | |
933 ngx_log_error(NGX_LOG_WARN, fc->log, 0, | |
934 "non-absolute path \"%V\" not pushed", path); | |
935 return NGX_DECLINED; | |
936 } | |
937 | |
938 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
939 "http2 pushing:%ui limit:%ui", | |
940 h2c->pushing, h2c->concurrent_pushes); | |
941 | |
942 if (h2c->pushing >= h2c->concurrent_pushes) { | |
943 return NGX_ABORT; | |
944 } | |
945 | |
946 if (h2c->last_push == 0x7ffffffe) { | |
947 return NGX_ABORT; | |
948 } | |
949 | |
950 if (path->len > NGX_HTTP_V2_MAX_FIELD) { | |
951 return NGX_DECLINED; | |
952 } | |
953 | |
954 host = r->headers_in.host; | |
955 | |
956 if (authority->len == 0 && host) { | |
957 | |
958 len = 1 + NGX_HTTP_V2_INT_OCTETS + host->value.len; | |
959 | |
960 tmp = ngx_palloc(r->pool, len); | |
961 pos = ngx_pnalloc(r->pool, len); | |
962 | |
963 if (pos == NULL || tmp == NULL) { | |
964 return NGX_ERROR; | |
965 } | |
966 | |
967 authority->data = pos; | |
968 | |
969 *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX); | |
970 pos = ngx_http_v2_write_value(pos, host->value.data, host->value.len, | |
971 tmp); | |
972 | |
973 authority->len = pos - authority->data; | |
974 } | |
975 | |
976 len = (h2c->table_update ? 1 : 0) | |
977 + 1 | |
978 + 1 + NGX_HTTP_V2_INT_OCTETS + path->len | |
979 + authority->len | |
980 + 1; | |
981 | |
982 tmp = ngx_palloc(r->pool, len); | |
983 pos = ngx_pnalloc(r->pool, len); | |
984 | |
985 if (pos == NULL || tmp == NULL) { | |
986 return NGX_ERROR; | |
987 } | |
988 | |
989 start = pos; | |
990 | |
991 if (h2c->table_update) { | |
992 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
993 "http2 table size update: 0"); | |
994 *pos++ = (1 << 5) | 0; | |
995 h2c->table_update = 0; | |
996 } | |
997 | |
998 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
999 "http2 push header: \":method: GET\""); | |
1000 | |
1001 *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_METHOD_GET_INDEX); | |
1002 | |
1003 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
1004 "http2 push header: \":path: %V\"", path); | |
1005 | |
1006 *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); | |
1007 pos = ngx_http_v2_write_value(pos, path->data, path->len, tmp); | |
1008 | |
1009 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
1010 "http2 push header: \":authority: %V\"", &host->value); | |
1011 | |
1012 pos = ngx_cpymem(pos, authority->data, authority->len); | |
1013 | |
1014 #if (NGX_HTTP_SSL) | |
1015 if (fc->ssl) { | |
1016 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
1017 "http2 push header: \":scheme: https\""); | |
1018 *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTPS_INDEX); | |
1019 | |
1020 } else | |
1021 #endif | |
1022 { | |
1023 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
1024 "http2 push header: \":scheme: http\""); | |
1025 *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); | |
1026 } | |
1027 | |
1028 frame = ngx_http_v2_create_push_frame(r, start, pos); | |
1029 if (frame == NULL) { | |
1030 return NGX_ERROR; | |
1031 } | |
1032 | |
1033 ngx_http_v2_queue_blocked_frame(h2c, frame); | |
1034 | |
1035 stream->queued++; | |
1036 | |
1037 return ngx_http_v2_push_stream(h2c, stream->node->id, pos - start, | |
1038 path, &host->value); | |
655 } | 1039 } |
656 | 1040 |
657 | 1041 |
658 static u_char * | 1042 static u_char * |
659 ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, | 1043 ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, |
800 frame->last = cl; | 1184 frame->last = cl; |
801 | 1185 |
802 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 1186 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
803 "http2:%ui create HEADERS frame %p: len:%uz", | 1187 "http2:%ui create HEADERS frame %p: len:%uz", |
804 stream->node->id, frame, frame->length); | 1188 stream->node->id, frame, frame->length); |
1189 | |
1190 return frame; | |
1191 } | |
1192 } | |
1193 | |
1194 | |
1195 static ngx_http_v2_out_frame_t * | |
1196 ngx_http_v2_create_push_frame(ngx_http_request_t *r, u_char *pos, u_char *end) | |
1197 { | |
1198 u_char type, flags; | |
1199 size_t rest, frame_size, len; | |
1200 ngx_buf_t *b; | |
1201 ngx_chain_t *cl, **ll; | |
1202 ngx_http_v2_stream_t *stream; | |
1203 ngx_http_v2_out_frame_t *frame; | |
1204 ngx_http_v2_connection_t *h2c; | |
1205 | |
1206 stream = r->stream; | |
1207 h2c = stream->connection; | |
1208 rest = NGX_HTTP_V2_STREAM_ID_SIZE + (end - pos); | |
1209 | |
1210 frame = ngx_palloc(r->pool, sizeof(ngx_http_v2_out_frame_t)); | |
1211 if (frame == NULL) { | |
1212 return NULL; | |
1213 } | |
1214 | |
1215 frame->handler = ngx_http_v2_push_frame_handler; | |
1216 frame->stream = stream; | |
1217 frame->length = rest; | |
1218 frame->blocked = 1; | |
1219 frame->fin = 0; | |
1220 | |
1221 ll = &frame->first; | |
1222 | |
1223 type = NGX_HTTP_V2_PUSH_PROMISE_FRAME; | |
1224 flags = NGX_HTTP_V2_NO_FLAG; | |
1225 frame_size = h2c->frame_size; | |
1226 | |
1227 for ( ;; ) { | |
1228 if (rest <= frame_size) { | |
1229 frame_size = rest; | |
1230 flags |= NGX_HTTP_V2_END_HEADERS_FLAG; | |
1231 } | |
1232 | |
1233 b = ngx_create_temp_buf(r->pool, | |
1234 NGX_HTTP_V2_FRAME_HEADER_SIZE | |
1235 + ((type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) | |
1236 ? NGX_HTTP_V2_STREAM_ID_SIZE : 0)); | |
1237 if (b == NULL) { | |
1238 return NULL; | |
1239 } | |
1240 | |
1241 b->last = ngx_http_v2_write_len_and_type(b->last, frame_size, type); | |
1242 *b->last++ = flags; | |
1243 b->last = ngx_http_v2_write_sid(b->last, stream->node->id); | |
1244 | |
1245 b->tag = (ngx_buf_tag_t) &ngx_http_v2_module; | |
1246 | |
1247 if (type == NGX_HTTP_V2_PUSH_PROMISE_FRAME) { | |
1248 h2c->last_push += 2; | |
1249 | |
1250 b->last = ngx_http_v2_write_sid(b->last, h2c->last_push); | |
1251 len = frame_size - NGX_HTTP_V2_STREAM_ID_SIZE; | |
1252 | |
1253 } else { | |
1254 len = frame_size; | |
1255 } | |
1256 | |
1257 cl = ngx_alloc_chain_link(r->pool); | |
1258 if (cl == NULL) { | |
1259 return NULL; | |
1260 } | |
1261 | |
1262 cl->buf = b; | |
1263 | |
1264 *ll = cl; | |
1265 ll = &cl->next; | |
1266 | |
1267 b = ngx_calloc_buf(r->pool); | |
1268 if (b == NULL) { | |
1269 return NULL; | |
1270 } | |
1271 | |
1272 b->pos = pos; | |
1273 | |
1274 pos += len; | |
1275 | |
1276 b->last = pos; | |
1277 b->start = b->pos; | |
1278 b->end = b->last; | |
1279 b->temporary = 1; | |
1280 | |
1281 cl = ngx_alloc_chain_link(r->pool); | |
1282 if (cl == NULL) { | |
1283 return NULL; | |
1284 } | |
1285 | |
1286 cl->buf = b; | |
1287 | |
1288 *ll = cl; | |
1289 ll = &cl->next; | |
1290 | |
1291 rest -= frame_size; | |
1292 | |
1293 if (rest) { | |
1294 frame->length += NGX_HTTP_V2_FRAME_HEADER_SIZE; | |
1295 | |
1296 type = NGX_HTTP_V2_CONTINUATION_FRAME; | |
1297 continue; | |
1298 } | |
1299 | |
1300 cl->next = NULL; | |
1301 frame->last = cl; | |
1302 | |
1303 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
1304 "http2:%ui create PUSH_PROMISE frame %p: " | |
1305 "sid:%ui len:%uz", | |
1306 stream->node->id, frame, h2c->last_push, | |
1307 frame->length); | |
805 | 1308 |
806 return frame; | 1309 return frame; |
807 } | 1310 } |
808 } | 1311 } |
809 | 1312 |
1375 return NGX_OK; | 1878 return NGX_OK; |
1376 } | 1879 } |
1377 | 1880 |
1378 | 1881 |
1379 static ngx_int_t | 1882 static ngx_int_t |
1883 ngx_http_v2_push_frame_handler(ngx_http_v2_connection_t *h2c, | |
1884 ngx_http_v2_out_frame_t *frame) | |
1885 { | |
1886 ngx_chain_t *cl, *ln; | |
1887 ngx_http_v2_stream_t *stream; | |
1888 | |
1889 stream = frame->stream; | |
1890 cl = frame->first; | |
1891 | |
1892 for ( ;; ) { | |
1893 if (cl->buf->pos != cl->buf->last) { | |
1894 frame->first = cl; | |
1895 | |
1896 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1897 "http2:%ui PUSH_PROMISE frame %p was sent partially", | |
1898 stream->node->id, frame); | |
1899 | |
1900 return NGX_AGAIN; | |
1901 } | |
1902 | |
1903 ln = cl->next; | |
1904 | |
1905 if (cl->buf->tag == (ngx_buf_tag_t) &ngx_http_v2_module) { | |
1906 cl->next = stream->free_frame_headers; | |
1907 stream->free_frame_headers = cl; | |
1908 | |
1909 } else { | |
1910 cl->next = stream->free_bufs; | |
1911 stream->free_bufs = cl; | |
1912 } | |
1913 | |
1914 if (cl == frame->last) { | |
1915 break; | |
1916 } | |
1917 | |
1918 cl = ln; | |
1919 } | |
1920 | |
1921 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, h2c->connection->log, 0, | |
1922 "http2:%ui PUSH_PROMISE frame %p was sent", | |
1923 stream->node->id, frame); | |
1924 | |
1925 stream->request->header_size += NGX_HTTP_V2_FRAME_HEADER_SIZE | |
1926 + frame->length; | |
1927 | |
1928 ngx_http_v2_handle_frame(stream, frame); | |
1929 | |
1930 ngx_http_v2_handle_stream(h2c, stream); | |
1931 | |
1932 return NGX_OK; | |
1933 } | |
1934 | |
1935 | |
1936 static ngx_int_t | |
1380 ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, | 1937 ngx_http_v2_data_frame_handler(ngx_http_v2_connection_t *h2c, |
1381 ngx_http_v2_out_frame_t *frame) | 1938 ngx_http_v2_out_frame_t *frame) |
1382 { | 1939 { |
1383 ngx_buf_t *buf; | 1940 ngx_buf_t *buf; |
1384 ngx_chain_t *cl, *ln; | 1941 ngx_chain_t *cl, *ln; |