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)