Mercurial > hg > nginx
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 } |