3 * Copyright (C) Igor Sysoev
4 * Copyright (C) Nginx, Inc.
8 #include <ngx_config.h>
15 ngx_http_variable_value_t value
;
16 } ngx_http_split_clients_part_t
;
20 ngx_http_complex_value_t value
;
22 } ngx_http_split_clients_ctx_t
;
25 static char *ngx_conf_split_clients_block(ngx_conf_t
*cf
, ngx_command_t
*cmd
,
27 static char *ngx_http_split_clients(ngx_conf_t
*cf
, ngx_command_t
*dummy
,
30 static ngx_command_t ngx_http_split_clients_commands
[] = {
32 { ngx_string("split_clients"),
33 NGX_HTTP_MAIN_CONF
|NGX_CONF_BLOCK
|NGX_CONF_TAKE2
,
34 ngx_conf_split_clients_block
,
35 NGX_HTTP_MAIN_CONF_OFFSET
,
43 static ngx_http_module_t ngx_http_split_clients_module_ctx
= {
44 NULL
, /* preconfiguration */
45 NULL
, /* postconfiguration */
47 NULL
, /* create main configuration */
48 NULL
, /* init main configuration */
50 NULL
, /* create server configuration */
51 NULL
, /* merge server configuration */
53 NULL
, /* create location configuration */
54 NULL
/* merge location configuration */
58 ngx_module_t ngx_http_split_clients_module
= {
60 &ngx_http_split_clients_module_ctx
, /* module context */
61 ngx_http_split_clients_commands
, /* module directives */
62 NGX_HTTP_MODULE
, /* module type */
63 NULL
, /* init master */
64 NULL
, /* init module */
65 NULL
, /* init process */
66 NULL
, /* init thread */
67 NULL
, /* exit thread */
68 NULL
, /* exit process */
69 NULL
, /* exit master */
75 ngx_http_split_clients_variable(ngx_http_request_t
*r
,
76 ngx_http_variable_value_t
*v
, uintptr_t data
)
78 ngx_http_split_clients_ctx_t
*ctx
= (ngx_http_split_clients_ctx_t
*) data
;
83 ngx_http_split_clients_part_t
*part
;
85 *v
= ngx_http_variable_null_value
;
87 if (ngx_http_complex_value(r
, &ctx
->value
, &val
) != NGX_OK
) {
91 hash
= ngx_murmur_hash2(val
.data
, val
.len
);
93 part
= ctx
->parts
.elts
;
95 for (i
= 0; i
< ctx
->parts
.nelts
; i
++) {
97 ngx_log_debug2(NGX_LOG_DEBUG_HTTP
, r
->connection
->log
, 0,
98 "http split: %uD %uD", hash
, part
[i
].percent
);
100 if (hash
< part
[i
].percent
|| part
[i
].percent
== 0) {
111 ngx_conf_split_clients_block(ngx_conf_t
*cf
, ngx_command_t
*cmd
, void *conf
)
115 ngx_str_t
*value
, name
;
118 ngx_http_variable_t
*var
;
119 ngx_http_split_clients_ctx_t
*ctx
;
120 ngx_http_split_clients_part_t
*part
;
121 ngx_http_compile_complex_value_t ccv
;
123 ctx
= ngx_pcalloc(cf
->pool
, sizeof(ngx_http_split_clients_ctx_t
));
125 return NGX_CONF_ERROR
;
128 value
= cf
->args
->elts
;
130 ngx_memzero(&ccv
, sizeof(ngx_http_compile_complex_value_t
));
133 ccv
.value
= &value
[1];
134 ccv
.complex_value
= &ctx
->value
;
136 if (ngx_http_compile_complex_value(&ccv
) != NGX_OK
) {
137 return NGX_CONF_ERROR
;
142 if (name
.data
[0] != '$') {
143 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
144 "invalid variable name \"%V\"", &name
);
145 return NGX_CONF_ERROR
;
151 var
= ngx_http_add_variable(cf
, &name
, NGX_HTTP_VAR_CHANGEABLE
);
153 return NGX_CONF_ERROR
;
156 var
->get_handler
= ngx_http_split_clients_variable
;
157 var
->data
= (uintptr_t) ctx
;
159 if (ngx_array_init(&ctx
->parts
, cf
->pool
, 2,
160 sizeof(ngx_http_split_clients_part_t
))
163 return NGX_CONF_ERROR
;
168 cf
->handler
= ngx_http_split_clients
;
169 cf
->handler_conf
= conf
;
171 rv
= ngx_conf_parse(cf
, NULL
);
175 if (rv
!= NGX_CONF_OK
) {
181 part
= ctx
->parts
.elts
;
183 for (i
= 0; i
< ctx
->parts
.nelts
; i
++) {
184 sum
= part
[i
].percent
? sum
+ part
[i
].percent
: 10000;
186 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
187 "percent total is greater than 100%%");
188 return NGX_CONF_ERROR
;
191 if (part
[i
].percent
) {
192 last
+= part
[i
].percent
* (uint64_t) 0xffffffff / 10000;
193 part
[i
].percent
= last
;
202 ngx_http_split_clients(ngx_conf_t
*cf
, ngx_command_t
*dummy
, void *conf
)
206 ngx_http_split_clients_ctx_t
*ctx
;
207 ngx_http_split_clients_part_t
*part
;
210 value
= cf
->args
->elts
;
212 part
= ngx_array_push(&ctx
->parts
);
214 return NGX_CONF_ERROR
;
217 if (value
[0].len
== 1 && value
[0].data
[0] == '*') {
221 if (value
[0].len
== 0 || value
[0].data
[value
[0].len
- 1] != '%') {
225 n
= ngx_atofp(value
[0].data
, value
[0].len
- 1, 2);
226 if (n
== NGX_ERROR
|| n
== 0) {
230 part
->percent
= (uint32_t) n
;
233 part
->value
.len
= value
[1].len
;
234 part
->value
.valid
= 1;
235 part
->value
.no_cacheable
= 0;
236 part
->value
.not_found
= 0;
237 part
->value
.data
= value
[1].data
;
243 ngx_conf_log_error(NGX_LOG_EMERG
, cf
, 0,
244 "invalid percent value \"%V\"", &value
[0]);
245 return NGX_CONF_ERROR
;