Mercurial > hg > nginx
comparison src/http/modules/ngx_http_proxy_module.c @ 7716:d6a5e14aa3e4
Proxy: added the "proxy_cookie_flags" directive.
author | Ruslan Ermilov <ru@nginx.com> |
---|---|
date | Sun, 27 Sep 2020 23:21:11 +0300 |
parents | 5c7917292b29 |
children | a88384c69d1e |
comparison
equal
deleted
inserted
replaced
7715:5c7917292b29 | 7716:d6a5e14aa3e4 |
---|---|
6 | 6 |
7 | 7 |
8 #include <ngx_config.h> | 8 #include <ngx_config.h> |
9 #include <ngx_core.h> | 9 #include <ngx_core.h> |
10 #include <ngx_http.h> | 10 #include <ngx_http.h> |
11 | |
12 | |
13 #define NGX_HTTP_PROXY_COOKIE_SECURE 0x0001 | |
14 #define NGX_HTTP_PROXY_COOKIE_SECURE_ON 0x0002 | |
15 #define NGX_HTTP_PROXY_COOKIE_SECURE_OFF 0x0004 | |
16 #define NGX_HTTP_PROXY_COOKIE_HTTPONLY 0x0008 | |
17 #define NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON 0x0010 | |
18 #define NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF 0x0020 | |
19 #define NGX_HTTP_PROXY_COOKIE_SAMESITE 0x0040 | |
20 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT 0x0080 | |
21 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX 0x0100 | |
22 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE 0x0200 | |
23 #define NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF 0x0400 | |
11 | 24 |
12 | 25 |
13 typedef struct { | 26 typedef struct { |
14 ngx_array_t caches; /* ngx_http_file_cache_t * */ | 27 ngx_array_t caches; /* ngx_http_file_cache_t * */ |
15 } ngx_http_proxy_main_conf_t; | 28 } ngx_http_proxy_main_conf_t; |
31 #endif | 44 #endif |
32 } pattern; | 45 } pattern; |
33 | 46 |
34 ngx_http_complex_value_t replacement; | 47 ngx_http_complex_value_t replacement; |
35 }; | 48 }; |
49 | |
50 | |
51 typedef struct { | |
52 union { | |
53 ngx_http_complex_value_t complex; | |
54 #if (NGX_PCRE) | |
55 ngx_http_regex_t *regex; | |
56 #endif | |
57 } cookie; | |
58 | |
59 ngx_uint_t flags; | |
60 ngx_uint_t regex; | |
61 } ngx_http_proxy_cookie_flags_t; | |
36 | 62 |
37 | 63 |
38 typedef struct { | 64 typedef struct { |
39 ngx_str_t key_start; | 65 ngx_str_t key_start; |
40 ngx_str_t schema; | 66 ngx_str_t schema; |
70 ngx_array_t *proxy_values; | 96 ngx_array_t *proxy_values; |
71 | 97 |
72 ngx_array_t *redirects; | 98 ngx_array_t *redirects; |
73 ngx_array_t *cookie_domains; | 99 ngx_array_t *cookie_domains; |
74 ngx_array_t *cookie_paths; | 100 ngx_array_t *cookie_paths; |
101 ngx_array_t *cookie_flags; | |
75 | 102 |
76 ngx_http_complex_value_t *method; | 103 ngx_http_complex_value_t *method; |
77 ngx_str_t location; | 104 ngx_str_t location; |
78 ngx_str_t url; | 105 ngx_str_t url; |
79 | 106 |
156 ngx_http_variable_value_t *v, uintptr_t data); | 183 ngx_http_variable_value_t *v, uintptr_t data); |
157 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, | 184 static ngx_int_t ngx_http_proxy_rewrite_redirect(ngx_http_request_t *r, |
158 ngx_table_elt_t *h, size_t prefix); | 185 ngx_table_elt_t *h, size_t prefix); |
159 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, | 186 static ngx_int_t ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, |
160 ngx_table_elt_t *h); | 187 ngx_table_elt_t *h); |
188 static ngx_int_t ngx_http_proxy_parse_cookie(ngx_str_t *value, | |
189 ngx_array_t *attrs); | |
161 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, | 190 static ngx_int_t ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, |
162 ngx_table_elt_t *h, u_char *value, ngx_array_t *rewrites); | 191 ngx_str_t *value, ngx_array_t *rewrites); |
192 static ngx_int_t ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, | |
193 ngx_array_t *attrs, ngx_array_t *flags); | |
194 static ngx_int_t ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, | |
195 ngx_array_t *attrs, ngx_uint_t flags); | |
163 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r, | 196 static ngx_int_t ngx_http_proxy_rewrite(ngx_http_request_t *r, |
164 ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement); | 197 ngx_str_t *value, size_t prefix, size_t len, ngx_str_t *replacement); |
165 | 198 |
166 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); | 199 static ngx_int_t ngx_http_proxy_add_variables(ngx_conf_t *cf); |
167 static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf); | 200 static void *ngx_http_proxy_create_main_conf(ngx_conf_t *cf); |
177 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, | 210 static char *ngx_http_proxy_redirect(ngx_conf_t *cf, ngx_command_t *cmd, |
178 void *conf); | 211 void *conf); |
179 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, | 212 static char *ngx_http_proxy_cookie_domain(ngx_conf_t *cf, ngx_command_t *cmd, |
180 void *conf); | 213 void *conf); |
181 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, | 214 static char *ngx_http_proxy_cookie_path(ngx_conf_t *cf, ngx_command_t *cmd, |
215 void *conf); | |
216 static char *ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, | |
182 void *conf); | 217 void *conf); |
183 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, | 218 static char *ngx_http_proxy_store(ngx_conf_t *cf, ngx_command_t *cmd, |
184 void *conf); | 219 void *conf); |
185 #if (NGX_HTTP_CACHE) | 220 #if (NGX_HTTP_CACHE) |
186 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, | 221 static char *ngx_http_proxy_cache(ngx_conf_t *cf, ngx_command_t *cmd, |
276 NULL }, | 311 NULL }, |
277 | 312 |
278 { ngx_string("proxy_cookie_path"), | 313 { ngx_string("proxy_cookie_path"), |
279 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, | 314 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE12, |
280 ngx_http_proxy_cookie_path, | 315 ngx_http_proxy_cookie_path, |
316 NGX_HTTP_LOC_CONF_OFFSET, | |
317 0, | |
318 NULL }, | |
319 | |
320 { ngx_string("proxy_cookie_flags"), | |
321 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1234, | |
322 ngx_http_proxy_cookie_flags, | |
281 NGX_HTTP_LOC_CONF_OFFSET, | 323 NGX_HTTP_LOC_CONF_OFFSET, |
282 0, | 324 0, |
283 NULL }, | 325 NULL }, |
284 | 326 |
285 { ngx_string("proxy_store"), | 327 { ngx_string("proxy_store"), |
843 static ngx_path_init_t ngx_http_proxy_temp_path = { | 885 static ngx_path_init_t ngx_http_proxy_temp_path = { |
844 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 } | 886 ngx_string(NGX_HTTP_PROXY_TEMP_PATH), { 1, 2, 0 } |
845 }; | 887 }; |
846 | 888 |
847 | 889 |
890 static ngx_conf_bitmask_t ngx_http_proxy_cookie_flags_masks[] = { | |
891 | |
892 { ngx_string("secure"), | |
893 NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_ON }, | |
894 | |
895 { ngx_string("nosecure"), | |
896 NGX_HTTP_PROXY_COOKIE_SECURE|NGX_HTTP_PROXY_COOKIE_SECURE_OFF }, | |
897 | |
898 { ngx_string("httponly"), | |
899 NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON }, | |
900 | |
901 { ngx_string("nohttponly"), | |
902 NGX_HTTP_PROXY_COOKIE_HTTPONLY|NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF }, | |
903 | |
904 { ngx_string("samesite=strict"), | |
905 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT }, | |
906 | |
907 { ngx_string("samesite=lax"), | |
908 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX }, | |
909 | |
910 { ngx_string("samesite=none"), | |
911 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE }, | |
912 | |
913 { ngx_string("nosamesite"), | |
914 NGX_HTTP_PROXY_COOKIE_SAMESITE|NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF }, | |
915 | |
916 { ngx_null_string, 0 } | |
917 }; | |
918 | |
919 | |
848 static ngx_int_t | 920 static ngx_int_t |
849 ngx_http_proxy_handler(ngx_http_request_t *r) | 921 ngx_http_proxy_handler(ngx_http_request_t *r) |
850 { | 922 { |
851 ngx_int_t rc; | 923 ngx_int_t rc; |
852 ngx_http_upstream_t *u; | 924 ngx_http_upstream_t *u; |
904 | 976 |
905 if (plcf->redirects) { | 977 if (plcf->redirects) { |
906 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; | 978 u->rewrite_redirect = ngx_http_proxy_rewrite_redirect; |
907 } | 979 } |
908 | 980 |
909 if (plcf->cookie_domains || plcf->cookie_paths) { | 981 if (plcf->cookie_domains || plcf->cookie_paths || plcf->cookie_flags) { |
910 u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; | 982 u->rewrite_cookie = ngx_http_proxy_rewrite_cookie; |
911 } | 983 } |
912 | 984 |
913 u->buffering = plcf->upstream.buffering; | 985 u->buffering = plcf->upstream.buffering; |
914 | 986 |
2596 | 2668 |
2597 | 2669 |
2598 static ngx_int_t | 2670 static ngx_int_t |
2599 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) | 2671 ngx_http_proxy_rewrite_cookie(ngx_http_request_t *r, ngx_table_elt_t *h) |
2600 { | 2672 { |
2601 size_t prefix; | |
2602 u_char *p; | 2673 u_char *p; |
2674 size_t len; | |
2603 ngx_int_t rc, rv; | 2675 ngx_int_t rc, rv; |
2676 ngx_str_t *key, *value; | |
2677 ngx_uint_t i; | |
2678 ngx_array_t attrs; | |
2679 ngx_keyval_t *attr; | |
2604 ngx_http_proxy_loc_conf_t *plcf; | 2680 ngx_http_proxy_loc_conf_t *plcf; |
2605 | 2681 |
2606 p = (u_char *) ngx_strchr(h->value.data, ';'); | 2682 ngx_array_init(&attrs, r->pool, 2, sizeof(ngx_keyval_t)); |
2607 if (p == NULL) { | 2683 |
2684 if (ngx_http_proxy_parse_cookie(&h->value, &attrs) != NGX_OK) { | |
2685 return NGX_ERROR; | |
2686 } | |
2687 | |
2688 attr = attrs.elts; | |
2689 | |
2690 if (attr[0].value.data == NULL) { | |
2608 return NGX_DECLINED; | 2691 return NGX_DECLINED; |
2609 } | 2692 } |
2610 | 2693 |
2611 prefix = p + 1 - h->value.data; | |
2612 | |
2613 rv = NGX_DECLINED; | 2694 rv = NGX_DECLINED; |
2614 | 2695 |
2615 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); | 2696 plcf = ngx_http_get_module_loc_conf(r, ngx_http_proxy_module); |
2616 | 2697 |
2617 if (plcf->cookie_domains) { | 2698 for (i = 1; i < attrs.nelts; i++) { |
2618 p = ngx_strcasestrn(h->value.data + prefix, "domain=", 7 - 1); | 2699 |
2619 | 2700 key = &attr[i].key; |
2620 if (p) { | 2701 value = &attr[i].value; |
2621 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 7, | 2702 |
2703 if (plcf->cookie_domains && key->len == 6 | |
2704 && ngx_strncasecmp(key->data, (u_char *) "domain", 6) == 0 | |
2705 && value->data) | |
2706 { | |
2707 rc = ngx_http_proxy_rewrite_cookie_value(r, value, | |
2622 plcf->cookie_domains); | 2708 plcf->cookie_domains); |
2623 if (rc == NGX_ERROR) { | 2709 if (rc == NGX_ERROR) { |
2624 return NGX_ERROR; | 2710 return NGX_ERROR; |
2625 } | 2711 } |
2626 | 2712 |
2627 if (rc != NGX_DECLINED) { | 2713 if (rc != NGX_DECLINED) { |
2628 rv = rc; | 2714 rv = rc; |
2629 } | 2715 } |
2630 } | 2716 } |
2631 } | 2717 |
2632 | 2718 if (plcf->cookie_paths && key->len == 4 |
2633 if (plcf->cookie_paths) { | 2719 && ngx_strncasecmp(key->data, (u_char *) "path", 4) == 0 |
2634 p = ngx_strcasestrn(h->value.data + prefix, "path=", 5 - 1); | 2720 && value->data) |
2635 | 2721 { |
2636 if (p) { | 2722 rc = ngx_http_proxy_rewrite_cookie_value(r, value, |
2637 rc = ngx_http_proxy_rewrite_cookie_value(r, h, p + 5, | |
2638 plcf->cookie_paths); | 2723 plcf->cookie_paths); |
2639 if (rc == NGX_ERROR) { | 2724 if (rc == NGX_ERROR) { |
2640 return NGX_ERROR; | 2725 return NGX_ERROR; |
2641 } | 2726 } |
2642 | 2727 |
2644 rv = rc; | 2729 rv = rc; |
2645 } | 2730 } |
2646 } | 2731 } |
2647 } | 2732 } |
2648 | 2733 |
2649 return rv; | 2734 if (plcf->cookie_flags) { |
2735 rc = ngx_http_proxy_rewrite_cookie_flags(r, &attrs, | |
2736 plcf->cookie_flags); | |
2737 if (rc == NGX_ERROR) { | |
2738 return NGX_ERROR; | |
2739 } | |
2740 | |
2741 if (rc != NGX_DECLINED) { | |
2742 rv = rc; | |
2743 } | |
2744 | |
2745 attr = attrs.elts; | |
2746 } | |
2747 | |
2748 if (rv != NGX_OK) { | |
2749 return rv; | |
2750 } | |
2751 | |
2752 len = 0; | |
2753 | |
2754 for (i = 0; i < attrs.nelts; i++) { | |
2755 | |
2756 if (attr[i].key.data == NULL) { | |
2757 continue; | |
2758 } | |
2759 | |
2760 if (i > 0) { | |
2761 len += 2; | |
2762 } | |
2763 | |
2764 len += attr[i].key.len; | |
2765 | |
2766 if (attr[i].value.data) { | |
2767 len += 1 + attr[i].value.len; | |
2768 } | |
2769 } | |
2770 | |
2771 p = ngx_pnalloc(r->pool, len + 1); | |
2772 if (p == NULL) { | |
2773 return NGX_ERROR; | |
2774 } | |
2775 | |
2776 h->value.data = p; | |
2777 h->value.len = len; | |
2778 | |
2779 for (i = 0; i < attrs.nelts; i++) { | |
2780 | |
2781 if (attr[i].key.data == NULL) { | |
2782 continue; | |
2783 } | |
2784 | |
2785 if (i > 0) { | |
2786 *p++ = ';'; | |
2787 *p++ = ' '; | |
2788 } | |
2789 | |
2790 p = ngx_cpymem(p, attr[i].key.data, attr[i].key.len); | |
2791 | |
2792 if (attr[i].value.data) { | |
2793 *p++ = '='; | |
2794 p = ngx_cpymem(p, attr[i].value.data, attr[i].value.len); | |
2795 } | |
2796 } | |
2797 | |
2798 *p = '\0'; | |
2799 | |
2800 return NGX_OK; | |
2650 } | 2801 } |
2651 | 2802 |
2652 | 2803 |
2653 static ngx_int_t | 2804 static ngx_int_t |
2654 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_table_elt_t *h, | 2805 ngx_http_proxy_parse_cookie(ngx_str_t *value, ngx_array_t *attrs) |
2655 u_char *value, ngx_array_t *rewrites) | |
2656 { | 2806 { |
2657 size_t len, prefix; | 2807 u_char *start, *end, *p, *last; |
2658 u_char *p; | 2808 ngx_str_t name, val; |
2809 ngx_keyval_t *attr; | |
2810 | |
2811 start = value->data; | |
2812 end = value->data + value->len; | |
2813 | |
2814 for ( ;; ) { | |
2815 | |
2816 last = (u_char *) ngx_strchr(start, ';'); | |
2817 | |
2818 if (last == NULL) { | |
2819 last = end; | |
2820 } | |
2821 | |
2822 while (start < last && *start == ' ') { start++; } | |
2823 | |
2824 for (p = start; p < last && *p != '='; p++) { /* void */ } | |
2825 | |
2826 name.data = start; | |
2827 name.len = p - start; | |
2828 | |
2829 while (name.len && name.data[name.len - 1] == ' ') { | |
2830 name.len--; | |
2831 } | |
2832 | |
2833 if (p < last) { | |
2834 | |
2835 p++; | |
2836 | |
2837 while (p < last && *p == ' ') { p++; } | |
2838 | |
2839 val.data = p; | |
2840 val.len = last - val.data; | |
2841 | |
2842 while (val.len && val.data[val.len - 1] == ' ') { | |
2843 val.len--; | |
2844 } | |
2845 | |
2846 } else { | |
2847 ngx_str_null(&val); | |
2848 } | |
2849 | |
2850 attr = ngx_array_push(attrs); | |
2851 if (attr == NULL) { | |
2852 return NGX_ERROR; | |
2853 } | |
2854 | |
2855 attr->key = name; | |
2856 attr->value = val; | |
2857 | |
2858 if (last == end) { | |
2859 break; | |
2860 } | |
2861 | |
2862 start = last + 1; | |
2863 } | |
2864 | |
2865 return NGX_OK; | |
2866 } | |
2867 | |
2868 | |
2869 static ngx_int_t | |
2870 ngx_http_proxy_rewrite_cookie_value(ngx_http_request_t *r, ngx_str_t *value, | |
2871 ngx_array_t *rewrites) | |
2872 { | |
2659 ngx_int_t rc; | 2873 ngx_int_t rc; |
2660 ngx_uint_t i; | 2874 ngx_uint_t i; |
2661 ngx_http_proxy_rewrite_t *pr; | 2875 ngx_http_proxy_rewrite_t *pr; |
2662 | 2876 |
2663 prefix = value - h->value.data; | |
2664 | |
2665 p = (u_char *) ngx_strchr(value, ';'); | |
2666 | |
2667 len = p ? (size_t) (p - value) : (h->value.len - prefix); | |
2668 | |
2669 pr = rewrites->elts; | 2877 pr = rewrites->elts; |
2670 | 2878 |
2671 for (i = 0; i < rewrites->nelts; i++) { | 2879 for (i = 0; i < rewrites->nelts; i++) { |
2672 rc = pr[i].handler(r, &h->value, prefix, len, &pr[i]); | 2880 rc = pr[i].handler(r, value, 0, value->len, &pr[i]); |
2673 | 2881 |
2674 if (rc != NGX_DECLINED) { | 2882 if (rc != NGX_DECLINED) { |
2675 return rc; | 2883 return rc; |
2676 } | 2884 } |
2677 } | 2885 } |
2678 | 2886 |
2679 return NGX_DECLINED; | 2887 return NGX_DECLINED; |
2888 } | |
2889 | |
2890 | |
2891 static ngx_int_t | |
2892 ngx_http_proxy_rewrite_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, | |
2893 ngx_array_t *flags) | |
2894 { | |
2895 ngx_str_t pattern; | |
2896 #if (NGX_PCRE) | |
2897 ngx_int_t rc; | |
2898 #endif | |
2899 ngx_uint_t i; | |
2900 ngx_keyval_t *attr; | |
2901 ngx_http_proxy_cookie_flags_t *pcf; | |
2902 | |
2903 attr = attrs->elts; | |
2904 pcf = flags->elts; | |
2905 | |
2906 for (i = 0; i < flags->nelts; i++) { | |
2907 | |
2908 #if (NGX_PCRE) | |
2909 if (pcf[i].regex) { | |
2910 rc = ngx_http_regex_exec(r, pcf[i].cookie.regex, &attr[0].key); | |
2911 | |
2912 if (rc == NGX_ERROR) { | |
2913 return NGX_ERROR; | |
2914 } | |
2915 | |
2916 if (rc == NGX_OK) { | |
2917 break; | |
2918 } | |
2919 | |
2920 /* NGX_DECLINED */ | |
2921 | |
2922 continue; | |
2923 } | |
2924 #endif | |
2925 | |
2926 if (ngx_http_complex_value(r, &pcf[i].cookie.complex, &pattern) | |
2927 != NGX_OK) | |
2928 { | |
2929 return NGX_ERROR; | |
2930 } | |
2931 | |
2932 if (pattern.len == attr[0].key.len | |
2933 && ngx_strncasecmp(attr[0].key.data, pattern.data, pattern.len) | |
2934 == 0) | |
2935 { | |
2936 break; | |
2937 } | |
2938 } | |
2939 | |
2940 if (i == flags->nelts) { | |
2941 return NGX_DECLINED; | |
2942 } | |
2943 | |
2944 return ngx_http_proxy_edit_cookie_flags(r, attrs, pcf[i].flags); | |
2945 } | |
2946 | |
2947 | |
2948 static ngx_int_t | |
2949 ngx_http_proxy_edit_cookie_flags(ngx_http_request_t *r, ngx_array_t *attrs, | |
2950 ngx_uint_t flags) | |
2951 { | |
2952 ngx_str_t *key, *value; | |
2953 ngx_uint_t i; | |
2954 ngx_keyval_t *attr; | |
2955 | |
2956 attr = attrs->elts; | |
2957 | |
2958 for (i = 1; i < attrs->nelts; i++) { | |
2959 key = &attr[i].key; | |
2960 | |
2961 if (key->len == 6 | |
2962 && ngx_strncasecmp(key->data, (u_char *) "secure", 6) == 0) | |
2963 { | |
2964 if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) { | |
2965 flags &= ~NGX_HTTP_PROXY_COOKIE_SECURE_ON; | |
2966 | |
2967 } else if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_OFF) { | |
2968 key->data = NULL; | |
2969 } | |
2970 | |
2971 continue; | |
2972 } | |
2973 | |
2974 if (key->len == 8 | |
2975 && ngx_strncasecmp(key->data, (u_char *) "httponly", 8) == 0) | |
2976 { | |
2977 if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) { | |
2978 flags &= ~NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON; | |
2979 | |
2980 } else if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_OFF) { | |
2981 key->data = NULL; | |
2982 } | |
2983 | |
2984 continue; | |
2985 } | |
2986 | |
2987 if (key->len == 8 | |
2988 && ngx_strncasecmp(key->data, (u_char *) "samesite", 8) == 0) | |
2989 { | |
2990 value = &attr[i].value; | |
2991 | |
2992 if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) { | |
2993 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT; | |
2994 | |
2995 if (value->len != 6 | |
2996 || ngx_strncasecmp(value->data, (u_char *) "strict", 6) | |
2997 != 0) | |
2998 { | |
2999 ngx_str_set(key, "SameSite"); | |
3000 ngx_str_set(value, "Strict"); | |
3001 } | |
3002 | |
3003 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) { | |
3004 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX; | |
3005 | |
3006 if (value->len != 3 | |
3007 || ngx_strncasecmp(value->data, (u_char *) "lax", 3) != 0) | |
3008 { | |
3009 ngx_str_set(key, "SameSite"); | |
3010 ngx_str_set(value, "Lax"); | |
3011 } | |
3012 | |
3013 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE) { | |
3014 flags &= ~NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE; | |
3015 | |
3016 if (value->len != 4 | |
3017 || ngx_strncasecmp(value->data, (u_char *) "none", 4) != 0) | |
3018 { | |
3019 ngx_str_set(key, "SameSite"); | |
3020 ngx_str_set(value, "None"); | |
3021 } | |
3022 | |
3023 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_OFF) { | |
3024 key->data = NULL; | |
3025 } | |
3026 | |
3027 continue; | |
3028 } | |
3029 } | |
3030 | |
3031 if (flags & NGX_HTTP_PROXY_COOKIE_SECURE_ON) { | |
3032 attr = ngx_array_push(attrs); | |
3033 if (attr == NULL) { | |
3034 return NGX_ERROR; | |
3035 } | |
3036 | |
3037 ngx_str_set(&attr->key, "Secure"); | |
3038 ngx_str_null(&attr->value); | |
3039 } | |
3040 | |
3041 if (flags & NGX_HTTP_PROXY_COOKIE_HTTPONLY_ON) { | |
3042 attr = ngx_array_push(attrs); | |
3043 if (attr == NULL) { | |
3044 return NGX_ERROR; | |
3045 } | |
3046 | |
3047 ngx_str_set(&attr->key, "HttpOnly"); | |
3048 ngx_str_null(&attr->value); | |
3049 } | |
3050 | |
3051 if (flags & (NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT | |
3052 |NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX | |
3053 |NGX_HTTP_PROXY_COOKIE_SAMESITE_NONE)) | |
3054 { | |
3055 attr = ngx_array_push(attrs); | |
3056 if (attr == NULL) { | |
3057 return NGX_ERROR; | |
3058 } | |
3059 | |
3060 ngx_str_set(&attr->key, "SameSite"); | |
3061 | |
3062 if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_STRICT) { | |
3063 ngx_str_set(&attr->value, "Strict"); | |
3064 | |
3065 } else if (flags & NGX_HTTP_PROXY_COOKIE_SAMESITE_LAX) { | |
3066 ngx_str_set(&attr->value, "Lax"); | |
3067 | |
3068 } else { | |
3069 ngx_str_set(&attr->value, "None"); | |
3070 } | |
3071 } | |
3072 | |
3073 return NGX_OK; | |
2680 } | 3074 } |
2681 | 3075 |
2682 | 3076 |
2683 static ngx_int_t | 3077 static ngx_int_t |
2684 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, ngx_str_t *value, | 3078 ngx_http_proxy_rewrite_complex_handler(ngx_http_request_t *r, ngx_str_t *value, |
2740 return NGX_ERROR; | 3134 return NGX_ERROR; |
2741 } | 3135 } |
2742 | 3136 |
2743 p = value->data + prefix; | 3137 p = value->data + prefix; |
2744 | 3138 |
2745 if (p[0] == '.') { | 3139 if (len && p[0] == '.') { |
2746 p++; | 3140 p++; |
2747 prefix++; | 3141 prefix++; |
2748 len--; | 3142 len--; |
2749 } | 3143 } |
2750 | 3144 |
2953 conf->redirect = NGX_CONF_UNSET; | 3347 conf->redirect = NGX_CONF_UNSET; |
2954 conf->upstream.change_buffering = 1; | 3348 conf->upstream.change_buffering = 1; |
2955 | 3349 |
2956 conf->cookie_domains = NGX_CONF_UNSET_PTR; | 3350 conf->cookie_domains = NGX_CONF_UNSET_PTR; |
2957 conf->cookie_paths = NGX_CONF_UNSET_PTR; | 3351 conf->cookie_paths = NGX_CONF_UNSET_PTR; |
3352 conf->cookie_flags = NGX_CONF_UNSET_PTR; | |
2958 | 3353 |
2959 conf->http_version = NGX_CONF_UNSET_UINT; | 3354 conf->http_version = NGX_CONF_UNSET_UINT; |
2960 | 3355 |
2961 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; | 3356 conf->headers_hash_max_size = NGX_CONF_UNSET_UINT; |
2962 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT; | 3357 conf->headers_hash_bucket_size = NGX_CONF_UNSET_UINT; |
3347 } | 3742 } |
3348 | 3743 |
3349 ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL); | 3744 ngx_conf_merge_ptr_value(conf->cookie_domains, prev->cookie_domains, NULL); |
3350 | 3745 |
3351 ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL); | 3746 ngx_conf_merge_ptr_value(conf->cookie_paths, prev->cookie_paths, NULL); |
3747 | |
3748 ngx_conf_merge_ptr_value(conf->cookie_flags, prev->cookie_flags, NULL); | |
3352 | 3749 |
3353 ngx_conf_merge_uint_value(conf->http_version, prev->http_version, | 3750 ngx_conf_merge_uint_value(conf->http_version, prev->http_version, |
3354 NGX_HTTP_VERSION_10); | 3751 NGX_HTTP_VERSION_10); |
3355 | 3752 |
3356 ngx_conf_merge_uint_value(conf->headers_hash_max_size, | 3753 ngx_conf_merge_uint_value(conf->headers_hash_max_size, |
4079 | 4476 |
4080 return NGX_CONF_OK; | 4477 return NGX_CONF_OK; |
4081 } | 4478 } |
4082 | 4479 |
4083 | 4480 |
4481 static char * | |
4482 ngx_http_proxy_cookie_flags(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
4483 { | |
4484 ngx_http_proxy_loc_conf_t *plcf = conf; | |
4485 | |
4486 ngx_str_t *value; | |
4487 ngx_uint_t i, m; | |
4488 ngx_conf_bitmask_t *mask; | |
4489 ngx_http_proxy_cookie_flags_t *pcf; | |
4490 ngx_http_compile_complex_value_t ccv; | |
4491 #if (NGX_PCRE) | |
4492 ngx_regex_compile_t rc; | |
4493 u_char errstr[NGX_MAX_CONF_ERRSTR]; | |
4494 #endif | |
4495 | |
4496 if (plcf->cookie_flags == NULL) { | |
4497 return "is duplicate"; | |
4498 } | |
4499 | |
4500 value = cf->args->elts; | |
4501 | |
4502 if (cf->args->nelts == 2) { | |
4503 | |
4504 if (ngx_strcmp(value[1].data, "off") == 0) { | |
4505 | |
4506 if (plcf->cookie_flags != NGX_CONF_UNSET_PTR) { | |
4507 return "is duplicate"; | |
4508 } | |
4509 | |
4510 plcf->cookie_flags = NULL; | |
4511 return NGX_CONF_OK; | |
4512 } | |
4513 | |
4514 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4515 "invalid parameter \"%V\"", &value[1]); | |
4516 return NGX_CONF_ERROR; | |
4517 } | |
4518 | |
4519 if (plcf->cookie_flags == NGX_CONF_UNSET_PTR) { | |
4520 plcf->cookie_flags = ngx_array_create(cf->pool, 1, | |
4521 sizeof(ngx_http_proxy_cookie_flags_t)); | |
4522 if (plcf->cookie_flags == NULL) { | |
4523 return NGX_CONF_ERROR; | |
4524 } | |
4525 } | |
4526 | |
4527 pcf = ngx_array_push(plcf->cookie_flags); | |
4528 if (pcf == NULL) { | |
4529 return NGX_CONF_ERROR; | |
4530 } | |
4531 | |
4532 pcf->regex = 0; | |
4533 | |
4534 if (value[1].data[0] == '~') { | |
4535 value[1].len--; | |
4536 value[1].data++; | |
4537 | |
4538 #if (NGX_PCRE) | |
4539 ngx_memzero(&rc, sizeof(ngx_regex_compile_t)); | |
4540 | |
4541 rc.pattern = value[1]; | |
4542 rc.err.len = NGX_MAX_CONF_ERRSTR; | |
4543 rc.err.data = errstr; | |
4544 rc.options = NGX_REGEX_CASELESS; | |
4545 | |
4546 pcf->cookie.regex = ngx_http_regex_compile(cf, &rc); | |
4547 if (pcf->cookie.regex == NULL) { | |
4548 return NGX_CONF_ERROR; | |
4549 } | |
4550 | |
4551 pcf->regex = 1; | |
4552 #else | |
4553 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4554 "using regex \"%V\" requires PCRE library", | |
4555 &value[1]); | |
4556 return NGX_CONF_ERROR; | |
4557 #endif | |
4558 | |
4559 } else { | |
4560 | |
4561 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); | |
4562 | |
4563 ccv.cf = cf; | |
4564 ccv.value = &value[1]; | |
4565 ccv.complex_value = &pcf->cookie.complex; | |
4566 | |
4567 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { | |
4568 return NGX_CONF_ERROR; | |
4569 } | |
4570 } | |
4571 | |
4572 mask = ngx_http_proxy_cookie_flags_masks; | |
4573 pcf->flags = 0; | |
4574 | |
4575 for (i = 2; i < cf->args->nelts; i++) { | |
4576 for (m = 0; mask[m].name.len != 0; m++) { | |
4577 | |
4578 if (mask[m].name.len != value[i].len | |
4579 || ngx_strcasecmp(mask[m].name.data, value[i].data) != 0) | |
4580 { | |
4581 continue; | |
4582 } | |
4583 | |
4584 if (pcf->flags & mask[m].mask) { | |
4585 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4586 "duplicate parameter \"%V\"", &value[i]); | |
4587 return NGX_CONF_ERROR; | |
4588 } | |
4589 | |
4590 pcf->flags |= mask[m].mask; | |
4591 | |
4592 break; | |
4593 } | |
4594 | |
4595 if (mask[m].name.len == 0) { | |
4596 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4597 "invalid parameter \"%V\"", &value[i]); | |
4598 return NGX_CONF_ERROR; | |
4599 } | |
4600 } | |
4601 | |
4602 return NGX_CONF_OK; | |
4603 } | |
4604 | |
4605 | |
4084 static ngx_int_t | 4606 static ngx_int_t |
4085 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, | 4607 ngx_http_proxy_rewrite_regex(ngx_conf_t *cf, ngx_http_proxy_rewrite_t *pr, |
4086 ngx_str_t *regex, ngx_uint_t caseless) | 4608 ngx_str_t *regex, ngx_uint_t caseless) |
4087 { | 4609 { |
4088 #if (NGX_PCRE) | 4610 #if (NGX_PCRE) |