Mercurial > hg > nginx
annotate src/http/modules/ngx_http_split_clients_module.c @ 4437:3a1507f48686 stable-1.0
Merge of r4372, r4373, r4374:
SCGI fixes:
*) Fixed incorrect use of r->http_version in scgi module.
The r->http_version is a version of client's request, and modules
must not set it unless they are really willing to downgrade protocol
version used for a response (i.e. to HTTP/0.9 if no response headers
are available). In neither case r->http_version may be upgraded.
The former code downgraded response from HTTP/1.1 to HTTP/1.0 for no
reason, causing various problems (see ticket #66). It was also
possible that HTTP/0.9 requests were upgraded to HTTP/1.0.
*) Removed duplicate function declaration.
*) Removed error if there is no Status header.
The SCGI specification doesn't specify format of the response, and
assuming CGI specs should be used there is no reason to complain.
RFC 3875 explicitly states that "A Status header field is optional,
and status 200 'OK' is assumed if it is omitted".
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Sun, 05 Feb 2012 13:53:50 +0000 |
parents | eccd0b66a4ab |
children | d620f497c50f |
rev | line source |
---|---|
3513 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4 */ | |
5 | |
6 | |
7 #include <ngx_config.h> | |
8 #include <ngx_core.h> | |
9 #include <ngx_http.h> | |
10 | |
11 | |
12 typedef struct { | |
13 uint32_t percent; | |
14 ngx_http_variable_value_t value; | |
15 } ngx_http_split_clients_part_t; | |
16 | |
17 | |
18 typedef struct { | |
19 ngx_http_complex_value_t value; | |
20 ngx_array_t parts; | |
21 } ngx_http_split_clients_ctx_t; | |
22 | |
23 | |
24 static char *ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, | |
25 void *conf); | |
26 static char *ngx_http_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, | |
27 void *conf); | |
28 | |
29 static ngx_command_t ngx_http_split_clients_commands[] = { | |
30 | |
31 { ngx_string("split_clients"), | |
32 NGX_HTTP_MAIN_CONF|NGX_CONF_BLOCK|NGX_CONF_TAKE2, | |
33 ngx_conf_split_clients_block, | |
34 NGX_HTTP_MAIN_CONF_OFFSET, | |
35 0, | |
36 NULL }, | |
37 | |
38 ngx_null_command | |
39 }; | |
40 | |
41 | |
42 static ngx_http_module_t ngx_http_split_clients_module_ctx = { | |
43 NULL, /* preconfiguration */ | |
44 NULL, /* postconfiguration */ | |
45 | |
46 NULL, /* create main configuration */ | |
47 NULL, /* init main configuration */ | |
48 | |
49 NULL, /* create server configuration */ | |
50 NULL, /* merge server configuration */ | |
51 | |
52 NULL, /* create location configuration */ | |
53 NULL /* merge location configuration */ | |
54 }; | |
55 | |
56 | |
57 ngx_module_t ngx_http_split_clients_module = { | |
58 NGX_MODULE_V1, | |
59 &ngx_http_split_clients_module_ctx, /* module context */ | |
60 ngx_http_split_clients_commands, /* module directives */ | |
61 NGX_HTTP_MODULE, /* module type */ | |
62 NULL, /* init master */ | |
63 NULL, /* init module */ | |
64 NULL, /* init process */ | |
65 NULL, /* init thread */ | |
66 NULL, /* exit thread */ | |
67 NULL, /* exit process */ | |
68 NULL, /* exit master */ | |
69 NGX_MODULE_V1_PADDING | |
70 }; | |
71 | |
72 | |
73 static ngx_int_t | |
74 ngx_http_split_clients_variable(ngx_http_request_t *r, | |
75 ngx_http_variable_value_t *v, uintptr_t data) | |
76 { | |
77 ngx_http_split_clients_ctx_t *ctx = (ngx_http_split_clients_ctx_t *) data; | |
78 | |
79 uint32_t hash; | |
80 ngx_str_t val; | |
81 ngx_uint_t i; | |
82 ngx_http_split_clients_part_t *part; | |
83 | |
84 *v = ngx_http_variable_null_value; | |
85 | |
86 if (ngx_http_complex_value(r, &ctx->value, &val) != NGX_OK) { | |
87 return NGX_OK; | |
88 } | |
89 | |
3892
12d8d2f30205
use MurmurHash2 for split_clients, because
Igor Sysoev <igor@sysoev.ru>
parents:
3607
diff
changeset
|
90 hash = ngx_murmur_hash2(val.data, val.len); |
3513 | 91 |
92 part = ctx->parts.elts; | |
93 | |
94 for (i = 0; i < ctx->parts.nelts; i++) { | |
95 | |
96 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
3918 | 97 "http split: %uD %uD", hash, part[i].percent); |
3513 | 98 |
99 if (hash < part[i].percent) { | |
100 *v = part[i].value; | |
101 return NGX_OK; | |
102 } | |
103 } | |
104 | |
105 return NGX_OK; | |
106 } | |
107 | |
108 | |
109 static char * | |
110 ngx_conf_split_clients_block(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
111 { | |
112 char *rv; | |
113 ngx_str_t *value, name; | |
114 ngx_uint_t i, sum, last; | |
115 ngx_conf_t save; | |
116 ngx_http_variable_t *var; | |
117 ngx_http_split_clients_ctx_t *ctx; | |
118 ngx_http_split_clients_part_t *part; | |
119 ngx_http_compile_complex_value_t ccv; | |
120 | |
121 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_split_clients_ctx_t)); | |
122 if (ctx == NULL) { | |
123 return NGX_CONF_ERROR; | |
124 } | |
125 | |
126 value = cf->args->elts; | |
127 | |
128 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); | |
129 | |
130 ccv.cf = cf; | |
131 ccv.value = &value[1]; | |
132 ccv.complex_value = &ctx->value; | |
133 | |
134 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { | |
135 return NGX_CONF_ERROR; | |
136 } | |
137 | |
138 name = value[2]; | |
139 name.len--; | |
140 name.data++; | |
141 | |
142 var = ngx_http_add_variable(cf, &name, NGX_HTTP_VAR_CHANGEABLE); | |
143 if (var == NULL) { | |
144 return NGX_CONF_ERROR; | |
145 } | |
146 | |
147 var->get_handler = ngx_http_split_clients_variable; | |
148 var->data = (uintptr_t) ctx; | |
149 | |
150 if (ngx_array_init(&ctx->parts, cf->pool, 2, | |
151 sizeof(ngx_http_split_clients_part_t)) | |
152 != NGX_OK) | |
153 { | |
154 return NGX_CONF_ERROR; | |
155 } | |
156 | |
157 save = *cf; | |
158 cf->ctx = ctx; | |
159 cf->handler = ngx_http_split_clients; | |
160 cf->handler_conf = conf; | |
161 | |
162 rv = ngx_conf_parse(cf, NULL); | |
163 | |
164 *cf = save; | |
165 | |
3607
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
166 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
|
167 return rv; |
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
168 } |
8bff43217171
do not try to calculate procent sum if there was an error
Igor Sysoev <igor@sysoev.ru>
parents:
3513
diff
changeset
|
169 |
3513 | 170 sum = 0; |
171 last = 0; | |
172 part = ctx->parts.elts; | |
173 | |
174 for (i = 0; i < ctx->parts.nelts; i++) { | |
175 sum = part[i].percent ? sum + part[i].percent : 10000; | |
176 if (sum > 10000) { | |
177 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
178 "percent sum is more than 100%%"); | |
179 return NGX_CONF_ERROR; | |
180 } | |
181 | |
182 if (part[i].percent) { | |
183 part[i].percent = (uint32_t) | |
184 (last + 0xffffffff / 10000 * part[i].percent); | |
185 } else { | |
186 part[i].percent = 0xffffffff; | |
187 } | |
188 | |
189 last = part[i].percent; | |
190 } | |
191 | |
192 return rv; | |
193 } | |
194 | |
195 | |
196 static char * | |
197 ngx_http_split_clients(ngx_conf_t *cf, ngx_command_t *dummy, void *conf) | |
198 { | |
199 ngx_int_t n; | |
200 ngx_str_t *value; | |
201 ngx_http_split_clients_ctx_t *ctx; | |
202 ngx_http_split_clients_part_t *part; | |
203 | |
204 ctx = cf->ctx; | |
205 value = cf->args->elts; | |
206 | |
207 part = ngx_array_push(&ctx->parts); | |
208 if (part == NULL) { | |
209 return NGX_CONF_ERROR; | |
210 } | |
211 | |
212 if (value[0].len == 1 && value[0].data[0] == '*') { | |
213 part->percent = 0; | |
214 | |
215 } else { | |
216 if (value[0].data[value[0].len - 1] != '%') { | |
217 goto invalid; | |
218 } | |
219 | |
220 n = ngx_atofp(value[0].data, value[0].len - 1, 2); | |
221 if (n == NGX_ERROR || n == 0) { | |
222 goto invalid; | |
223 } | |
224 | |
225 part->percent = (uint32_t) n; | |
226 } | |
227 | |
228 part->value.len = value[1].len; | |
229 part->value.valid = 1; | |
230 part->value.no_cacheable = 0; | |
231 part->value.not_found = 0; | |
232 part->value.data = value[1].data; | |
233 | |
234 return NGX_CONF_OK; | |
235 | |
236 invalid: | |
237 | |
238 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
239 "invalid percent value \"%V\"", &value[0]); | |
240 return NGX_CONF_ERROR; | |
241 } |