Mercurial > hg > nginx
annotate src/http/modules/ngx_http_limit_zone_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 | 23d567eabc5d |
children | 3544987fef85 97995d63aa36 |
rev | line source |
---|---|
980 | 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 { | |
981 | 13 u_char color; |
14 u_char len; | |
980 | 15 u_short conn; |
16 u_char data[1]; | |
17 } ngx_http_limit_zone_node_t; | |
18 | |
19 | |
20 typedef struct { | |
21 ngx_shm_zone_t *shm_zone; | |
22 ngx_rbtree_node_t *node; | |
23 } ngx_http_limit_zone_cleanup_t; | |
24 | |
25 | |
26 typedef struct { | |
987 | 27 ngx_rbtree_t *rbtree; |
28 ngx_int_t index; | |
29 ngx_str_t var; | |
30 } ngx_http_limit_zone_ctx_t; | |
31 | |
32 | |
33 typedef struct { | |
980 | 34 ngx_shm_zone_t *shm_zone; |
35 ngx_uint_t conn; | |
3186 | 36 ngx_uint_t log_level; |
980 | 37 } ngx_http_limit_zone_conf_t; |
38 | |
39 | |
40 static void ngx_http_limit_zone_cleanup(void *data); | |
41 | |
42 static void *ngx_http_limit_zone_create_conf(ngx_conf_t *cf); | |
43 static char *ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, | |
44 void *child); | |
45 static char *ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, | |
46 void *conf); | |
47 static char *ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, | |
48 void *conf); | |
49 static ngx_int_t ngx_http_limit_zone_init(ngx_conf_t *cf); | |
50 | |
51 | |
3186 | 52 static ngx_conf_enum_t ngx_http_limit_conn_log_levels[] = { |
53 { ngx_string("info"), NGX_LOG_INFO }, | |
54 { ngx_string("notice"), NGX_LOG_NOTICE }, | |
55 { ngx_string("warn"), NGX_LOG_WARN }, | |
56 { ngx_string("error"), NGX_LOG_ERR }, | |
57 { ngx_null_string, 0 } | |
58 }; | |
59 | |
60 | |
980 | 61 static ngx_command_t ngx_http_limit_zone_commands[] = { |
62 | |
63 { ngx_string("limit_zone"), | |
987 | 64 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, |
980 | 65 ngx_http_limit_zone, |
66 0, | |
67 0, | |
68 NULL }, | |
69 | |
70 { ngx_string("limit_conn"), | |
987 | 71 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE2, |
980 | 72 ngx_http_limit_conn, |
73 NGX_HTTP_LOC_CONF_OFFSET, | |
74 0, | |
75 NULL }, | |
76 | |
3186 | 77 { ngx_string("limit_conn_log_level"), |
78 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
79 ngx_conf_set_enum_slot, | |
80 NGX_HTTP_LOC_CONF_OFFSET, | |
81 offsetof(ngx_http_limit_zone_conf_t, log_level), | |
82 &ngx_http_limit_conn_log_levels }, | |
83 | |
980 | 84 ngx_null_command |
85 }; | |
86 | |
87 | |
88 static ngx_http_module_t ngx_http_limit_zone_module_ctx = { | |
89 NULL, /* preconfiguration */ | |
90 ngx_http_limit_zone_init, /* postconfiguration */ | |
91 | |
92 NULL, /* create main configuration */ | |
93 NULL, /* init main configuration */ | |
94 | |
95 NULL, /* create server configuration */ | |
96 NULL, /* merge server configuration */ | |
97 | |
98 ngx_http_limit_zone_create_conf, /* create location configration */ | |
99 ngx_http_limit_zone_merge_conf /* merge location configration */ | |
100 }; | |
101 | |
102 | |
103 ngx_module_t ngx_http_limit_zone_module = { | |
104 NGX_MODULE_V1, | |
105 &ngx_http_limit_zone_module_ctx, /* module context */ | |
106 ngx_http_limit_zone_commands, /* module directives */ | |
107 NGX_HTTP_MODULE, /* module type */ | |
108 NULL, /* init master */ | |
109 NULL, /* init module */ | |
110 NULL, /* init process */ | |
111 NULL, /* init thread */ | |
112 NULL, /* exit thread */ | |
113 NULL, /* exit process */ | |
114 NULL, /* exit master */ | |
115 NGX_MODULE_V1_PADDING | |
116 }; | |
117 | |
118 | |
119 static ngx_int_t | |
120 ngx_http_limit_zone_handler(ngx_http_request_t *r) | |
121 { | |
122 size_t len, n; | |
123 uint32_t hash; | |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
124 ngx_int_t rc; |
980 | 125 ngx_slab_pool_t *shpool; |
126 ngx_rbtree_node_t *node, *sentinel; | |
127 ngx_pool_cleanup_t *cln; | |
128 ngx_http_variable_value_t *vv; | |
987 | 129 ngx_http_limit_zone_ctx_t *ctx; |
980 | 130 ngx_http_limit_zone_node_t *lz; |
131 ngx_http_limit_zone_conf_t *lzcf; | |
132 ngx_http_limit_zone_cleanup_t *lzcln; | |
133 | |
997
5900ec20604a
do not count connection for subrequest
Igor Sysoev <igor@sysoev.ru>
parents:
993
diff
changeset
|
134 if (r->main->limit_zone_set) { |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
135 return NGX_DECLINED; |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
136 } |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
137 |
980 | 138 lzcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_zone_module); |
139 | |
140 if (lzcf->shm_zone == NULL) { | |
141 return NGX_DECLINED; | |
142 } | |
143 | |
987 | 144 ctx = lzcf->shm_zone->data; |
145 | |
146 vv = ngx_http_get_indexed_variable(r, ctx->index); | |
980 | 147 |
148 if (vv == NULL || vv->not_found) { | |
149 return NGX_DECLINED; | |
150 } | |
151 | |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
152 len = vv->len; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
153 |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
154 if (len == 0) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
155 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
156 } |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
157 |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
158 if (len > 255) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
159 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
160 "the value of the \"%V\" variable " |
1406
03341711f9a2
use %v for ngx_variable_value_t in ngx_sprintf(),
Igor Sysoev <igor@sysoev.ru>
parents:
1036
diff
changeset
|
161 "is more than 255 bytes: \"%v\"", |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
162 &ctx->var, vv); |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
163 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
164 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
165 |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
166 r->main->limit_zone_set = 1; |
980 | 167 |
168 hash = ngx_crc32_short(vv->data, len); | |
169 | |
170 cln = ngx_pool_cleanup_add(r->pool, sizeof(ngx_http_limit_zone_cleanup_t)); | |
171 if (cln == NULL) { | |
172 return NGX_HTTP_INTERNAL_SERVER_ERROR; | |
173 } | |
174 | |
175 shpool = (ngx_slab_pool_t *) lzcf->shm_zone->shm.addr; | |
176 | |
177 ngx_shmtx_lock(&shpool->mutex); | |
178 | |
987 | 179 node = ctx->rbtree->root; |
180 sentinel = ctx->rbtree->sentinel; | |
980 | 181 |
182 while (node != sentinel) { | |
183 | |
184 if (hash < node->key) { | |
185 node = node->left; | |
186 continue; | |
187 } | |
188 | |
189 if (hash > node->key) { | |
190 node = node->right; | |
191 continue; | |
192 } | |
193 | |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
194 /* hash == node->key */ |
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
195 |
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
196 do { |
981 | 197 lz = (ngx_http_limit_zone_node_t *) &node->color; |
980 | 198 |
1036 | 199 rc = ngx_memn2cmp(vv->data, lz->data, len, (size_t) lz->len); |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
200 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
201 if (rc == 0) { |
981 | 202 if ((ngx_uint_t) lz->conn < lzcf->conn) { |
980 | 203 lz->conn++; |
204 goto done; | |
205 } | |
206 | |
207 ngx_shmtx_unlock(&shpool->mutex); | |
208 | |
3186 | 209 ngx_log_error(lzcf->log_level, r->connection->log, 0, |
2373 | 210 "limiting connections by zone \"%V\"", |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
211 &lzcf->shm_zone->shm.name); |
2373 | 212 |
980 | 213 return NGX_HTTP_SERVICE_UNAVAILABLE; |
214 } | |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
215 |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
216 node = (rc < 0) ? node->left : node->right; |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
217 |
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
218 } while (node != sentinel && hash == node->key); |
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
219 |
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
220 break; |
980 | 221 } |
222 | |
981 | 223 n = offsetof(ngx_rbtree_node_t, color) |
980 | 224 + offsetof(ngx_http_limit_zone_node_t, data) |
225 + len; | |
226 | |
227 node = ngx_slab_alloc_locked(shpool, n); | |
228 if (node == NULL) { | |
229 ngx_shmtx_unlock(&shpool->mutex); | |
230 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
231 } | |
232 | |
981 | 233 lz = (ngx_http_limit_zone_node_t *) &node->color; |
980 | 234 |
235 node->key = hash; | |
981 | 236 lz->len = (u_char) len; |
980 | 237 lz->conn = 1; |
238 ngx_memcpy(lz->data, vv->data, len); | |
239 | |
987 | 240 ngx_rbtree_insert(ctx->rbtree, node); |
980 | 241 |
242 done: | |
243 | |
244 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | |
245 "limit zone: %08XD %d", node->key, lz->conn); | |
246 | |
247 ngx_shmtx_unlock(&shpool->mutex); | |
248 | |
249 cln->handler = ngx_http_limit_zone_cleanup; | |
250 lzcln = cln->data; | |
251 | |
252 lzcln->shm_zone = lzcf->shm_zone; | |
253 lzcln->node = node; | |
254 | |
255 return NGX_DECLINED; | |
256 } | |
257 | |
258 | |
259 static void | |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
260 ngx_http_limit_zone_rbtree_insert_value(ngx_rbtree_node_t *temp, |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
261 ngx_rbtree_node_t *node, ngx_rbtree_node_t *sentinel) |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
262 { |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
263 ngx_rbtree_node_t **p; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
264 ngx_http_limit_zone_node_t *lzn, *lznt; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
265 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
266 for ( ;; ) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
267 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
268 if (node->key < temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
269 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
270 p = &temp->left; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
271 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
272 } else if (node->key > temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
273 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
274 p = &temp->right; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
275 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
276 } else { /* node->key == temp->key */ |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
277 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
278 lzn = (ngx_http_limit_zone_node_t *) &node->color; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
279 lznt = (ngx_http_limit_zone_node_t *) &temp->color; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
280 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
281 p = (ngx_memn2cmp(lzn->data, lznt->data, lzn->len, lznt->len) < 0) |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
282 ? &temp->left : &temp->right; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
283 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
284 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
285 if (*p == sentinel) { |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
286 break; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
287 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
288 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
289 temp = *p; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
290 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
291 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
292 *p = node; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
293 node->parent = temp; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
294 node->left = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
295 node->right = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
296 ngx_rbt_red(node); |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
297 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
298 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
299 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
300 static void |
980 | 301 ngx_http_limit_zone_cleanup(void *data) |
302 { | |
303 ngx_http_limit_zone_cleanup_t *lzcln = data; | |
304 | |
305 ngx_slab_pool_t *shpool; | |
306 ngx_rbtree_node_t *node; | |
987 | 307 ngx_http_limit_zone_ctx_t *ctx; |
980 | 308 ngx_http_limit_zone_node_t *lz; |
309 | |
987 | 310 ctx = lzcln->shm_zone->data; |
980 | 311 shpool = (ngx_slab_pool_t *) lzcln->shm_zone->shm.addr; |
312 node = lzcln->node; | |
981 | 313 lz = (ngx_http_limit_zone_node_t *) &node->color; |
980 | 314 |
315 ngx_shmtx_lock(&shpool->mutex); | |
316 | |
317 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, lzcln->shm_zone->shm.log, 0, | |
318 "limit zone cleanup: %08XD %d", node->key, lz->conn); | |
319 | |
320 lz->conn--; | |
321 | |
322 if (lz->conn == 0) { | |
987 | 323 ngx_rbtree_delete(ctx->rbtree, node); |
980 | 324 ngx_slab_free_locked(shpool, node); |
325 } | |
326 | |
327 ngx_shmtx_unlock(&shpool->mutex); | |
328 } | |
329 | |
330 | |
331 static ngx_int_t | |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
332 ngx_http_limit_zone_init_zone(ngx_shm_zone_t *shm_zone, void *data) |
980 | 333 { |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
334 ngx_http_limit_zone_ctx_t *octx = data; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
335 |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
336 size_t len; |
987 | 337 ngx_slab_pool_t *shpool; |
338 ngx_rbtree_node_t *sentinel; | |
339 ngx_http_limit_zone_ctx_t *ctx; | |
980 | 340 |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
341 ctx = shm_zone->data; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
342 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
343 if (octx) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
344 if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
345 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, |
1001 | 346 "limit_zone \"%V\" uses the \"%V\" variable " |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
347 "while previously it used the \"%V\" variable", |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
348 &shm_zone->shm.name, &ctx->var, &octx->var); |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
349 return NGX_ERROR; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
350 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
351 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
352 ctx->rbtree = octx->rbtree; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
353 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
354 return NGX_OK; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
355 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
356 |
980 | 357 shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
358 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
359 if (shm_zone->shm.exists) { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
360 ctx->rbtree = shpool->data; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
361 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
362 return NGX_OK; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
363 } |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
364 |
987 | 365 ctx->rbtree = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_t)); |
366 if (ctx->rbtree == NULL) { | |
980 | 367 return NGX_ERROR; |
368 } | |
369 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
370 shpool->data = ctx->rbtree; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
371 |
980 | 372 sentinel = ngx_slab_alloc(shpool, sizeof(ngx_rbtree_node_t)); |
373 if (sentinel == NULL) { | |
374 return NGX_ERROR; | |
375 } | |
376 | |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
377 ngx_rbtree_init(ctx->rbtree, sentinel, |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
378 ngx_http_limit_zone_rbtree_insert_value); |
980 | 379 |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
380 len = sizeof(" in limit_zone \"\"") + shm_zone->shm.name.len; |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
381 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
382 shpool->log_ctx = ngx_slab_alloc(shpool, len); |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
383 if (shpool->log_ctx == NULL) { |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
384 return NGX_ERROR; |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
385 } |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
386 |
2716
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
387 ngx_sprintf(shpool->log_ctx, " in limit_zone \"%V\"%Z", |
d5896f6608e8
move zone name from ngx_shm_zone_t to ngx_shm_t to use Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2612
diff
changeset
|
388 &shm_zone->shm.name); |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2373
diff
changeset
|
389 |
980 | 390 return NGX_OK; |
391 } | |
392 | |
393 | |
394 static void * | |
395 ngx_http_limit_zone_create_conf(ngx_conf_t *cf) | |
396 { | |
397 ngx_http_limit_zone_conf_t *conf; | |
398 | |
399 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_conf_t)); | |
400 if (conf == NULL) { | |
2912
c7d57b539248
return NULL instead of NGX_CONF_ERROR on a create conf failure
Igor Sysoev <igor@sysoev.ru>
parents:
2720
diff
changeset
|
401 return NULL; |
980 | 402 } |
403 | |
404 /* | |
405 * set by ngx_pcalloc(): | |
406 * | |
407 * conf->shm_zone = NULL; | |
408 * conf->conn = 0; | |
409 */ | |
410 | |
3186 | 411 conf->log_level = NGX_CONF_UNSET_UINT; |
412 | |
980 | 413 return conf; |
414 } | |
415 | |
416 | |
417 static char * | |
418 ngx_http_limit_zone_merge_conf(ngx_conf_t *cf, void *parent, void *child) | |
419 { | |
420 ngx_http_limit_zone_conf_t *prev = parent; | |
421 ngx_http_limit_zone_conf_t *conf = child; | |
422 | |
423 if (conf->shm_zone == NULL) { | |
424 *conf = *prev; | |
425 } | |
426 | |
3186 | 427 ngx_conf_merge_uint_value(conf->log_level, prev->log_level, NGX_LOG_ERR); |
428 | |
980 | 429 return NGX_CONF_OK; |
430 } | |
431 | |
432 | |
433 static char * | |
434 ngx_http_limit_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
435 { | |
987 | 436 ssize_t n; |
437 ngx_str_t *value; | |
438 ngx_shm_zone_t *shm_zone; | |
439 ngx_http_limit_zone_ctx_t *ctx; | |
980 | 440 |
441 value = cf->args->elts; | |
442 | |
987 | 443 if (value[2].data[0] != '$') { |
444 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
445 "invalid variable name \"%V\"", &value[2]); | |
446 return NGX_CONF_ERROR; | |
447 } | |
448 | |
449 value[2].len--; | |
450 value[2].data++; | |
451 | |
452 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_zone_ctx_t)); | |
453 if (ctx == NULL) { | |
454 return NGX_CONF_ERROR; | |
455 } | |
456 | |
457 ctx->index = ngx_http_get_variable_index(cf, &value[2]); | |
458 if (ctx->index == NGX_ERROR) { | |
459 return NGX_CONF_ERROR; | |
460 } | |
461 | |
462 ctx->var = value[2]; | |
463 | |
464 n = ngx_parse_size(&value[3]); | |
980 | 465 |
466 if (n == NGX_ERROR) { | |
467 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
987 | 468 "invalid size of limit_zone \"%V\"", &value[3]); |
980 | 469 return NGX_CONF_ERROR; |
470 } | |
471 | |
472 if (n < (ngx_int_t) (8 * ngx_pagesize)) { | |
473 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
474 "limit_zone \"%V\" is too small", &value[1]); | |
475 return NGX_CONF_ERROR; | |
476 } | |
477 | |
478 | |
479 shm_zone = ngx_shared_memory_add(cf, &value[1], n, | |
480 &ngx_http_limit_zone_module); | |
481 if (shm_zone == NULL) { | |
482 return NGX_CONF_ERROR; | |
483 } | |
484 | |
987 | 485 if (shm_zone->data) { |
486 ctx = shm_zone->data; | |
487 | |
488 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
489 "limit_zone \"%V\" is already bound to variable \"%V\"", | |
490 &value[1], &ctx->var); | |
491 return NGX_CONF_ERROR; | |
492 } | |
493 | |
980 | 494 shm_zone->init = ngx_http_limit_zone_init_zone; |
987 | 495 shm_zone->data = ctx; |
980 | 496 |
497 return NGX_CONF_OK; | |
498 } | |
499 | |
500 | |
501 static char * | |
502 ngx_http_limit_conn(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) | |
503 { | |
504 ngx_http_limit_zone_conf_t *lzcf = conf; | |
505 | |
506 ngx_int_t n; | |
507 ngx_str_t *value; | |
508 | |
2372 | 509 if (lzcf->shm_zone) { |
510 return "is duplicate"; | |
511 } | |
512 | |
980 | 513 value = cf->args->elts; |
514 | |
987 | 515 lzcf->shm_zone = ngx_shared_memory_add(cf, &value[1], 0, |
516 &ngx_http_limit_zone_module); | |
517 if (lzcf->shm_zone == NULL) { | |
980 | 518 return NGX_CONF_ERROR; |
519 } | |
520 | |
987 | 521 n = ngx_atoi(value[2].data, value[2].len); |
522 if (n <= 0) { | |
980 | 523 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
987 | 524 "invalid number of connections \"%V\"", &value[2]); |
980 | 525 return NGX_CONF_ERROR; |
526 } | |
527 | |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
528 if (n > 65535) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
529 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
530 "connection limit must be less 65536"); |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
531 return NGX_CONF_ERROR; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
532 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
533 |
980 | 534 lzcf->conn = n; |
535 | |
536 return NGX_CONF_OK; | |
537 } | |
538 | |
539 | |
540 static ngx_int_t | |
541 ngx_http_limit_zone_init(ngx_conf_t *cf) | |
542 { | |
543 ngx_http_handler_pt *h; | |
544 ngx_http_core_main_conf_t *cmcf; | |
545 | |
546 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
547 | |
548 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); | |
549 if (h == NULL) { | |
550 return NGX_ERROR; | |
551 } | |
552 | |
553 *h = ngx_http_limit_zone_handler; | |
554 | |
555 return NGX_OK; | |
556 } |