comparison src/http/v3/ngx_http_v3_request.c @ 8497:0596fe1aee16 quic

HTTP/3: server pushes. New directives are added: - http3_max_concurrent_pushes - http3_push - http3_push_preload
author Roman Arutyunyan <arut@nginx.com>
date Thu, 23 Jul 2020 13:41:24 +0300
parents e334ca1b23ba
children 830680e78b24
comparison
equal deleted inserted replaced
8496:c5324bb3a704 8497:0596fe1aee16
9 #include <ngx_core.h> 9 #include <ngx_core.h>
10 #include <ngx_http.h> 10 #include <ngx_http.h>
11 11
12 12
13 /* static table indices */ 13 /* static table indices */
14 #define NGX_HTTP_V3_HEADER_AUTHORITY 0
15 #define NGX_HTTP_V3_HEADER_PATH_ROOT 1
14 #define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO 4 16 #define NGX_HTTP_V3_HEADER_CONTENT_LENGTH_ZERO 4
15 #define NGX_HTTP_V3_HEADER_DATE 6 17 #define NGX_HTTP_V3_HEADER_DATE 6
16 #define NGX_HTTP_V3_HEADER_LAST_MODIFIED 10 18 #define NGX_HTTP_V3_HEADER_LAST_MODIFIED 10
17 #define NGX_HTTP_V3_HEADER_LOCATION 12 19 #define NGX_HTTP_V3_HEADER_LOCATION 12
20 #define NGX_HTTP_V3_HEADER_METHOD_GET 17
21 #define NGX_HTTP_V3_HEADER_SCHEME_HTTP 22
22 #define NGX_HTTP_V3_HEADER_SCHEME_HTTPS 23
18 #define NGX_HTTP_V3_HEADER_STATUS_200 25 23 #define NGX_HTTP_V3_HEADER_STATUS_200 25
24 #define NGX_HTTP_V3_HEADER_ACCEPT_ENCODING 31
19 #define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN 53 25 #define NGX_HTTP_V3_HEADER_CONTENT_TYPE_TEXT_PLAIN 53
20 #define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING 59 26 #define NGX_HTTP_V3_HEADER_VARY_ACCEPT_ENCODING 59
27 #define NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE 72
21 #define NGX_HTTP_V3_HEADER_SERVER 92 28 #define NGX_HTTP_V3_HEADER_SERVER 92
29 #define NGX_HTTP_V3_HEADER_USER_AGENT 95
22 30
23 31
24 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r, 32 static ngx_int_t ngx_http_v3_process_pseudo_header(ngx_http_request_t *r,
25 ngx_str_t *name, ngx_str_t *value); 33 ngx_str_t *name, ngx_str_t *value);
34 static ngx_int_t ngx_http_v3_push_resources(ngx_http_request_t *r,
35 ngx_chain_t ***out);
36 static ngx_int_t ngx_http_v3_push_resource(ngx_http_request_t *r,
37 ngx_str_t *path, ngx_chain_t ***out);
38 static ngx_int_t ngx_http_v3_create_push_request(
39 ngx_http_request_t *pr, ngx_str_t *path, uint64_t push_id);
40 static ngx_int_t ngx_http_v3_set_push_header(ngx_http_request_t *r,
41 const char *name, ngx_str_t *value);
42 static void ngx_http_v3_push_request_handler(ngx_event_t *ev);
43 static ngx_chain_t *ngx_http_v3_create_push_promise(ngx_http_request_t *r,
44 ngx_str_t *path, uint64_t push_id);
26 45
27 46
28 struct { 47 struct {
29 ngx_str_t name; 48 ngx_str_t name;
30 ngx_uint_t method; 49 ngx_uint_t method;
429 u_char *p; 448 u_char *p;
430 size_t len, n; 449 size_t len, n;
431 ngx_buf_t *b; 450 ngx_buf_t *b;
432 ngx_str_t host; 451 ngx_str_t host;
433 ngx_uint_t i, port; 452 ngx_uint_t i, port;
434 ngx_chain_t *hl, *cl, *bl; 453 ngx_chain_t *out, *hl, *cl, **ll;
435 ngx_list_part_t *part; 454 ngx_list_part_t *part;
436 ngx_table_elt_t *header; 455 ngx_table_elt_t *header;
437 ngx_connection_t *c; 456 ngx_connection_t *c;
438 ngx_http_core_loc_conf_t *clcf; 457 ngx_http_core_loc_conf_t *clcf;
439 ngx_http_core_srv_conf_t *cscf; 458 ngx_http_core_srv_conf_t *cscf;
440 u_char addr[NGX_SOCKADDR_STRLEN]; 459 u_char addr[NGX_SOCKADDR_STRLEN];
441 460
442 c = r->connection; 461 c = r->connection;
443 462
444 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header"); 463 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 create header");
464
465 out = NULL;
466 ll = &out;
467
468 if ((c->qs->id & NGX_QUIC_STREAM_UNIDIRECTIONAL) == 0
469 && r->method != NGX_HTTP_HEAD)
470 {
471 if (ngx_http_v3_push_resources(r, &ll) != NGX_OK) {
472 return NULL;
473 }
474 }
445 475
446 len = ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0); 476 len = ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0);
447 477
448 if (r->headers_out.status == NGX_HTTP_OK) { 478 if (r->headers_out.status == NGX_HTTP_OK) {
449 len += ngx_http_v3_encode_header_ri(NULL, 0, 479 len += ngx_http_v3_encode_header_ri(NULL, 0,
794 } 824 }
795 825
796 hl->buf = b; 826 hl->buf = b;
797 hl->next = cl; 827 hl->next = cl;
798 828
829 *ll = hl;
830 ll = &cl->next;
831
799 if (r->headers_out.content_length_n >= 0 && !r->header_only) { 832 if (r->headers_out.content_length_n >= 0 && !r->header_only) {
800 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_DATA) 833 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_DATA)
801 + ngx_http_v3_encode_varlen_int(NULL, 834 + ngx_http_v3_encode_varlen_int(NULL,
802 r->headers_out.content_length_n); 835 r->headers_out.content_length_n);
803 836
809 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, 842 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last,
810 NGX_HTTP_V3_FRAME_DATA); 843 NGX_HTTP_V3_FRAME_DATA);
811 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, 844 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last,
812 r->headers_out.content_length_n); 845 r->headers_out.content_length_n);
813 846
814 bl = ngx_alloc_chain_link(c->pool); 847 cl = ngx_alloc_chain_link(c->pool);
815 if (bl == NULL) { 848 if (cl == NULL) {
816 return NULL; 849 return NULL;
817 } 850 }
818 851
819 bl->buf = b; 852 cl->buf = b;
820 bl->next = NULL; 853 cl->next = NULL;
821 cl->next = bl; 854
822 } 855 *ll = cl;
823 856 }
824 return hl; 857
858 return out;
825 } 859 }
826 860
827 861
828 ngx_chain_t * 862 ngx_chain_t *
829 ngx_http_v3_create_trailers(ngx_http_request_t *r) 863 ngx_http_v3_create_trailers(ngx_http_request_t *r)
851 cl->buf = b; 885 cl->buf = b;
852 cl->next = NULL; 886 cl->next = NULL;
853 887
854 return cl; 888 return cl;
855 } 889 }
890
891
892 static ngx_int_t
893 ngx_http_v3_push_resources(ngx_http_request_t *r, ngx_chain_t ***out)
894 {
895 u_char *start, *end, *last;
896 ngx_str_t path;
897 ngx_int_t rc;
898 ngx_uint_t i, push;
899 ngx_table_elt_t **h;
900 ngx_http_v3_loc_conf_t *h3lcf;
901 ngx_http_complex_value_t *pushes;
902
903 h3lcf = ngx_http_get_module_loc_conf(r, ngx_http_v3_module);
904
905 if (h3lcf->pushes) {
906 pushes = h3lcf->pushes->elts;
907
908 for (i = 0; i < h3lcf->pushes->nelts; i++) {
909
910 if (ngx_http_complex_value(r, &pushes[i], &path) != NGX_OK) {
911 return NGX_ERROR;
912 }
913
914 if (path.len == 0) {
915 continue;
916 }
917
918 if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) {
919 continue;
920 }
921
922 rc = ngx_http_v3_push_resource(r, &path, out);
923
924 if (rc == NGX_ERROR) {
925 return NGX_ERROR;
926 }
927
928 if (rc == NGX_ABORT) {
929 return NGX_OK;
930 }
931
932 /* NGX_OK, NGX_DECLINED */
933 }
934 }
935
936 if (!h3lcf->push_preload) {
937 return NGX_OK;
938 }
939
940 h = r->headers_out.link.elts;
941
942 for (i = 0; i < r->headers_out.link.nelts; i++) {
943
944 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
945 "http3 parse link: \"%V\"", &h[i]->value);
946
947 start = h[i]->value.data;
948 end = h[i]->value.data + h[i]->value.len;
949
950 next_link:
951
952 while (start < end && *start == ' ') { start++; }
953
954 if (start == end || *start++ != '<') {
955 continue;
956 }
957
958 while (start < end && *start == ' ') { start++; }
959
960 for (last = start; last < end && *last != '>'; last++) {
961 /* void */
962 }
963
964 if (last == start || last == end) {
965 continue;
966 }
967
968 path.len = last - start;
969 path.data = start;
970
971 start = last + 1;
972
973 while (start < end && *start == ' ') { start++; }
974
975 if (start == end) {
976 continue;
977 }
978
979 if (*start == ',') {
980 start++;
981 goto next_link;
982 }
983
984 if (*start++ != ';') {
985 continue;
986 }
987
988 last = ngx_strlchr(start, end, ',');
989
990 if (last == NULL) {
991 last = end;
992 }
993
994 push = 0;
995
996 for ( ;; ) {
997
998 while (start < last && *start == ' ') { start++; }
999
1000 if (last - start >= 6
1001 && ngx_strncasecmp(start, (u_char *) "nopush", 6) == 0)
1002 {
1003 start += 6;
1004
1005 if (start == last || *start == ' ' || *start == ';') {
1006 push = 0;
1007 break;
1008 }
1009
1010 goto next_param;
1011 }
1012
1013 if (last - start >= 11
1014 && ngx_strncasecmp(start, (u_char *) "rel=preload", 11) == 0)
1015 {
1016 start += 11;
1017
1018 if (start == last || *start == ' ' || *start == ';') {
1019 push = 1;
1020 }
1021
1022 goto next_param;
1023 }
1024
1025 if (last - start >= 4
1026 && ngx_strncasecmp(start, (u_char *) "rel=", 4) == 0)
1027 {
1028 start += 4;
1029
1030 while (start < last && *start == ' ') { start++; }
1031
1032 if (start == last || *start++ != '"') {
1033 goto next_param;
1034 }
1035
1036 for ( ;; ) {
1037
1038 while (start < last && *start == ' ') { start++; }
1039
1040 if (last - start >= 7
1041 && ngx_strncasecmp(start, (u_char *) "preload", 7) == 0)
1042 {
1043 start += 7;
1044
1045 if (start < last && (*start == ' ' || *start == '"')) {
1046 push = 1;
1047 break;
1048 }
1049 }
1050
1051 while (start < last && *start != ' ' && *start != '"') {
1052 start++;
1053 }
1054
1055 if (start == last) {
1056 break;
1057 }
1058
1059 if (*start == '"') {
1060 break;
1061 }
1062
1063 start++;
1064 }
1065 }
1066
1067 next_param:
1068
1069 start = ngx_strlchr(start, last, ';');
1070
1071 if (start == NULL) {
1072 break;
1073 }
1074
1075 start++;
1076 }
1077
1078 if (push) {
1079 while (path.len && path.data[path.len - 1] == ' ') {
1080 path.len--;
1081 }
1082 }
1083
1084 if (push && path.len
1085 && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/'))
1086 {
1087 rc = ngx_http_v3_push_resource(r, &path, out);
1088
1089 if (rc == NGX_ERROR) {
1090 return NGX_ERROR;
1091 }
1092
1093 if (rc == NGX_ABORT) {
1094 return NGX_OK;
1095 }
1096
1097 /* NGX_OK, NGX_DECLINED */
1098 }
1099
1100 if (last < end) {
1101 start = last + 1;
1102 goto next_link;
1103 }
1104 }
1105
1106 return NGX_OK;
1107 }
1108
1109
1110 static ngx_int_t
1111 ngx_http_v3_push_resource(ngx_http_request_t *r, ngx_str_t *path,
1112 ngx_chain_t ***ll)
1113 {
1114 uint64_t push_id;
1115 ngx_int_t rc;
1116 ngx_chain_t *cl;
1117 ngx_connection_t *c;
1118 ngx_http_v3_srv_conf_t *h3scf;
1119 ngx_http_v3_connection_t *h3c;
1120
1121 c = r->connection;
1122 h3c = c->qs->parent->data;
1123 h3scf = ngx_http_get_module_srv_conf(r, ngx_http_v3_module);
1124
1125 ngx_log_debug5(NGX_LOG_DEBUG_HTTP, c->log, 0,
1126 "http3 push \"%V\" pushing:%ui/%ui id:%uL/%uL",
1127 path, h3c->npushing, h3scf->max_concurrent_pushes,
1128 h3c->next_push_id, h3c->max_push_id);
1129
1130 if (!ngx_path_separator(path->data[0])) {
1131 ngx_log_error(NGX_LOG_WARN, c->log, 0,
1132 "non-absolute path \"%V\" not pushed", path);
1133 return NGX_DECLINED;
1134 }
1135
1136 if (h3c->next_push_id > h3c->max_push_id) {
1137 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1138 "http3 abort pushes due to max_push_id");
1139 return NGX_ABORT;
1140 }
1141
1142 if (h3c->npushing >= h3scf->max_concurrent_pushes) {
1143 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0,
1144 "http3 abort pushes due to max_concurrent_pushes");
1145 return NGX_ABORT;
1146 }
1147
1148 push_id = h3c->next_push_id++;
1149
1150 rc = ngx_http_v3_create_push_request(r, path, push_id);
1151 if (rc != NGX_OK) {
1152 return rc;
1153 }
1154
1155 cl = ngx_http_v3_create_push_promise(r, path, push_id);
1156 if (cl == NULL) {
1157 return NGX_ERROR;
1158 }
1159
1160 for (**ll = cl; **ll; *ll = &(**ll)->next);
1161
1162 return NGX_OK;
1163 }
1164
1165
1166 static ngx_int_t
1167 ngx_http_v3_create_push_request(ngx_http_request_t *pr, ngx_str_t *path,
1168 uint64_t push_id)
1169 {
1170 ngx_pool_t *pool;
1171 ngx_connection_t *c, *pc;
1172 ngx_http_request_t *r;
1173 ngx_http_log_ctx_t *ctx;
1174 ngx_http_connection_t *hc;
1175 ngx_http_core_srv_conf_t *cscf;
1176 ngx_http_v3_connection_t *h3c;
1177
1178 pc = pr->connection;
1179
1180 r = NULL;
1181
1182 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
1183 "http3 create push request id:%uL", push_id);
1184
1185 c = ngx_http_v3_create_push_stream(pc, push_id);
1186 if (c == NULL) {
1187 return NGX_ABORT;
1188 }
1189
1190 hc = ngx_palloc(c->pool, sizeof(ngx_http_connection_t));
1191 if (hc == NULL) {
1192 goto failed;
1193 }
1194
1195 h3c = c->qs->parent->data;
1196 ngx_memcpy(hc, h3c, sizeof(ngx_http_connection_t));
1197 c->data = hc;
1198
1199 ctx = ngx_palloc(c->pool, sizeof(ngx_http_log_ctx_t));
1200 if (ctx == NULL) {
1201 goto failed;
1202 }
1203
1204 ctx->connection = c;
1205 ctx->request = NULL;
1206 ctx->current_request = NULL;
1207
1208 c->log->handler = ngx_http_log_error;
1209 c->log->data = ctx;
1210 c->log->action = "processing pushed request headers";
1211
1212 c->log_error = NGX_ERROR_INFO;
1213
1214 r = ngx_http_create_request(c);
1215 if (r == NULL) {
1216 goto failed;
1217 }
1218
1219 c->data = r;
1220
1221 ngx_str_set(&r->http_protocol, "HTTP/3.0");
1222
1223 r->method_name = ngx_http_core_get_method;
1224 r->method = NGX_HTTP_GET;
1225
1226 cscf = ngx_http_get_module_srv_conf(r, ngx_http_core_module);
1227
1228 r->header_in = ngx_create_temp_buf(r->pool,
1229 cscf->client_header_buffer_size);
1230 if (r->header_in == NULL) {
1231 goto failed;
1232 }
1233
1234 if (ngx_list_init(&r->headers_in.headers, r->pool, 4,
1235 sizeof(ngx_table_elt_t))
1236 != NGX_OK)
1237 {
1238 goto failed;
1239 }
1240
1241 r->headers_in.connection_type = NGX_HTTP_CONNECTION_CLOSE;
1242
1243 r->schema.data = ngx_pstrdup(r->pool, &pr->schema);
1244 if (r->schema.data == NULL) {
1245 goto failed;
1246 }
1247
1248 r->schema.len = pr->schema.len;
1249
1250 r->uri_start = ngx_pstrdup(r->pool, path);
1251 if (r->uri_start == NULL) {
1252 goto failed;
1253 }
1254
1255 r->uri_end = r->uri_start + path->len;
1256
1257 if (ngx_http_parse_uri(r) != NGX_OK) {
1258 goto failed;
1259 }
1260
1261 if (ngx_http_process_request_uri(r) != NGX_OK) {
1262 goto failed;
1263 }
1264
1265 if (ngx_http_v3_set_push_header(r, "host", &pr->headers_in.server)
1266 != NGX_OK)
1267 {
1268 goto failed;
1269 }
1270
1271 if (pr->headers_in.accept_encoding) {
1272 if (ngx_http_v3_set_push_header(r, "accept-encoding",
1273 &pr->headers_in.accept_encoding->value)
1274 != NGX_OK)
1275 {
1276 goto failed;
1277 }
1278 }
1279
1280 if (pr->headers_in.accept_language) {
1281 if (ngx_http_v3_set_push_header(r, "accept-language",
1282 &pr->headers_in.accept_language->value)
1283 != NGX_OK)
1284 {
1285 goto failed;
1286 }
1287 }
1288
1289 if (pr->headers_in.user_agent) {
1290 if (ngx_http_v3_set_push_header(r, "user-agent",
1291 &pr->headers_in.user_agent->value)
1292 != NGX_OK)
1293 {
1294 goto failed;
1295 }
1296 }
1297
1298 c->read->handler = ngx_http_v3_push_request_handler;
1299 c->read->handler = ngx_http_v3_push_request_handler;
1300
1301 ngx_post_event(c->read, &ngx_posted_events);
1302
1303 return NGX_OK;
1304
1305 failed:
1306
1307 if (r) {
1308 ngx_http_free_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR);
1309 }
1310
1311 c->destroyed = 1;
1312
1313 pool = c->pool;
1314
1315 ngx_close_connection(c);
1316
1317 ngx_destroy_pool(pool);
1318
1319 return NGX_ERROR;
1320 }
1321
1322
1323 static ngx_int_t
1324 ngx_http_v3_set_push_header(ngx_http_request_t *r, const char *name,
1325 ngx_str_t *value)
1326 {
1327 u_char *p;
1328 ngx_table_elt_t *h;
1329 ngx_http_header_t *hh;
1330 ngx_http_core_main_conf_t *cmcf;
1331
1332 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1333 "http3 push header \"%s\": \"%V\"", name, value);
1334
1335 cmcf = ngx_http_get_module_main_conf(r, ngx_http_core_module);
1336
1337 p = ngx_pnalloc(r->pool, value->len + 1);
1338 if (p == NULL) {
1339 return NGX_ERROR;
1340 }
1341
1342 ngx_memcpy(p, value->data, value->len);
1343 p[value->len] = '\0';
1344
1345 h = ngx_list_push(&r->headers_in.headers);
1346 if (h == NULL) {
1347 return NGX_ERROR;
1348 }
1349
1350 h->key.data = (u_char *) name;
1351 h->key.len = ngx_strlen(name);
1352 h->hash = ngx_hash_key(h->key.data, h->key.len);
1353 h->lowcase_key = (u_char *) name;
1354 h->value.data = p;
1355 h->value.len = value->len;
1356
1357 hh = ngx_hash_find(&cmcf->headers_in_hash, h->hash,
1358 h->lowcase_key, h->key.len);
1359
1360 if (hh && hh->handler(r, h, hh->offset) != NGX_OK) {
1361 return NGX_ERROR;
1362 }
1363
1364 return NGX_OK;
1365 }
1366
1367
1368 static void
1369 ngx_http_v3_push_request_handler(ngx_event_t *ev)
1370 {
1371 ngx_connection_t *c;
1372 ngx_http_request_t *r;
1373
1374 c = ev->data;
1375 r = c->data;
1376
1377 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "http3 push request handler");
1378
1379 ngx_http_process_request(r);
1380 }
1381
1382
1383 static ngx_chain_t *
1384 ngx_http_v3_create_push_promise(ngx_http_request_t *r, ngx_str_t *path,
1385 uint64_t push_id)
1386 {
1387 size_t n, len;
1388 ngx_buf_t *b;
1389 ngx_chain_t *hl, *cl;
1390
1391 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
1392 "http3 create push promise id:%uL", push_id);
1393
1394 len = ngx_http_v3_encode_varlen_int(NULL, push_id);
1395
1396 len += ngx_http_v3_encode_header_block_prefix(NULL, 0, 0, 0);
1397
1398 len += ngx_http_v3_encode_header_ri(NULL, 0,
1399 NGX_HTTP_V3_HEADER_METHOD_GET);
1400
1401 len += ngx_http_v3_encode_header_lri(NULL, 0,
1402 NGX_HTTP_V3_HEADER_AUTHORITY,
1403 NULL, r->headers_in.server.len);
1404
1405 if (path->len == 1 && path->data[0] == '/') {
1406 len += ngx_http_v3_encode_header_ri(NULL, 0,
1407 NGX_HTTP_V3_HEADER_PATH_ROOT);
1408
1409 } else {
1410 len += ngx_http_v3_encode_header_lri(NULL, 0,
1411 NGX_HTTP_V3_HEADER_PATH_ROOT,
1412 NULL, path->len);
1413 }
1414
1415 if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) {
1416 len += ngx_http_v3_encode_header_ri(NULL, 0,
1417 NGX_HTTP_V3_HEADER_SCHEME_HTTPS);
1418
1419 } else if (r->schema.len == 4
1420 && ngx_strncmp(r->schema.data, "http", 4) == 0)
1421 {
1422 len += ngx_http_v3_encode_header_ri(NULL, 0,
1423 NGX_HTTP_V3_HEADER_SCHEME_HTTP);
1424
1425 } else {
1426 len += ngx_http_v3_encode_header_lri(NULL, 0,
1427 NGX_HTTP_V3_HEADER_SCHEME_HTTP,
1428 NULL, r->schema.len);
1429 }
1430
1431 if (r->headers_in.accept_encoding) {
1432 len += ngx_http_v3_encode_header_lri(NULL, 0,
1433 NGX_HTTP_V3_HEADER_ACCEPT_ENCODING, NULL,
1434 r->headers_in.accept_encoding->value.len);
1435 }
1436
1437 if (r->headers_in.accept_language) {
1438 len += ngx_http_v3_encode_header_lri(NULL, 0,
1439 NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE, NULL,
1440 r->headers_in.accept_language->value.len);
1441 }
1442
1443 if (r->headers_in.user_agent) {
1444 len += ngx_http_v3_encode_header_lri(NULL, 0,
1445 NGX_HTTP_V3_HEADER_USER_AGENT, NULL,
1446 r->headers_in.user_agent->value.len);
1447 }
1448
1449 b = ngx_create_temp_buf(r->pool, len);
1450 if (b == NULL) {
1451 return NULL;
1452 }
1453
1454 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, push_id);
1455
1456 b->last = (u_char *) ngx_http_v3_encode_header_block_prefix(b->last,
1457 0, 0, 0);
1458
1459 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
1460 NGX_HTTP_V3_HEADER_METHOD_GET);
1461
1462 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
1463 NGX_HTTP_V3_HEADER_AUTHORITY,
1464 r->headers_in.server.data,
1465 r->headers_in.server.len);
1466
1467 if (path->len == 1 && path->data[0] == '/') {
1468 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
1469 NGX_HTTP_V3_HEADER_PATH_ROOT);
1470
1471 } else {
1472 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
1473 NGX_HTTP_V3_HEADER_PATH_ROOT,
1474 path->data, path->len);
1475 }
1476
1477 if (r->schema.len == 5 && ngx_strncmp(r->schema.data, "https", 5) == 0) {
1478 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
1479 NGX_HTTP_V3_HEADER_SCHEME_HTTPS);
1480
1481 } else if (r->schema.len == 4
1482 && ngx_strncmp(r->schema.data, "http", 4) == 0)
1483 {
1484 b->last = (u_char *) ngx_http_v3_encode_header_ri(b->last, 0,
1485 NGX_HTTP_V3_HEADER_SCHEME_HTTP);
1486
1487 } else {
1488 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
1489 NGX_HTTP_V3_HEADER_SCHEME_HTTP,
1490 r->schema.data, r->schema.len);
1491 }
1492
1493 if (r->headers_in.accept_encoding) {
1494 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
1495 NGX_HTTP_V3_HEADER_ACCEPT_ENCODING,
1496 r->headers_in.accept_encoding->value.data,
1497 r->headers_in.accept_encoding->value.len);
1498 }
1499
1500 if (r->headers_in.accept_language) {
1501 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
1502 NGX_HTTP_V3_HEADER_ACCEPT_LANGUAGE,
1503 r->headers_in.accept_language->value.data,
1504 r->headers_in.accept_language->value.len);
1505 }
1506
1507 if (r->headers_in.user_agent) {
1508 b->last = (u_char *) ngx_http_v3_encode_header_lri(b->last, 0,
1509 NGX_HTTP_V3_HEADER_USER_AGENT,
1510 r->headers_in.user_agent->value.data,
1511 r->headers_in.user_agent->value.len);
1512 }
1513
1514 cl = ngx_alloc_chain_link(r->pool);
1515 if (cl == NULL) {
1516 return NULL;
1517 }
1518
1519 cl->buf = b;
1520 cl->next = NULL;
1521
1522 n = b->last - b->pos;
1523
1524 len = ngx_http_v3_encode_varlen_int(NULL, NGX_HTTP_V3_FRAME_PUSH_PROMISE)
1525 + ngx_http_v3_encode_varlen_int(NULL, n);
1526
1527 b = ngx_create_temp_buf(r->pool, len);
1528 if (b == NULL) {
1529 return NULL;
1530 }
1531
1532 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last,
1533 NGX_HTTP_V3_FRAME_PUSH_PROMISE);
1534 b->last = (u_char *) ngx_http_v3_encode_varlen_int(b->last, n);
1535
1536 hl = ngx_alloc_chain_link(r->pool);
1537 if (hl == NULL) {
1538 return NULL;
1539 }
1540
1541 hl->buf = b;
1542 hl->next = cl;
1543
1544 return hl;
1545 }