Klaus Demo nginx / fadd4bd
ngx_http_split_clients_module Igor Sysoev 12 years ago
4 changed file(s) with 249 addition(s) and 0 deletion(s). Raw diff Collapse all Expand all
244244 HTTP_SRCS="$HTTP_SRCS $HTTP_MAP_SRCS"
245245 fi
246246
247 if [ $HTTP_SPLIT_CLIENTS = YES ]; then
248 HTTP_MODULES="$HTTP_MODULES $HTTP_SPLIT_CLIENTS_MODULE"
249 HTTP_SRCS="$HTTP_SRCS $HTTP_SPLIT_CLIENTS_SRCS"
250 fi
251
247252 if [ $HTTP_REFERER = YES ]; then
248253 HTTP_MODULES="$HTTP_MODULES $HTTP_REFERER_MODULE"
249254 HTTP_SRCS="$HTTP_SRCS $HTTP_REFERER_SRCS"
7373 HTTP_GEO=YES
7474 HTTP_GEOIP=NO
7575 HTTP_MAP=YES
76 HTTP_SPLIT_CLIENTS=YES
7677 HTTP_REFERER=YES
7778 HTTP_REWRITE=YES
7879 HTTP_PROXY=YES
208209 --without-http_status_module) HTTP_STATUS=NO ;;
209210 --without-http_geo_module) HTTP_GEO=NO ;;
210211 --without-http_map_module) HTTP_MAP=NO ;;
212 --without-http_split_clients_module) HTTP_SPLIT_CLIENTS=NO ;;
211213 --without-http_referer_module) HTTP_REFERER=NO ;;
212214 --without-http_rewrite_module) HTTP_REWRITE=NO ;;
213215 --without-http_proxy_module) HTTP_PROXY=NO ;;
340342 --without-http_autoindex_module disable ngx_http_autoindex_module
341343 --without-http_geo_module disable ngx_http_geo_module
342344 --without-http_map_module disable ngx_http_map_module
345 --without-http_split_clients_module disable ngx_http_split_clients_module
343346 --without-http_referer_module disable ngx_http_referer_module
344347 --without-http_rewrite_module disable ngx_http_rewrite_module
345348 --without-http_proxy_module disable ngx_http_proxy_module
386386 HTTP_MAP_SRCS=src/http/modules/ngx_http_map_module.c
387387
388388
389 HTTP_SPLIT_CLIENTS_MODULE=ngx_http_split_clients_module
390 HTTP_SPLIT_CLIENTS_SRCS=src/http/modules/ngx_http_split_clients_module.c
391
392
389393 HTTP_REFERER_MODULE=ngx_http_referer_module
390394 HTTP_REFERER_SRCS=src/http/modules/ngx_http_referer_module.c
391395
0
1 /*
2 * Copyright (C) Igor Sysoev
3 */
4
5
6 #include <ngx_config.h>
7 #include <ngx_core.h>
8 #include <ngx_http.h>
9
10
11 typedef struct {
12 uint32_t percent;
13 ngx_http_variable_value_t value;
14 } ngx_http_split_clients_part_t;
15
16
17 typedef struct {
18 ngx_http_complex_value_t value;
19 ngx_array_t parts;
20 } ngx_http_split_clients_ctx_t;
21
22
23 static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd,
24 void *conf);
25 static char *ngx_http_split_clients(ngx_conf_t *cf, ngx_command_t *dummy,
26 void *conf);
27
28 static ngx_command_t ngx_http_split_clients_commands[] = {
29
30 { ngx_string("split_clients"),
31 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2,
32 ngx_conf_split_clients_block,
33 NGX_HTTP_MAIN_CONF_OFFSET,
34 0,
35 NULL },
36
37 ngx_null_command
38 };
39
40
41 static ngx_http_module_t ngx_http_split_clients_module_ctx = {
42 NULL, /* preconfiguration */
43 NULL, /* postconfiguration */
44
45 NULL, /* create main configuration */
46 NULL, /* init main configuration */
47
48 NULL, /* create server configuration */
49 NULL, /* merge server configuration */
50
51 NULL, /* create location configuration */
52 NULL /* merge location configuration */
53 };
54
55
56 ngx_module_t ngx_http_split_clients_module = {
57 NGX_MODULE_V1,
58 &ngx_http_split_clients_module_ctx, /* module context */
59 ngx_http_split_clients_commands, /* module directives */
60 NGX_HTTP_MODULE, /* module type */
61 NULL, /* init master */
62 NULL, /* init module */
63 NULL, /* init process */
64 NULL, /* init thread */
65 NULL, /* exit thread */
66 NULL, /* exit process */
67 NULL, /* exit master */
68 NGX_MODULE_V1_PADDING
69 };
70
71
72 static ngx_int_t
73 ngx_http_split_clients_variable(ngx_http_request_t *r,
74 ngx_http_variable_value_t *v, uintptr_t data)
75 {
76 ngx_http_split_clients_ctx_t *ctx = (ngx_http_split_clients_ctx_t *) data;
77
78 uint32_t hash;
79 ngx_str_t val;
80 ngx_uint_t i;
81 ngx_http_split_clients_part_t *part;
82
83 *v = ngx_http_variable_null_value;
84
85 if (ngx_http_complex_value(r, &ctx->value, &val) != NGX_OK) {
86 return NGX_OK;
87 }
88
89 hash = ngx_crc32_short(val.data, val.len);
90
91 part = ctx->parts.elts;
92
93 for (i = 0; i < ctx->parts.nelts; i++) {
94
95 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
96 "%D %D", hash, part[i].percent);
97
98 if (hash < part[i].percent) {
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;
112 ngx_str_t *value, name;
113 ngx_uint_t i, sum, last;
114 ngx_conf_t save;
115 ngx_http_variable_t *var;
116 ngx_http_split_clients_ctx_t *ctx;
117 ngx_http_split_clients_part_t *part;
118 ngx_http_compile_complex_value_t ccv;
119
120 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_split_clients_ctx_t));
121 if (ctx == NULL) {
122 return NGX_CONF_ERROR;
123 }
124
125 value = cf->args->elts;
126
127 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t));
128
129 ccv.cf = cf;
130 ccv.value = &value[1];
131 ccv.complex_value = &ctx->value;
132
133 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) {
134 return NGX_CONF_ERROR;
135 }
136
137 name = value[2];
138 name.len--;
139 name.data++;
140
141 var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE);
142 if (var == NULL) {
143 return NGX_CONF_ERROR;
144 }
145
146 var->get_handler = ngx_http_split_clients_variable;
147 var->data = (uintptr_t) ctx;
148
149 if (ngx_array_init(&ctx->parts, cf->pool, 2,
150 sizeof(ngx_http_split_clients_part_t))
151 != NGX_OK)
152 {
153 return NGX_CONF_ERROR;
154 }
155
156 save = *cf;
157 cf->ctx = ctx;
158 cf->handler = ngx_http_split_clients;
159 cf->handler_conf = conf;
160
161 rv = ngx_conf_parse(cf, NULL);
162
163 *cf = save;
164
165 sum = 0;
166 last = 0;
167 part = ctx->parts.elts;
168
169 for (i = 0; i < ctx->parts.nelts; i++) {
170 sum = part[i].percent ? sum + part[i].percent : 10000;
171 if (sum > 10000) {
172 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
173 "percent sum is more than 100%%");
174 return NGX_CONF_ERROR;
175 }
176
177 if (part[i].percent) {
178 part[i].percent = (uint32_t)
179 (last + 0xffffffff / 10000 * part[i].percent);
180 } else {
181 part[i].percent = 0xffffffff;
182 }
183
184 last = part[i].percent;
185 }
186
187 return rv;
188 }
189
190
191 static char *
192 ngx_http_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf)
193 {
194 ngx_int_t n;
195 ngx_str_t *value;
196 ngx_http_split_clients_ctx_t *ctx;
197 ngx_http_split_clients_part_t *part;
198
199 ctx = cf->ctx;
200 value = cf->args->elts;
201
202 part = ngx_array_push(&ctx->parts);
203 if (part == NULL) {
204 return NGX_CONF_ERROR;
205 }
206
207 if (value[0].len == 1 && value[0].data[0] == '*') {
208 part->percent = 0;
209
210 } else {
211 if (value[0].data[value[0].len - 1] != '%') {
212 goto invalid;
213 }
214
215 n = ngx_atofp(value[0].data, value[0].len - 1, 2);
216 if (n == NGX_ERROR || n == 0) {
217 goto invalid;
218 }
219
220 part->percent = (uint32_t) n;
221 }
222
223 part->value.len = value[1].len;
224 part->value.valid = 1;
225 part->value.no_cacheable = 0;
226 part->value.not_found = 0;
227 part->value.data = value[1].data;
228
229 return NGX_CONF_OK;
230
231 invalid:
232
233 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0,
234 "invalid percent value \"%V\"", &value[0]);
235 return NGX_CONF_ERROR;
236 }