Mercurial > hg > nginx-quic
annotate src/stream/ngx_stream_split_clients_module.c @ 6963:3ff293cfdab8
Slice filter: prevented slice redirection (ticket #1219).
When a slice subrequest was redirected to a new location, its context was lost.
After its completion, a new slice subrequest for the same slice was created.
This could lead to infinite loop. Now the slice module makes sure each slice
subrequest starts output with the slice context available.
author | Roman Arutyunyan <arut@nginx.com> |
---|---|
date | Fri, 31 Mar 2017 21:47:56 +0300 |
parents | 787dcc15b802 |
children |
rev | line source |
---|---|
3513 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 4 * Copyright (C) Nginx, Inc. |
3513 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
10 #include <ngx_stream.h> |
3513 | 11 |
12 | |
13 typedef struct { | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
14 uint32_t percent; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
15 ngx_stream_variable_value_t value; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
16 } ngx_stream_split_clients_part_t; |
3513 | 17 |
18 | |
19 typedef struct { | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
20 ngx_stream_complex_value_t value; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
21 ngx_array_t parts; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
22 } ngx_stream_split_clients_ctx_t; |
3513 | 23 |
24 | |
25 static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, | |
26 void *conf); | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
27 static char *ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, |
3513 | 28 void *conf); |
29 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
30 static ngx_command_t ngx_stream_split_clients_commands[] = { |
3513 | 31 |
32 { ngx_string("split_clients"), | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
33 NGX_STREAM_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, |
3513 | 34 ngx_conf_split_clients_block, |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
35 NGX_STREAM_MAIN_CONF_OFFSET, |
3513 | 36 0, |
37 NULL }, | |
38 | |
39 ngx_null_command | |
40 }; | |
41 | |
42 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
43 static ngx_stream_module_t ngx_stream_split_clients_module_ctx = { |
3513 | 44 NULL, /* preconfiguration */ |
45 NULL, /* postconfiguration */ | |
46 | |
47 NULL, /* create main configuration */ | |
48 NULL, /* init main configuration */ | |
49 | |
50 NULL, /* create server configuration */ | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
51 NULL /* merge server configuration */ |
3513 | 52 }; |
53 | |
54 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
55 ngx_module_t ngx_stream_split_clients_module = { |
3513 | 56 NGX_MODULE_V1, |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
57 &ngx_stream_split_clients_module_ctx, /* module context */ |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
58 ngx_stream_split_clients_commands, /* module directives */ |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
59 NGX_STREAM_MODULE, /* module type */ |
3513 | 60 NULL, /* init master */ |
61 NULL, /* init module */ | |
62 NULL, /* init process */ | |
63 NULL, /* init thread */ | |
64 NULL, /* exit thread */ | |
65 NULL, /* exit process */ | |
66 NULL, /* exit master */ | |
67 NGX_MODULE_V1_PADDING | |
68 }; | |
69 | |
70 | |
71 static ngx_int_t | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
72 ngx_stream_split_clients_variable(ngx_stream_session_t *s, |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
73 ngx_stream_variable_value_t *v, uintptr_t data) |
3513 | 74 { |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
75 ngx_stream_split_clients_ctx_t *ctx = |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
76 (ngx_stream_split_clients_ctx_t *) data; |
3513 | 77 |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
78 uint32_t hash; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
79 ngx_str_t val; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
80 ngx_uint_t i; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
81 ngx_stream_split_clients_part_t *part; |
3513 | 82 |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
83 *v = ngx_stream_variable_null_value; |
3513 | 84 |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
85 if (ngx_stream_complex_value(s, &ctx->value, &val) != NGX_OK) { |
3513 | 86 return NGX_OK; |
87 } | |
88 | |
3892
12d8d2f30205
use MurmurHash2 for split_clients, because
Igor Sysoev <igor@sysoev.ru>
parents:
3607
diff
changeset
|
89 hash = ngx_murmur_hash2(val.data, val.len); |
3513 | 90 |
91 part = ctx->parts.elts; | |
92 | |
93 for (i = 0; i < ctx->parts.nelts; i++) { | |
94 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
95 ngx_log_debug2(NGX_LOG_DEBUG_STREAM, s->connection->log, 0, |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
96 "stream split: %uD %uD", hash, part[i].percent); |
3513 | 97 |
4561
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
98 if (hash < part[i].percent || part[i].percent == 0) { |
3513 | 99 *v = part[i].value; |
100 return NGX_OK; | |
101 } | |
102 } | |
103 | |
104 return NGX_OK; | |
105 } | |
106 | |
107 | |
108 static char * | |
109 ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
110 { | |
111 char *rv; | |
4561
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
112 uint32_t sum, last; |
3513 | 113 ngx_str_t *value, name; |
4561
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
114 ngx_uint_t i; |
3513 | 115 ngx_conf_t save; |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
116 ngx_stream_variable_t *var; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
117 ngx_stream_split_clients_ctx_t *ctx; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
118 ngx_stream_split_clients_part_t *part; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
119 ngx_stream_compile_complex_value_t ccv; |
3513 | 120 |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
121 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_stream_split_clients_ctx_t)); |
3513 | 122 if (ctx == NULL) { |
123 return NGX_CONF_ERROR; | |
124 } | |
125 | |
126 value = cf->args->elts; | |
127 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
128 ngx_memzero(&ccv, sizeof(ngx_stream_compile_complex_value_t)); |
3513 | 129 |
130 ccv.cf = cf; | |
131 ccv.value = &value[1]; | |
132 ccv.complex_value = &ctx->value; | |
133 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
134 if (ngx_stream_compile_complex_value(&ccv) != NGX_OK) { |
3513 | 135 return NGX_CONF_ERROR; |
136 } | |
137 | |
138 name = value[2]; | |
4635
9c9fbdbe9383
Added syntax checking of the second parameter of the "split_clients" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4593
diff
changeset
|
139 |
4972
8b635cf36ccc
Added checks that disallow adding a variable with an empty name.
Ruslan Ermilov <ru@nginx.com>
parents:
4635
diff
changeset
|
140 if (name.data[0] != '$') { |
4635
9c9fbdbe9383
Added syntax checking of the second parameter of the "split_clients" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4593
diff
changeset
|
141 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
9c9fbdbe9383
Added syntax checking of the second parameter of the "split_clients" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4593
diff
changeset
|
142 "invalid variable name \"%V\"", &name); |
9c9fbdbe9383
Added syntax checking of the second parameter of the "split_clients" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4593
diff
changeset
|
143 return NGX_CONF_ERROR; |
9c9fbdbe9383
Added syntax checking of the second parameter of the "split_clients" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4593
diff
changeset
|
144 } |
9c9fbdbe9383
Added syntax checking of the second parameter of the "split_clients" directive.
Ruslan Ermilov <ru@nginx.com>
parents:
4593
diff
changeset
|
145 |
3513 | 146 name.len--; |
147 name.data++; | |
148 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
149 var = ngx_stream_add_variable(cf, &name, NGX_STREAM_VAR_CHANGEABLE); |
3513 | 150 if (var == NULL) { |
151 return NGX_CONF_ERROR; | |
152 } | |
153 | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
154 var->get_handler = ngx_stream_split_clients_variable; |
3513 | 155 var->data = (uintptr_t) ctx; |
156 | |
157 if (ngx_array_init(&ctx->parts, cf->pool, 2, | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
158 sizeof(ngx_stream_split_clients_part_t)) |
3513 | 159 != NGX_OK) |
160 { | |
161 return NGX_CONF_ERROR; | |
162 } | |
163 | |
164 save = *cf; | |
165 cf->ctx = ctx; | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
166 cf->handler = ngx_stream_split_clients; |
3513 | 167 cf->handler_conf = conf; |
168 | |
169 rv = ngx_conf_parse(cf, NULL); | |
170 | |
171 *cf = save; | |
172 | |
3607
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
173 if (rv != NGX_CONF_OK) { |
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
174 return rv; |
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
175 } |
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
176 |
3513 | 177 sum = 0; |
178 last = 0; | |
179 part = ctx->parts.elts; | |
180 | |
181 for (i = 0; i < ctx->parts.nelts; i++) { | |
182 sum = part[i].percent ? sum + part[i].percent : 10000; | |
183 if (sum > 10000) { | |
4561
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
184 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
4593
834049edae24
Fixed grammar in error messages.
Ruslan Ermilov <ru@nginx.com>
parents:
4561
diff
changeset
|
185 "percent total is greater than 100%%"); |
4561
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
186 return NGX_CONF_ERROR; |
3513 | 187 } |
188 | |
189 if (part[i].percent) { | |
4561
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
190 last += part[i].percent * (uint64_t) 0xffffffff / 10000; |
ae63013cbffa
Fixed calculation of range boundaries.
Ruslan Ermilov <ru@nginx.com>
parents:
4412
diff
changeset
|
191 part[i].percent = last; |
3513 | 192 } |
193 } | |
194 | |
195 return rv; | |
196 } | |
197 | |
198 | |
199 static char * | |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
200 ngx_stream_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) |
3513 | 201 { |
6632
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
202 ngx_int_t n; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
203 ngx_str_t *value; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
204 ngx_stream_split_clients_ctx_t *ctx; |
787dcc15b802
Stream: split_clients module.
Vladimir Homutov <vl@nginx.com>
parents:
5128
diff
changeset
|
205 ngx_stream_split_clients_part_t *part; |
3513 | 206 |
207 ctx = cf->ctx; | |
208 value = cf->args->elts; | |
209 | |
210 part = ngx_array_push(&ctx->parts); | |
211 if (part == NULL) { | |
212 return NGX_CONF_ERROR; | |
213 } | |
214 | |
215 if (value[0].len == 1 && value[0].data[0] == '*') { | |
216 part->percent = 0; | |
217 | |
218 } else { | |
5128
b78cf2414fda
Split clients: check length when parsing configuration.
Ruslan Ermilov <ru@nginx.com>
parents:
4972
diff
changeset
|
219 if (value[0].len == 0 || value[0].data[value[0].len - 1] != '%') { |
3513 | 220 goto invalid; |
221 } | |
222 | |
223 n = ngx_atofp(value[0].data, value[0].len - 1, 2); | |
224 if (n == NGX_ERROR || n == 0) { | |
225 goto invalid; | |
226 } | |
227 | |
228 part->percent = (uint32_t) n; | |
229 } | |
230 | |
231 part->value.len = value[1].len; | |
232 part->value.valid = 1; | |
233 part->value.no_cacheable = 0; | |
234 part->value.not_found = 0; | |
235 part->value.data = value[1].data; | |
236 | |
237 return NGX_CONF_OK; | |
238 | |
239 invalid: | |
240 | |
241 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
242 "invalid percent value \"%V\"", &value[0]); | |
243 return NGX_CONF_ERROR; | |
244 } |