Mercurial > hg > nginx
annotate src/http/modules/ngx_http_split_clients_module.c @ 4253:6efec8b1ff52 stable-1.0
Merging r4193, r4194:
Autoindex fixes:
*) Autoindex: escape '?' in file names.
For files with '?' in their names autoindex generated links with '?' not
escaped. This resulted in effectively truncated links as '?' indicates
query string start.
This is an updated version of the patch originally posted at [1]. It
introduces generic NGX_ESCAPE_URI_COMPONENT which escapes everything but
unreserved characters as per RFC 3986. This approach also renders unneeded
special colon processing (as colon is percent-encoded now), it's dropped
accordingly.
[1] http://nginx.org/pipermail/nginx-devel/2010-February/000112.html
*) Autoindex: escape html in file names.
author | Igor Sysoev <igor@sysoev.ru> |
---|---|
date | Tue, 01 Nov 2011 14:09:15 +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 } |