comparison src/http/v3/ngx_http_v3_filter_module.c @ 9108:f742b1b46901 quic

HTTP/3: removed server push support.
author Roman Arutyunyan <arut@nginx.com>
date Fri, 12 May 2023 10:02:10 +0400
parents 8d0753760546
children f91dc350be9f
comparison
equal deleted inserted replaced
9107:adcc6d8acfd4 9108:f742b1b46901
34 ngx_chain_t *busy; 34 ngx_chain_t *busy;
35 } ngx_http_v3_filter_ctx_t; 35 } ngx_http_v3_filter_ctx_t;
36 36
37 37
38 static ngx_int_t ngx_http_v3_header_filter(ngx_http_request_t *r); 38 static ngx_int_t ngx_http_v3_header_filter(ngx_http_request_t *r);
39 static ngx_int_t ngx_http_v3_push_resources(ngx_http_request_t *r,
40 ngx_chain_t ***out);
41 static ngx_int_t ngx_http_v3_push_resource(ngx_http_request_t *r,
42 ngx_str_t *path, ngx_chain_t ***out);
43 static ngx_int_t ngx_http_v3_create_push_request(
44 ngx_http_request_t *pr, ngx_str_t *path, uint64_t push_id);
45 static ngx_int_t ngx_http_v3_set_push_header(ngx_http_request_t *r,
46 const char *name, ngx_str_t *value);
47 static void ngx_http_v3_push_request_handler(ngx_event_t *ev);
48 static ngx_chain_t *ngx_http_v3_create_push_promise(ngx_http_request_t *r,
49 ngx_str_t *path, uint64_t push_id);
50 static ngx_int_t ngx_http_v3_body_filter(ngx_http_request_t *r, 39 static ngx_int_t ngx_http_v3_body_filter(ngx_http_request_t *r,
51 ngx_chain_t *in); 40 ngx_chain_t *in);
52 static ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r, 41 static ngx_chain_t *ngx_http_v3_create_trailers(ngx_http_request_t *r,
53 ngx_http_v3_filter_ctx_t *ctx); 42 ngx_http_v3_filter_ctx_t *ctx);
54 static ngx_int_t ngx_http_v3_filter_init(ngx_conf_t *cf); 43 static ngx_int_t ngx_http_v3_filter_init(ngx_conf_t *cf);
153 c = r->connection; 142 c = r->connection;
154 143
155 out = NULL; 144 out = NULL;
156 ll = &out; 145 ll = &out;
157 146
158 if ((c->quic->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0
159 && r->method != NGX_HTTP_HEAD)
160 {
161 if (ngx_http_v3_push_resources(r, &ll) != NGX_OK) {
162 return NGX_ERROR;
163 }
164 }
165
166 len = ngx_http_v3_encode_field_section_prefix(NULL, 0, 0, 0); 147 len = ngx_http_v3_encode_field_section_prefix(NULL, 0, 0, 0);
167 148
168 if (r->headers_out.status == NGX_HTTP_OK) { 149 if (r->headers_out.status == NGX_HTTP_OK) {
169 len += ngx_http_v3_encode_field_ri(NULL, 0, 150 len += ngx_http_v3_encode_field_ri(NULL, 0,
170 NGX_HTTP_V3_HEADER_STATUS_200); 151 NGX_HTTP_V3_HEADER_STATUS_200);
601 for (cl = out; cl; cl = cl->next) { 582 for (cl = out; cl; cl = cl->next) {
602 h3c->total_bytes += cl->buf->last - cl->buf->pos; 583 h3c->total_bytes += cl->buf->last - cl->buf->pos;
603 } 584 }
604 585
605 return ngx_http_write_filter(r, out); 586 return ngx_http_write_filter(r, out);
606 }
607
608
609 static ngx_int_t
610 ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out)
611 {
612 u_char *start, *end, *last;
613 ngx_str_t path;
614 ngx_int_t rc;
615 ngx_uint_t i, push;
616 ngx_table_elt_t *h;
617 ngx_http_v3_loc_conf_t *h3lcf;
618 ngx_http_complex_value_t *pushes;
619
620 h3lcf = ngx_http_get_module_loc_conf(r, ngx_http_v3_module);
621
622 if (h3lcf->pushes) {
623 pushes = h3lcf->pushes->elts;
624
625 for (i = 0; i < h3lcf->pushes->nelts; i++) {
626
627 if (ngx_http_complex_value(r, &pushes[i], &path) != NGX_OK) {
628 return NGX_ERROR;
629 }
630
631 if (path.len == 0) {
632 continue;
633 }
634
635 if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) {
636 continue;
637 }
638
639 rc = ngx_http_v3_push_resource(r, &path, out);
640
641 if (rc == NGX_ERROR) {
642 return NGX_ERROR;
643 }
644
645 if (rc == NGX_ABORT) {
646 return NGX_OK;
647 }
648
649 /* NGX_OK, NGX_DECLINED */
650 }
651 }
652
653 if (!h3lcf->push_preload) {
654 return NGX_OK;
655 }
656
657 for (h = r->headers_out.link; h; h = h->next) {
658
659 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
660 "http3 parse link: \"%V\"", &h->value);
661
662 start = h->value.data;
663 end = h->value.data + h->value.len;
664
665 next_link:
666
667 while (start < end && *start == ' ') { start++; }
668
669 if (start == end || *start++ != '<') {
670 continue;
671 }
672
673 while (start < end && *start == ' ') { start++; }
674
675 for (last = start; last < end && *last != '>'; last++) {
676 /* void */
677 }
678
679 if (last == start || last == end) {
680 continue;
681 }
682
683 path.len = last - start;
684 path.data = start;
685
686 start = last + 1;
687
688 while (start < end && *start == ' ') { start++; }
689
690 if (start == end) {
691 continue;
692 }
693
694 if (*start == ',') {
695 start++;
696 goto next_link;
697 }
698
699 if (*start++ != ';') {
700 continue;
701 }
702
703 last = ngx_strlchr(start, end, ',');
704
705 if (last == NULL) {
706 last = end;
707 }
708
709 push = 0;
710
711 for ( ;; ) {
712
713 while (start < last && *start == ' ') { start++; }
714
715 if (last - start >= 6
716 && ngx_strncasecmp(start, (u_char *) "nopush", 6) == 0)
717 {
718 start += 6;
719
720 if (start == last || *start == ' ' || *start == ';') {
721 push = 0;
722 break;
723 }
724
725 goto next_param;
726 }
727
728 if (last - start >= 11
729 && ngx_strncasecmp(start, (u_char *) "rel=preload", 11) == 0)
730 {
731 start += 11;
732
733 if (start == last || *start == ' ' || *start == ';') {
734 push = 1;
735 }
736
737 goto next_param;
738 }
739
740 if (last - start >= 4
741 && ngx_strncasecmp(start, (u_char *) "rel=", 4) == 0)
742 {
743 start += 4;
744
745 while (start < last && *start == ' ') { start++; }
746
747 if (start == last || *start++ != '"') {
748 goto next_param;
749 }
750
751 for ( ;; ) {
752
753 while (start < last && *start == ' ') { start++; }
754
755 if (last - start >= 7
756 && ngx_strncasecmp(start, (u_char *) "preload", 7) == 0)
757 {
758 start += 7;
759
760 if (start < last && (*start == ' ' || *start == '"')) {
761 push = 1;
762 break;
763 }
764 }
765
766 while (start < last && *start != ' ' && *start != '"') {
767 start++;
768 }
769
770 if (start == last) {
771 break;
772 }
773
774 if (*start == '"') {
775 break;
776 }
777
778 start++;
779 }
780 }
781
782 next_param:
783
784 start = ngx_strlchr(start, last, ';');
785
786 if (start == NULL) {
787 break;
788 }
789
790 start++;
791 }
792
793 if (push) {
794 while (path.len && path.data[path.len - 1] == ' ') {
795 path.len--;
796 }
797 }
798
799 if (push && path.len
800 && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/'))
801 {
802 rc = ngx_http_v3_push_resource(r, &path, out);
803
804 if (rc == NGX_ERROR) {
805 return NGX_ERROR;
806 }
807
808 if (rc == NGX_ABORT) {
809 return NGX_OK;
810 }
811
812 /* NGX_OK, NGX_DECLINED */
813 }
814
815 if (last < end) {
816 start = last + 1;
817 goto next_link;
818 }
819 }
820
821 return NGX_OK;
822 }
823
824
825 static ngx_int_t
826 ngx_http_v3_push_resource(ngx_http_request_t *r, ngx_str_t *path,
827 ngx_chain_t ***ll)
828 {
829 uint64_t push_id;
830 ngx_int_t rc;
831 ngx_chain_t *cl;
832 ngx_connection_t *c;
833 ngx_http_v3_session_t *h3c;
834 ngx_http_v3_srv_conf_t *h3scf;
835
836 c = r->connection;
837 h3c = ngx_http_v3_get_session(c);
838 h3scf = ngx_http_get_module_srv_conf(r, ngx_http_v3_module);
839
840 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
841 "http3 push \"%V\" pushing:%ui/%ui id:%uL/%L",
842 path, h3c->npushing, h3scf->max_concurrent_pushes,
843 h3c->next_push_id, h3c->max_push_id);
844
845 if (!ngx_path_separator(path->data[0])) {
846 ngx_log_error(NGX_LOG_WARN, c->log, 0,
847 "non-absolute path \"%V\" not pushed", path);
848 return NGX_DECLINED;
849 }
850
851 if (h3c->max_push_id == (uint64_t) -1
852 || h3c->next_push_id > h3c->max_push_id)
853 {
854 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
855 "http3 abort pushes due to max_push_id");
856 return NGX_ABORT;
857 }
858
859 if (h3c->goaway_push_id != (uint64_t) -1) {
860 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
861 "http3 abort pushes due to goaway");
862 return NGX_ABORT;
863 }
864
865 if (h3c->npushing >= h3scf->max_concurrent_pushes) {
866 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
867 "http3 abort pushes due to max_concurrent_pushes");
868 return NGX_ABORT;
869 }
870
871 if (r->headers_in.server.len == 0) {
872 return NGX_ABORT;
873 }
874
875 push_id = h3c->next_push_id++;
876
877 rc = ngx_http_v3_create_push_request(r, path, push_id);
878 if (rc != NGX_OK) {
879 return rc;
880 }
881
882 cl = ngx_http_v3_create_push_promise(r, path, push_id);
883 if (cl == NULL) {
884 return NGX_ERROR;
885 }
886
887 for (**ll = cl; **ll; *ll = &(**ll)->next);
888
889 return NGX_OK;
890 }
891
892
893 static ngx_int_t
894 ngx_http_v3_create_push_request(ngx_http_request_t *pr, ngx_str_t *path,
895 uint64_t push_id)
896 {
897 ngx_connection_t *c, *pc;
898 ngx_http_request_t *r;
899 ngx_http_log_ctx_t *ctx;
900 ngx_http_connection_t *hc, *phc;
901 ngx_http_core_srv_conf_t *cscf;
902
903 pc = pr->connection;
904
905 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
906 "http3 create push request id:%uL", push_id);
907
908 c = ngx_http_v3_create_push_stream(pc, push_id);
909 if (c == NULL) {
910 return NGX_ABORT;
911 }
912
913 #if (NGX_STAT_STUB)
914 (void) ngx_atomic_fetch_add(ngx_stat_active, 1);
915 #endif
916
917 hc = ngx_palloc(c->pool, sizeof(ngx_http_connection_t));
918 if (hc == NULL) {
919 ngx_http_close_connection(c);
920 return NGX_ERROR;
921 }
922
923 phc = ngx_http_quic_get_connection(pc);
924 ngx_memcpy(hc, phc, sizeof(ngx_http_connection_t));
925 c->data = hc;
926
927 ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
928 if (ctx == NULL) {
929 ngx_http_close_connection(c);
930 return NGX_ERROR;
931 }
932
933 ctx->connection = c;
934 ctx->request = NULL;
935 ctx->current_request = NULL;
936
937 c->log->handler = pc->log->handler;
938 c->log->data = ctx;
939 c->log->action = "processing pushed request headers";
940
941 c->log_error = NGX_ERROR_INFO;
942
943 r = ngx_http_create_request(c);
944 if (r == NULL) {
945 ngx_http_close_connection(c);
946 return NGX_ERROR;
947 }
948
949 c->data = r;
950
951 ngx_str_set(&r->http_protocol, "HTTP/3.0");
952
953 r->http_version = NGX_HTTP_VERSION_30;
954 r->method_name = ngx_http_core_get_method;
955 r->method = NGX_HTTP_GET;
956
957 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
958
959 r->header_in = ngx_create_temp_buf(r->pool,
960 cscf->client_header_buffer_size);
961 if (r->header_in == NULL) {
962 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
963 return NGX_ERROR;
964 }
965
966 if (ngx_list_init(&r->headers_in.headers, r->pool, 4,
967 sizeof(ngx_table_elt_t))
968 != NGX_OK)
969 {
970 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
971 return NGX_ERROR;
972 }
973
974 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
975
976 r->schema.data = ngx_pstrdup(r->pool, &pr->schema);
977 if (r->schema.data == NULL) {
978 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
979 return NGX_ERROR;
980 }
981
982 r->schema.len = pr->schema.len;
983
984 r->uri_start = ngx_pstrdup(r->pool, path);
985 if (r->uri_start == NULL) {
986 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
987 return NGX_ERROR;
988 }
989
990 r->uri_end = r->uri_start + path->len;
991
992 if (ngx_http_parse_uri(r) != NGX_OK) {
993 ngx_http_finalize_request(r, NGX_HTTP_BAD_REQUEST);
994 return NGX_ERROR;
995 }
996
997 if (ngx_http_process_request_uri(r) != NGX_OK) {
998 return NGX_ERROR;
999 }
1000
1001 if (ngx_http_v3_set_push_header(r, "host", &pr->headers_in.server)
1002 != NGX_OK)
1003 {
1004 return NGX_ERROR;
1005 }
1006
1007 if (pr->headers_in.accept_encoding) {
1008 if (ngx_http_v3_set_push_header(r, "accept-encoding",
1009 &pr->headers_in.accept_encoding->value)
1010 != NGX_OK)
1011 {
1012 return NGX_ERROR;
1013 }
1014 }
1015
1016 if (pr->headers_in.accept_language) {
1017 if (ngx_http_v3_set_push_header(r, "accept-language",
1018 &pr->headers_in.accept_language->value)
1019 != NGX_OK)
1020 {
1021 return NGX_ERROR;
1022 }
1023 }
1024
1025 if (pr->headers_in.user_agent) {
1026 if (ngx_http_v3_set_push_header(r, "user-agent",
1027 &pr->headers_in.user_agent->value)
1028 != NGX_OK)
1029 {
1030 return NGX_ERROR;
1031 }
1032 }
1033
1034 c->read->handler = ngx_http_v3_push_request_handler;
1035 c->read->handler = ngx_http_v3_push_request_handler;
1036
1037 ngx_post_event(c->read, &ngx_posted_events);
1038
1039 return NGX_OK;
1040 }
1041
1042
1043 static ngx_int_t
1044 ngx_http_v3_set_push_header(ngx_http_request_t *r, const char *name,
1045 ngx_str_t *value)
1046 {
1047 u_char *p;
1048 ngx_table_elt_t *h;
1049 ngx_http_header_t *hh;
1050 ngx_http_core_main_conf_t *cmcf;
1051
1052 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1053 "http3 push header \"%s\": \"%V\"", name, value);
1054
1055 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1056
1057 p = ngx_pnalloc(r->pool, value->len + 1);
1058 if (p == NULL) {
1059 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1060 return NGX_ERROR;
1061 }
1062
1063 ngx_memcpy(p, value->data, value->len);
1064 p[value->len] = '\0';
1065
1066 h = ngx_list_push(&r->headers_in.headers);
1067 if (h == NULL) {
1068 ngx_http_close_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1069 return NGX_ERROR;
1070 }
1071
1072 h->key.data = (u_char *) name;
1073 h->key.len = ngx_strlen(name);
1074 h->hash = ngx_hash_key(h->key.data, h->key.len);
1075 h->lowcase_key = (u_char *) name;
1076 h->value.data = p;
1077 h->value.len = value->len;
1078
1079 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1080 h->lowcase_key, h->key.len);
1081
1082 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1083 return NGX_ERROR;
1084 }
1085
1086 return NGX_OK;
1087 }
1088
1089
1090 static void
1091 ngx_http_v3_push_request_handler(ngx_event_t *ev)
1092 {
1093 ngx_connection_t *c;
1094 ngx_http_request_t *r;
1095
1096 c = ev->data;
1097 r = c->data;
1098
1099 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 push request handler");
1100
1101 ngx_http_process_request(r);
1102 }
1103
1104
1105 static ngx_chain_t *
1106 ngx_http_v3_create_push_promise(ngx_http_request_t *r, ngx_str_t *path,
1107 uint64_t push_id)
1108 {
1109 size_t n, len;
1110 ngx_buf_t *b;
1111 ngx_chain_t *hl, *cl;
1112 ngx_http_v3_session_t *h3c;
1113
1114 h3c = ngx_http_v3_get_session(r->connection);
1115
1116 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1117 "http3 create push promise id:%uL", push_id);
1118
1119 len = ngx_http_v3_encode_varlen_int(NULL, push_id);
1120
1121 len += ngx_http_v3_encode_field_section_prefix(NULL, 0, 0, 0);
1122
1123 len += ngx_http_v3_encode_field_ri(NULL, 0,
1124 NGX_HTTP_V3_HEADER_METHOD_GET);
1125
1126 len += ngx_http_v3_encode_field_lri(NULL, 0,
1127 NGX_HTTP_V3_HEADER_AUTHORITY,
1128 NULL, r->headers_in.server.len);
1129
1130 if (path->len == 1 && path->data[0] == '/') {
1131 len += ngx_http_v3_encode_field_ri(NULL, 0,
1132 NGX_HTTP_V3_HEADER_PATH_ROOT);
1133
1134 } else {
1135 len += ngx_http_v3_encode_field_lri(NULL, 0,
1136 NGX_HTTP_V3_HEADER_PATH_ROOT,
1137 NULL, path->len);
1138 }
1139
1140 if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) {
1141 len += ngx_http_v3_encode_field_ri(NULL, 0,
1142 NGX_HTTP_V3_HEADER_SCHEME_HTTPS);
1143
1144 } else if (r->schema.len == 4
1145 && ngx_strncmp(r->schema.data, "http", 4) == 0)
1146 {
1147 len += ngx_http_v3_encode_field_ri(NULL, 0,
1148 NGX_HTTP_V3_HEADER_SCHEME_HTTP);
1149
1150 } else {
1151 len += ngx_http_v3_encode_field_lri(NULL, 0,
1152 NGX_HTTP_V3_HEADER_SCHEME_HTTP,
1153 NULL, r->schema.len);
1154 }
1155
1156 if (r->headers_in.accept_encoding) {
1157 len += ngx_http_v3_encode_field_lri(NULL, 0,
1158 NGX_HTTP_V3_HEADER_ACCEPT_ENCODING, NULL,
1159 r->headers_in.accept_encoding->value.len);
1160 }
1161
1162 if (r->headers_in.accept_language) {
1163 len += ngx_http_v3_encode_field_lri(NULL, 0,
1164 NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE, NULL,
1165 r->headers_in.accept_language->value.len);
1166 }
1167
1168 if (r->headers_in.user_agent) {
1169 len += ngx_http_v3_encode_field_lri(NULL, 0,
1170 NGX_HTTP_V3_HEADER_USER_AGENT, NULL,
1171 r->headers_in.user_agent->value.len);
1172 }
1173
1174 b = ngx_create_temp_buf(r->pool, len);
1175 if (b == NULL) {
1176 return NULL;
1177 }
1178
1179 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, push_id);
1180
1181 b->last = (u_char *) ngx_http_v3_encode_field_section_prefix(b->last,
1182 0, 0, 0);
1183
1184 b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0,
1185 NGX_HTTP_V3_HEADER_METHOD_GET);
1186
1187 b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0,
1188 NGX_HTTP_V3_HEADER_AUTHORITY,
1189 r->headers_in.server.data,
1190 r->headers_in.server.len);
1191
1192 if (path->len == 1 && path->data[0] == '/') {
1193 b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0,
1194 NGX_HTTP_V3_HEADER_PATH_ROOT);
1195
1196 } else {
1197 b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0,
1198 NGX_HTTP_V3_HEADER_PATH_ROOT,
1199 path->data, path->len);
1200 }
1201
1202 if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) {
1203 b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0,
1204 NGX_HTTP_V3_HEADER_SCHEME_HTTPS);
1205
1206 } else if (r->schema.len == 4
1207 && ngx_strncmp(r->schema.data, "http", 4) == 0)
1208 {
1209 b->last = (u_char *) ngx_http_v3_encode_field_ri(b->last, 0,
1210 NGX_HTTP_V3_HEADER_SCHEME_HTTP);
1211
1212 } else {
1213 b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0,
1214 NGX_HTTP_V3_HEADER_SCHEME_HTTP,
1215 r->schema.data, r->schema.len);
1216 }
1217
1218 if (r->headers_in.accept_encoding) {
1219 b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0,
1220 NGX_HTTP_V3_HEADER_ACCEPT_ENCODING,
1221 r->headers_in.accept_encoding->value.data,
1222 r->headers_in.accept_encoding->value.len);
1223 }
1224
1225 if (r->headers_in.accept_language) {
1226 b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0,
1227 NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE,
1228 r->headers_in.accept_language->value.data,
1229 r->headers_in.accept_language->value.len);
1230 }
1231
1232 if (r->headers_in.user_agent) {
1233 b->last = (u_char *) ngx_http_v3_encode_field_lri(b->last, 0,
1234 NGX_HTTP_V3_HEADER_USER_AGENT,
1235 r->headers_in.user_agent->value.data,
1236 r->headers_in.user_agent->value.len);
1237 }
1238
1239 cl = ngx_alloc_chain_link(r->pool);
1240 if (cl == NULL) {
1241 return NULL;
1242 }
1243
1244 cl->buf = b;
1245 cl->next = NULL;
1246
1247 n = b->last - b->pos;
1248
1249 h3c->payload_bytes += n;
1250
1251 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_PUSH_PROMISE)
1252 + ngx_http_v3_encode_varlen_int(NULL, n);
1253
1254 b = ngx_create_temp_buf(r->pool, len);
1255 if (b == NULL) {
1256 return NULL;
1257 }
1258
1259 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last,
1260 NGX_HTTP_V3_FRAME_PUSH_PROMISE);
1261 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n);
1262
1263 hl = ngx_alloc_chain_link(r->pool);
1264 if (hl == NULL) {
1265 return NULL;
1266 }
1267
1268 hl->buf = b;
1269 hl->next = cl;
1270
1271 return hl;
1272 } 587 }
1273 588
1274 589
1275 static ngx_int_t 590 static ngx_int_t
1276 ngx_http_v3_body_filter(ngx_http_request_t *r, ngx_chain_t *in) 591 ngx_http_v3_body_filter(ngx_http_request_t *r, ngx_chain_t *in)