Mercurial > hg > nginx
comparison src/http/v2/ngx_http_v2_filter_module.c @ 7207:3d2b0b02bd3d
HTTP/2: push additional request headers (closes #1478).
The Accept-Encoding, Accept-Language, and User-Agent header fields
are now copied from the original request to pushed requests.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Thu, 15 Feb 2018 17:51:32 +0300 |
parents | e44c297a6b95 |
children | 87e9e4aabf1b |
comparison
equal
deleted
inserted
replaced
7206:33edea74bd58 | 7207:3d2b0b02bd3d |
---|---|
48 #define NGX_HTTP_V2_STATUS_304_INDEX 11 | 48 #define NGX_HTTP_V2_STATUS_304_INDEX 11 |
49 #define NGX_HTTP_V2_STATUS_400_INDEX 12 | 49 #define NGX_HTTP_V2_STATUS_400_INDEX 12 |
50 #define NGX_HTTP_V2_STATUS_404_INDEX 13 | 50 #define NGX_HTTP_V2_STATUS_404_INDEX 13 |
51 #define NGX_HTTP_V2_STATUS_500_INDEX 14 | 51 #define NGX_HTTP_V2_STATUS_500_INDEX 14 |
52 | 52 |
53 #define NGX_HTTP_V2_ACCEPT_ENCODING_INDEX 16 | |
54 #define NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX 17 | |
53 #define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28 | 55 #define NGX_HTTP_V2_CONTENT_LENGTH_INDEX 28 |
54 #define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31 | 56 #define NGX_HTTP_V2_CONTENT_TYPE_INDEX 31 |
55 #define NGX_HTTP_V2_DATE_INDEX 33 | 57 #define NGX_HTTP_V2_DATE_INDEX 33 |
56 #define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44 | 58 #define NGX_HTTP_V2_LAST_MODIFIED_INDEX 44 |
57 #define NGX_HTTP_V2_LOCATION_INDEX 46 | 59 #define NGX_HTTP_V2_LOCATION_INDEX 46 |
58 #define NGX_HTTP_V2_SERVER_INDEX 54 | 60 #define NGX_HTTP_V2_SERVER_INDEX 54 |
61 #define NGX_HTTP_V2_USER_AGENT_INDEX 58 | |
59 #define NGX_HTTP_V2_VARY_INDEX 59 | 62 #define NGX_HTTP_V2_VARY_INDEX 59 |
60 | 63 |
61 #define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 | 64 #define NGX_HTTP_V2_NO_TRAILERS (ngx_http_v2_out_frame_t *) -1 |
65 | |
66 | |
67 typedef struct { | |
68 ngx_str_t name; | |
69 u_char index; | |
70 ngx_uint_t offset; | |
71 } ngx_http_v2_push_header_t; | |
72 | |
73 | |
74 static ngx_http_v2_push_header_t ngx_http_v2_push_headers[] = { | |
75 { ngx_string(":authority"), NGX_HTTP_V2_AUTHORITY_INDEX, | |
76 offsetof(ngx_http_headers_in_t, host) }, | |
77 | |
78 { ngx_string("accept-encoding"), NGX_HTTP_V2_ACCEPT_ENCODING_INDEX, | |
79 offsetof(ngx_http_headers_in_t, accept_encoding) }, | |
80 | |
81 { ngx_string("accept-language"), NGX_HTTP_V2_ACCEPT_LANGUAGE_INDEX, | |
82 offsetof(ngx_http_headers_in_t, accept_language) }, | |
83 | |
84 { ngx_string("user-agent"), NGX_HTTP_V2_USER_AGENT_INDEX, | |
85 offsetof(ngx_http_headers_in_t, user_agent) }, | |
86 }; | |
87 | |
88 #define NGX_HTTP_V2_PUSH_HEADERS \ | |
89 (sizeof(ngx_http_v2_push_headers) / sizeof(ngx_http_v2_push_header_t)) | |
62 | 90 |
63 | 91 |
64 static ngx_int_t ngx_http_v2_push_resources(ngx_http_request_t *r); | 92 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, | 93 static ngx_int_t ngx_http_v2_push_resource(ngx_http_request_t *r, |
66 ngx_str_t *path, ngx_str_t *authority); | 94 ngx_str_t *path, ngx_str_t *binary); |
67 | 95 |
68 static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, | 96 static u_char *ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, |
69 u_char *tmp, ngx_uint_t lower); | 97 u_char *tmp, ngx_uint_t lower); |
70 static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, | 98 static u_char *ngx_http_v2_write_int(u_char *pos, ngx_uint_t prefix, |
71 ngx_uint_t value); | 99 ngx_uint_t value); |
683 static ngx_int_t | 711 static ngx_int_t |
684 ngx_http_v2_push_resources(ngx_http_request_t *r) | 712 ngx_http_v2_push_resources(ngx_http_request_t *r) |
685 { | 713 { |
686 u_char *start, *end, *last; | 714 u_char *start, *end, *last; |
687 ngx_int_t rc; | 715 ngx_int_t rc; |
688 ngx_str_t path, authority; | 716 ngx_str_t path; |
689 ngx_uint_t i, push; | 717 ngx_uint_t i, push; |
690 ngx_table_elt_t **h; | 718 ngx_table_elt_t **h; |
691 ngx_http_v2_loc_conf_t *h2lcf; | 719 ngx_http_v2_loc_conf_t *h2lcf; |
692 ngx_http_complex_value_t *pushes; | 720 ngx_http_complex_value_t *pushes; |
721 ngx_str_t binary[NGX_HTTP_V2_PUSH_HEADERS]; | |
693 | 722 |
694 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 723 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
695 "http2 push resources"); | 724 "http2 push resources"); |
696 | 725 |
697 ngx_str_null(&authority); | 726 ngx_memzero(binary, NGX_HTTP_V2_PUSH_HEADERS * sizeof(ngx_str_t)); |
698 | 727 |
699 h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module); | 728 h2lcf = ngx_http_get_module_loc_conf(r, ngx_http_v2_module); |
700 | 729 |
701 if (h2lcf->pushes) { | 730 if (h2lcf->pushes) { |
702 pushes = h2lcf->pushes->elts; | 731 pushes = h2lcf->pushes->elts; |
713 | 742 |
714 if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) { | 743 if (path.len == 3 && ngx_strncmp(path.data, "off", 3) == 0) { |
715 continue; | 744 continue; |
716 } | 745 } |
717 | 746 |
718 rc = ngx_http_v2_push_resource(r, &path, &authority); | 747 rc = ngx_http_v2_push_resource(r, &path, binary); |
719 | 748 |
720 if (rc == NGX_ERROR) { | 749 if (rc == NGX_ERROR) { |
721 return NGX_ERROR; | 750 return NGX_ERROR; |
722 } | 751 } |
723 | 752 |
878 } | 907 } |
879 | 908 |
880 if (push && path.len | 909 if (push && path.len |
881 && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/')) | 910 && !(path.len > 1 && path.data[0] == '/' && path.data[1] == '/')) |
882 { | 911 { |
883 rc = ngx_http_v2_push_resource(r, &path, &authority); | 912 rc = ngx_http_v2_push_resource(r, &path, binary); |
884 | 913 |
885 if (rc == NGX_ERROR) { | 914 if (rc == NGX_ERROR) { |
886 return NGX_ERROR; | 915 return NGX_ERROR; |
887 } | 916 } |
888 | 917 |
903 } | 932 } |
904 | 933 |
905 | 934 |
906 static ngx_int_t | 935 static ngx_int_t |
907 ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, | 936 ngx_http_v2_push_resource(ngx_http_request_t *r, ngx_str_t *path, |
908 ngx_str_t *authority) | 937 ngx_str_t *binary) |
909 { | 938 { |
910 u_char *start, *pos, *tmp; | 939 u_char *start, *pos, *tmp; |
911 size_t len; | 940 size_t len; |
912 ngx_table_elt_t *host; | 941 ngx_str_t *value; |
913 ngx_connection_t *fc; | 942 ngx_uint_t i; |
914 ngx_http_v2_stream_t *stream; | 943 ngx_table_elt_t **h; |
915 ngx_http_v2_out_frame_t *frame; | 944 ngx_connection_t *fc; |
916 ngx_http_v2_connection_t *h2c; | 945 ngx_http_v2_stream_t *stream; |
946 ngx_http_v2_out_frame_t *frame; | |
947 ngx_http_v2_connection_t *h2c; | |
948 ngx_http_v2_push_header_t *ph; | |
917 | 949 |
918 fc = r->connection; | 950 fc = r->connection; |
919 | 951 |
920 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 push resource"); | 952 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, "http2 push resource"); |
921 | 953 |
942 | 974 |
943 if (path->len > NGX_HTTP_V2_MAX_FIELD) { | 975 if (path->len > NGX_HTTP_V2_MAX_FIELD) { |
944 return NGX_DECLINED; | 976 return NGX_DECLINED; |
945 } | 977 } |
946 | 978 |
947 host = r->headers_in.host; | 979 if (r->headers_in.host == NULL) { |
948 | |
949 if (host == NULL) { | |
950 return NGX_ABORT; | 980 return NGX_ABORT; |
951 } | 981 } |
952 | 982 |
953 if (authority->len == 0) { | 983 ph = ngx_http_v2_push_headers; |
954 | 984 |
955 len = 1 + NGX_HTTP_V2_INT_OCTETS + host->value.len; | 985 if (binary[0].len) { |
986 tmp = ngx_palloc(r->pool, path->len); | |
987 if (tmp == NULL) { | |
988 return NGX_ERROR; | |
989 } | |
990 | |
991 } else { | |
992 len = path->len; | |
993 | |
994 for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { | |
995 h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); | |
996 | |
997 if (*h) { | |
998 len = ngx_max(len, (*h)->value.len); | |
999 } | |
1000 } | |
956 | 1001 |
957 tmp = ngx_palloc(r->pool, len); | 1002 tmp = ngx_palloc(r->pool, len); |
958 pos = ngx_pnalloc(r->pool, len); | 1003 if (tmp == NULL) { |
959 | |
960 if (pos == NULL || tmp == NULL) { | |
961 return NGX_ERROR; | 1004 return NGX_ERROR; |
962 } | 1005 } |
963 | 1006 |
964 authority->data = pos; | 1007 for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { |
965 | 1008 h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); |
966 *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_AUTHORITY_INDEX); | 1009 |
967 pos = ngx_http_v2_write_value(pos, host->value.data, host->value.len, | 1010 if (*h == NULL) { |
968 tmp); | 1011 continue; |
969 | 1012 } |
970 authority->len = pos - authority->data; | 1013 |
1014 value = &(*h)->value; | |
1015 | |
1016 len = 1 + NGX_HTTP_V2_INT_OCTETS + value->len; | |
1017 | |
1018 pos = ngx_pnalloc(r->pool, len); | |
1019 if (pos == NULL) { | |
1020 return NGX_ERROR; | |
1021 } | |
1022 | |
1023 binary[i].data = pos; | |
1024 | |
1025 *pos++ = ngx_http_v2_inc_indexed(ph[i].index); | |
1026 pos = ngx_http_v2_write_value(pos, value->data, value->len, tmp); | |
1027 | |
1028 binary[i].len = pos - binary[i].data; | |
1029 } | |
971 } | 1030 } |
972 | 1031 |
973 len = (h2c->table_update ? 1 : 0) | 1032 len = (h2c->table_update ? 1 : 0) |
974 + 1 | 1033 + 1 |
975 + 1 + NGX_HTTP_V2_INT_OCTETS + path->len | 1034 + 1 + NGX_HTTP_V2_INT_OCTETS + path->len |
976 + authority->len | |
977 + 1; | 1035 + 1; |
978 | 1036 |
979 tmp = ngx_palloc(r->pool, len); | 1037 for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { |
1038 len += binary[i].len; | |
1039 } | |
1040 | |
980 pos = ngx_pnalloc(r->pool, len); | 1041 pos = ngx_pnalloc(r->pool, len); |
981 | 1042 if (pos == NULL) { |
982 if (pos == NULL || tmp == NULL) { | |
983 return NGX_ERROR; | 1043 return NGX_ERROR; |
984 } | 1044 } |
985 | 1045 |
986 start = pos; | 1046 start = pos; |
987 | 1047 |
1000 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, | 1060 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, |
1001 "http2 push header: \":path: %V\"", path); | 1061 "http2 push header: \":path: %V\"", path); |
1002 | 1062 |
1003 *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); | 1063 *pos++ = ngx_http_v2_inc_indexed(NGX_HTTP_V2_PATH_INDEX); |
1004 pos = ngx_http_v2_write_value(pos, path->data, path->len, tmp); | 1064 pos = ngx_http_v2_write_value(pos, path->data, path->len, tmp); |
1005 | |
1006 ngx_log_debug1(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
1007 "http2 push header: \":authority: %V\"", &host->value); | |
1008 | |
1009 pos = ngx_cpymem(pos, authority->data, authority->len); | |
1010 | 1065 |
1011 #if (NGX_HTTP_SSL) | 1066 #if (NGX_HTTP_SSL) |
1012 if (fc->ssl) { | 1067 if (fc->ssl) { |
1013 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | 1068 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, |
1014 "http2 push header: \":scheme: https\""); | 1069 "http2 push header: \":scheme: https\""); |
1020 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, | 1075 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, fc->log, 0, |
1021 "http2 push header: \":scheme: http\""); | 1076 "http2 push header: \":scheme: http\""); |
1022 *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); | 1077 *pos++ = ngx_http_v2_indexed(NGX_HTTP_V2_SCHEME_HTTP_INDEX); |
1023 } | 1078 } |
1024 | 1079 |
1080 for (i = 0; i < NGX_HTTP_V2_PUSH_HEADERS; i++) { | |
1081 h = (ngx_table_elt_t **) ((char *) &r->headers_in + ph[i].offset); | |
1082 | |
1083 if (*h == NULL) { | |
1084 continue; | |
1085 } | |
1086 | |
1087 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, fc->log, 0, | |
1088 "http2 push header: \"%V: %V\"", | |
1089 &ph[i].name, &(*h)->value); | |
1090 | |
1091 pos = ngx_cpymem(pos, binary[i].data, binary[i].len); | |
1092 } | |
1093 | |
1025 frame = ngx_http_v2_create_push_frame(r, start, pos); | 1094 frame = ngx_http_v2_create_push_frame(r, start, pos); |
1026 if (frame == NULL) { | 1095 if (frame == NULL) { |
1027 return NGX_ERROR; | 1096 return NGX_ERROR; |
1028 } | 1097 } |
1029 | 1098 |
1030 ngx_http_v2_queue_blocked_frame(h2c, frame); | 1099 ngx_http_v2_queue_blocked_frame(h2c, frame); |
1031 | 1100 |
1032 stream->queued++; | 1101 stream->queued++; |
1033 | 1102 |
1034 return ngx_http_v2_push_stream(h2c, stream->node->id, pos - start, | 1103 stream = ngx_http_v2_push_stream(stream, path); |
1035 path, &host->value); | 1104 |
1105 if (stream) { | |
1106 stream->request->request_length = pos - start; | |
1107 return NGX_OK; | |
1108 } | |
1109 | |
1110 return NGX_ERROR; | |
1036 } | 1111 } |
1037 | 1112 |
1038 | 1113 |
1039 static u_char * | 1114 static u_char * |
1040 ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, | 1115 ngx_http_v2_string_encode(u_char *dst, u_char *src, size_t len, u_char *tmp, |