comparison src/http/ngx_http_variables.c @ 8023:08b3ea81ff5f

Combining unknown headers during variables lookup (ticket #1316). Previously, $http_*, $sent_http_*, $sent_trailer_*, $upstream_http_*, and $upstream_trailer_* variables returned only the first header (with a few specially handled exceptions: $http_cookie, $http_x_forwarded_for, $sent_http_cache_control, $sent_http_link). With this change, all headers are returned, combined together. For example, $http_foo variable will be "a, b" if there are "Foo: a" and "Foo: b" headers in the request. Note that $upstream_http_set_cookie will also return all "Set-Cookie" headers (ticket #1843), though this might not be what one want, since the "Set-Cookie" header does not follow the list syntax (see RFC 7230, section 3.2.2).
author Maxim Dounin <mdounin@mdounin.ru>
date Mon, 30 May 2022 21:25:32 +0300
parents ae7c767aa491
children ef6a3a99a81a
comparison
equal deleted inserted replaced
8022:8b7a96fdd54c 8023:08b3ea81ff5f
917 917
918 static ngx_int_t 918 static ngx_int_t
919 ngx_http_variable_unknown_header_in(ngx_http_request_t *r, 919 ngx_http_variable_unknown_header_in(ngx_http_request_t *r,
920 ngx_http_variable_value_t *v, uintptr_t data) 920 ngx_http_variable_value_t *v, uintptr_t data)
921 { 921 {
922 return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, 922 return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
923 &r->headers_in.headers.part, 923 &r->headers_in.headers.part,
924 sizeof("http_") - 1); 924 sizeof("http_") - 1);
925 } 925 }
926 926
927 927
928 static ngx_int_t 928 static ngx_int_t
929 ngx_http_variable_unknown_header_out(ngx_http_request_t *r, 929 ngx_http_variable_unknown_header_out(ngx_http_request_t *r,
930 ngx_http_variable_value_t *v, uintptr_t data) 930 ngx_http_variable_value_t *v, uintptr_t data)
931 { 931 {
932 return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, 932 return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
933 &r->headers_out.headers.part, 933 &r->headers_out.headers.part,
934 sizeof("sent_http_") - 1); 934 sizeof("sent_http_") - 1);
935 } 935 }
936 936
937 937
938 static ngx_int_t 938 static ngx_int_t
939 ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r, 939 ngx_http_variable_unknown_trailer_out(ngx_http_request_t *r,
940 ngx_http_variable_value_t *v, uintptr_t data) 940 ngx_http_variable_value_t *v, uintptr_t data)
941 { 941 {
942 return ngx_http_variable_unknown_header(v, (ngx_str_t *) data, 942 return ngx_http_variable_unknown_header(r, v, (ngx_str_t *) data,
943 &r->headers_out.trailers.part, 943 &r->headers_out.trailers.part,
944 sizeof("sent_trailer_") - 1); 944 sizeof("sent_trailer_") - 1);
945 } 945 }
946 946
947 947
948 ngx_int_t 948 ngx_int_t
949 ngx_http_variable_unknown_header(ngx_http_variable_value_t *v, ngx_str_t *var, 949 ngx_http_variable_unknown_header(ngx_http_request_t *r,
950 ngx_http_variable_value_t *v, ngx_str_t *var,
950 ngx_list_part_t *part, size_t prefix) 951 ngx_list_part_t *part, size_t prefix)
951 { 952 {
952 u_char ch; 953 u_char *p, ch;
954 size_t len;
953 ngx_uint_t i, n; 955 ngx_uint_t i, n;
954 ngx_table_elt_t *header; 956 ngx_table_elt_t *header, *h, **ph;
957
958 ph = &h;
959 #if (NGX_SUPPRESS_WARN)
960 len = 0;
961 #endif
955 962
956 header = part->elts; 963 header = part->elts;
957 964
958 for (i = 0; /* void */ ; i++) { 965 for (i = 0; /* void */ ; i++) {
959 966
969 976
970 if (header[i].hash == 0) { 977 if (header[i].hash == 0) {
971 continue; 978 continue;
972 } 979 }
973 980
974 for (n = 0; n + prefix < var->len && n < header[i].key.len; n++) { 981 if (header[i].key.len != var->len - prefix) {
982 continue;
983 }
984
985 for (n = 0; n < var->len - prefix; n++) {
975 ch = header[i].key.data[n]; 986 ch = header[i].key.data[n];
976 987
977 if (ch >= 'A' && ch <= 'Z') { 988 if (ch >= 'A' && ch <= 'Z') {
978 ch |= 0x20; 989 ch |= 0x20;
979 990
984 if (var->data[n + prefix] != ch) { 995 if (var->data[n + prefix] != ch) {
985 break; 996 break;
986 } 997 }
987 } 998 }
988 999
989 if (n + prefix == var->len && n == header[i].key.len) { 1000 if (n != var->len - prefix) {
990 v->len = header[i].value.len; 1001 continue;
991 v->valid = 1; 1002 }
992 v->no_cacheable = 0; 1003
993 v->not_found = 0; 1004 len += header[i].value.len + 2;
994 v->data = header[i].value.data; 1005
995 1006 *ph = &header[i];
996 return NGX_OK; 1007 ph = &header[i].next;
997 } 1008 }
998 } 1009
999 1010 *ph = NULL;
1000 v->not_found = 1; 1011
1012 if (h == NULL) {
1013 v->not_found = 1;
1014 return NGX_OK;
1015 }
1016
1017 len -= 2;
1018
1019 if (h->next == NULL) {
1020
1021 v->len = h->value.len;
1022 v->valid = 1;
1023 v->no_cacheable = 0;
1024 v->not_found = 0;
1025 v->data = h->value.data;
1026
1027 return NGX_OK;
1028 }
1029
1030 p = ngx_pnalloc(r->pool, len);
1031 if (p == NULL) {
1032 return NGX_ERROR;
1033 }
1034
1035 v->len = len;
1036 v->valid = 1;
1037 v->no_cacheable = 0;
1038 v->not_found = 0;
1039 v->data = p;
1040
1041 for ( ;; ) {
1042
1043 p = ngx_copy(p, h->value.data, h->value.len);
1044
1045 if (h->next == NULL) {
1046 break;
1047 }
1048
1049 *p++ = ','; *p++ = ' ';
1050
1051 h = h->next;
1052 }
1001 1053
1002 return NGX_OK; 1054 return NGX_OK;
1003 } 1055 }
1004 1056
1005 1057
1877 return NGX_OK; 1929 return NGX_OK;
1878 } 1930 }
1879 1931
1880 ngx_str_set(&name, "sent_http_location"); 1932 ngx_str_set(&name, "sent_http_location");
1881 1933
1882 return ngx_http_variable_unknown_header(v, &name, 1934 return ngx_http_variable_unknown_header(r, v, &name,
1883 &r->headers_out.headers.part, 1935 &r->headers_out.headers.part,
1884 sizeof("sent_http_") - 1); 1936 sizeof("sent_http_") - 1);
1885 } 1937 }
1886 1938
1887 1939