Mercurial > hg > nginx
annotate src/http/modules/ngx_http_limit_req_module.c @ 4515:8bb695c05870 stable-1.0
Merge of r4498:
Fix of rbtree lookup on hash collisions.
Previous code incorrectly assumed that nodes with identical keys are linked
together. This might not be true after tree rebalance.
Patch by Lanshun Zhou.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 05 Mar 2012 13:17:56 +0000 |
parents | 4919fb357a5d |
children | 50143b8fb95f |
rev | line source |
---|---|
980 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4450
4919fb357a5d
Merge of r4406, r4413: copyrights updated.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4440
diff
changeset
|
4 * Copyright (C) Nginx, Inc. |
980 | 5 */ |
6 | |
7 | |
8 #include <ngx_config.h> | |
9 #include <ngx_core.h> | |
10 #include <ngx_http.h> | |
11 | |
12 | |
13 typedef struct { | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
14 u_char color; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
15 u_char dummy; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
16 u_short len; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
17 ngx_queue_t queue; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
18 ngx_msec_t last; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
19 /* integer value, 1 corresponds to 0.001 r/s */ |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
20 ngx_uint_t excess; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
21 u_char data[1]; |
2294 | 22 } ngx_http_limit_req_node_t; |
980 | 23 |
24 | |
25 typedef struct { | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
26 ngx_rbtree_t rbtree; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
27 ngx_rbtree_node_t sentinel; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
28 ngx_queue_t queue; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
29 } ngx_http_limit_req_shctx_t; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
30 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
31 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
32 typedef struct { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
33 ngx_http_limit_req_shctx_t *sh; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
34 ngx_slab_pool_t *shpool; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
35 /* integer value, 1 corresponds to 0.001 r/s */ |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
36 ngx_uint_t rate; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
37 ngx_int_t index; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
38 ngx_str_t var; |
2294 | 39 } ngx_http_limit_req_ctx_t; |
987 | 40 |
41 | |
42 typedef struct { | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
43 ngx_shm_zone_t *shm_zone; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
44 /* integer value, 1 corresponds to 0.001 r/s */ |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
45 ngx_uint_t burst; |
3185 | 46 ngx_uint_t limit_log_level; |
47 ngx_uint_t delay_log_level; | |
48 | |
49 ngx_uint_t nodelay; /* unsigned nodelay:1 */ | |
2294 | 50 } ngx_http_limit_req_conf_t; |
980 | 51 |
52 | |
2294 | 53 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
54 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
55 ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep); |
2294 | 56 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
57 ngx_uint_t n); | |
980 | 58 |
2294 | 59 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); |
60 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, | |
980 | 61 void *child); |
2294 | 62 static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, |
980 | 63 void *conf); |
2294 | 64 static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, |
980 | 65 void *conf); |
2294 | 66 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); |
980 | 67 |
68 | |
3185 | 69 static ngx_conf_enum_t ngx_http_limit_req_log_levels[] = { |
70 { ngx_string("info"), NGX_LOG_INFO }, | |
71 { ngx_string("notice"), NGX_LOG_NOTICE }, | |
72 { ngx_string("warn"), NGX_LOG_WARN }, | |
73 { ngx_string("error"), NGX_LOG_ERR }, | |
74 { ngx_null_string, 0 } | |
75 }; | |
76 | |
77 | |
2294 | 78 static ngx_command_t ngx_http_limit_req_commands[] = { |
980 | 79 |
2294 | 80 { ngx_string("limit_req_zone"), |
987 | 81 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, |
2294 | 82 ngx_http_limit_req_zone, |
980 | 83 0, |
84 0, | |
85 NULL }, | |
86 | |
2294 | 87 { ngx_string("limit_req"), |
88 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, | |
89 ngx_http_limit_req, | |
980 | 90 NGX_HTTP_LOC_CONF_OFFSET, |
91 0, | |
92 NULL }, | |
93 | |
3185 | 94 { ngx_string("limit_req_log_level"), |
95 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
96 ngx_conf_set_enum_slot, | |
97 NGX_HTTP_LOC_CONF_OFFSET, | |
98 offsetof(ngx_http_limit_req_conf_t, limit_log_level), | |
99 &ngx_http_limit_req_log_levels }, | |
100 | |
980 | 101 ngx_null_command |
102 }; | |
103 | |
104 | |
2294 | 105 static ngx_http_module_t ngx_http_limit_req_module_ctx = { |
980 | 106 NULL, /* preconfiguration */ |
2294 | 107 ngx_http_limit_req_init, /* postconfiguration */ |
980 | 108 |
109 NULL, /* create main configuration */ | |
110 NULL, /* init main configuration */ | |
111 | |
112 NULL, /* create server configuration */ | |
113 NULL, /* merge server configuration */ | |
114 | |
2294 | 115 ngx_http_limit_req_create_conf, /* create location configration */ |
116 ngx_http_limit_req_merge_conf /* merge location configration */ | |
980 | 117 }; |
118 | |
119 | |
2294 | 120 ngx_module_t ngx_http_limit_req_module = { |
980 | 121 NGX_MODULE_V1, |
2294 | 122 &ngx_http_limit_req_module_ctx, /* module context */ |
123 ngx_http_limit_req_commands, /* module directives */ | |
980 | 124 NGX_HTTP_MODULE, /* module type */ |
125 NULL, /* init master */ | |
126 NULL, /* init module */ | |
127 NULL, /* init process */ | |
128 NULL, /* init thread */ | |
129 NULL, /* exit thread */ | |
130 NULL, /* exit process */ | |
131 NULL, /* exit master */ | |
132 NGX_MODULE_V1_PADDING | |
133 }; | |
134 | |
135 | |
136 static ngx_int_t | |
2294 | 137 ngx_http_limit_req_handler(ngx_http_request_t *r) |
980 | 138 { |
2294 | 139 size_t len, n; |
140 uint32_t hash; | |
141 ngx_int_t rc; | |
2313 | 142 ngx_uint_t excess; |
2294 | 143 ngx_time_t *tp; |
144 ngx_rbtree_node_t *node; | |
145 ngx_http_variable_value_t *vv; | |
146 ngx_http_limit_req_ctx_t *ctx; | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
147 ngx_http_limit_req_node_t *lr; |
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
148 ngx_http_limit_req_conf_t *lrcf; |
980 | 149 |
2294 | 150 if (r->main->limit_req_set) { |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
151 return NGX_DECLINED; |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
152 } |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
153 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
154 lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); |
980 | 155 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
156 if (lrcf->shm_zone == NULL) { |
980 | 157 return NGX_DECLINED; |
158 } | |
159 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
160 ctx = lrcf->shm_zone->data; |
987 | 161 |
162 vv = ngx_http_get_indexed_variable(r, ctx->index); | |
980 | 163 |
164 if (vv == NULL || vv->not_found) { | |
165 return NGX_DECLINED; | |
166 } | |
167 | |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
168 len = vv->len; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
169 |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
170 if (len == 0) { |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
171 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
172 } |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
173 |
2294 | 174 if (len > 65535) { |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
175 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
|
176 "the value of the \"%V\" variable " |
2294 | 177 "is more than 65535 bytes: \"%v\"", |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
178 &ctx->var, vv); |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
179 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
180 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
181 |
2294 | 182 r->main->limit_req_set = 1; |
980 | 183 |
184 hash = ngx_crc32_short(vv->data, len); | |
185 | |
2294 | 186 ngx_shmtx_lock(&ctx->shpool->mutex); |
187 | |
188 ngx_http_limit_req_expire(ctx, 1); | |
189 | |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
190 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess); |
980 | 191 |
2313 | 192 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2973 | 193 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
194 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
195 if (rc == NGX_DECLINED) { |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
196 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
197 n = offsetof(ngx_rbtree_node_t, color) |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
198 + offsetof(ngx_http_limit_req_node_t, data) |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
199 + len; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
200 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
201 node = ngx_slab_alloc_locked(ctx->shpool, n); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
202 if (node == NULL) { |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
203 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
204 ngx_http_limit_req_expire(ctx, 0); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
205 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
206 node = ngx_slab_alloc_locked(ctx->shpool, n); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
207 if (node == NULL) { |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
208 ngx_shmtx_unlock(&ctx->shpool->mutex); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
209 return NGX_HTTP_SERVICE_UNAVAILABLE; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
210 } |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
211 } |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
212 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
213 lr = (ngx_http_limit_req_node_t *) &node->color; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
214 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
215 node->key = hash; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
216 lr->len = (u_char) len; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
217 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
218 tp = ngx_timeofday(); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
219 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
220 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
221 lr->excess = 0; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
222 ngx_memcpy(lr->data, vv->data, len); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
223 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
224 ngx_rbtree_insert(&ctx->sh->rbtree, node); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
225 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
226 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
227 |
2294 | 228 ngx_shmtx_unlock(&ctx->shpool->mutex); |
1012
11ffb8e4753f
stop rbtree search early if equal hash was found
Igor Sysoev <igor@sysoev.ru>
parents:
1011
diff
changeset
|
229 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
230 return NGX_DECLINED; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
231 } |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
232 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
233 ngx_shmtx_unlock(&ctx->shpool->mutex); |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
234 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
235 if (rc == NGX_OK) { |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
236 return NGX_DECLINED; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
237 } |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
238 |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
239 if (rc == NGX_BUSY) { |
3185 | 240 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, |
2376
29d89920a749
*) add zone name while logging 503 error reason
Igor Sysoev <igor@sysoev.ru>
parents:
2375
diff
changeset
|
241 "limiting requests, excess: %ui.%03ui 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
|
242 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
980 | 243 |
244 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
245 } | |
246 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
247 /* rc == NGX_AGAIN */ |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
248 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
249 if (lrcf->nodelay) { |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
250 return NGX_DECLINED; |
2294 | 251 } |
252 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
253 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
254 "delaying request, excess: %ui.%03ui, by zone \"%V\"", |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
255 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
2294 | 256 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
257 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
258 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
2294 | 259 } |
260 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
261 r->read_event_handler = ngx_http_test_reading; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
262 r->write_event_handler = ngx_http_limit_req_delay; |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
263 ngx_add_timer(r->connection->write, |
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
264 (ngx_msec_t) excess * 1000 / ctx->rate); |
2294 | 265 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
266 return NGX_AGAIN; |
980 | 267 } |
268 | |
269 | |
270 static void | |
2294 | 271 ngx_http_limit_req_delay(ngx_http_request_t *r) |
272 { | |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
273 ngx_event_t *wev; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
274 |
2294 | 275 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2973 | 276 "limit_req delay"); |
2294 | 277 |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
278 wev = r->connection->write; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
279 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
280 if (!wev->timedout) { |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
281 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
282 if (ngx_handle_write_event(wev, 0) != NGX_OK) { |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
283 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
284 } |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
285 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
286 return; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
287 } |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
288 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
289 wev->timedout = 0; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
290 |
2294 | 291 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
292 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
293 return; | |
294 } | |
295 | |
296 r->read_event_handler = ngx_http_block_reading; | |
297 r->write_event_handler = ngx_http_core_run_phases; | |
298 | |
299 ngx_http_core_run_phases(r); | |
300 } | |
301 | |
302 | |
303 static void | |
304 ngx_http_limit_req_rbtree_insert_value(ngx_rbtree_node_t *temp, | |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
305 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
|
306 { |
2294 | 307 ngx_rbtree_node_t **p; |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
308 ngx_http_limit_req_node_t *lrn, *lrnt; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
309 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
310 for ( ;; ) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
311 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
312 if (node->key < temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
313 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
314 p = &temp->left; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
315 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
316 } else if (node->key > temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
317 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
318 p = &temp->right; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
319 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
320 } else { /* node->key == temp->key */ |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
321 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
322 lrn = (ngx_http_limit_req_node_t *) &node->color; |
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
323 lrnt = (ngx_http_limit_req_node_t *) &temp->color; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
324 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
325 p = (ngx_memn2cmp(lrn->data, lrnt->data, lrn->len, lrnt->len) < 0) |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
326 ? &temp->left : &temp->right; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
327 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
328 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
329 if (*p == sentinel) { |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
330 break; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
331 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
332 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
333 temp = *p; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
334 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
335 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
336 *p = node; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
337 node->parent = temp; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
338 node->left = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
339 node->right = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
340 ngx_rbt_red(node); |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
341 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
342 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
343 |
2294 | 344 static ngx_int_t |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
345 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
346 u_char *data, size_t len, ngx_uint_t *ep) |
980 | 347 { |
2313 | 348 ngx_int_t rc, excess; |
2294 | 349 ngx_time_t *tp; |
350 ngx_msec_t now; | |
351 ngx_msec_int_t ms; | |
352 ngx_rbtree_node_t *node, *sentinel; | |
353 ngx_http_limit_req_ctx_t *ctx; | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
354 ngx_http_limit_req_node_t *lr; |
2294 | 355 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
356 ctx = lrcf->shm_zone->data; |
2294 | 357 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
358 node = ctx->sh->rbtree.root; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
359 sentinel = ctx->sh->rbtree.sentinel; |
980 | 360 |
2294 | 361 while (node != sentinel) { |
362 | |
363 if (hash < node->key) { | |
364 node = node->left; | |
365 continue; | |
366 } | |
367 | |
368 if (hash > node->key) { | |
369 node = node->right; | |
370 continue; | |
371 } | |
372 | |
373 /* hash == node->key */ | |
374 | |
4515 | 375 lr = (ngx_http_limit_req_node_t *) &node->color; |
980 | 376 |
4515 | 377 rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); |
2294 | 378 |
4515 | 379 if (rc == 0) { |
380 ngx_queue_remove(&lr->queue); | |
381 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
2294 | 382 |
4515 | 383 tp = ngx_timeofday(); |
3191 | 384 |
4515 | 385 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
386 ms = (ngx_msec_int_t) (now - lr->last); | |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
387 |
4515 | 388 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; |
3183
b87542338ac3
make limit_req to conform to the leaky bucket algorithm
Igor Sysoev <igor@sysoev.ru>
parents:
2973
diff
changeset
|
389 |
4515 | 390 if (excess < 0) { |
391 excess = 0; | |
2294 | 392 } |
393 | |
4515 | 394 *ep = excess; |
395 | |
396 if ((ngx_uint_t) excess > lrcf->burst) { | |
397 return NGX_BUSY; | |
398 } | |
399 | |
400 lr->excess = excess; | |
401 lr->last = now; | |
2294 | 402 |
4515 | 403 if (excess) { |
404 return NGX_AGAIN; | |
405 } | |
2294 | 406 |
4515 | 407 return NGX_OK; |
408 } | |
409 | |
410 node = (rc < 0) ? node->left : node->right; | |
980 | 411 } |
412 | |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
413 *ep = 0; |
2294 | 414 |
415 return NGX_DECLINED; | |
416 } | |
417 | |
418 | |
419 static void | |
420 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) | |
421 { | |
2313 | 422 ngx_int_t excess; |
2294 | 423 ngx_time_t *tp; |
424 ngx_msec_t now; | |
425 ngx_queue_t *q; | |
426 ngx_msec_int_t ms; | |
427 ngx_rbtree_node_t *node; | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
428 ngx_http_limit_req_node_t *lr; |
2294 | 429 |
430 tp = ngx_timeofday(); | |
431 | |
432 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
433 | |
434 /* | |
435 * n == 1 deletes one or two zero rate entries | |
436 * n == 0 deletes oldest entry by force | |
437 * and one or two zero rate entries | |
438 */ | |
439 | |
440 while (n < 3) { | |
441 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
442 if (ngx_queue_empty(&ctx->sh->queue)) { |
2294 | 443 return; |
444 } | |
445 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
446 q = ngx_queue_last(&ctx->sh->queue); |
2294 | 447 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
448 lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); |
2294 | 449 |
450 if (n++ != 0) { | |
451 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
452 ms = (ngx_msec_int_t) (now - lr->last); |
2294 | 453 ms = ngx_abs(ms); |
454 | |
455 if (ms < 60000) { | |
456 return; | |
457 } | |
458 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
459 excess = lr->excess - ctx->rate * ms / 1000; |
2294 | 460 |
2313 | 461 if (excess > 0) { |
2294 | 462 return; |
463 } | |
464 } | |
465 | |
466 ngx_queue_remove(q); | |
467 | |
468 node = (ngx_rbtree_node_t *) | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
469 ((u_char *) lr - offsetof(ngx_rbtree_node_t, color)); |
2294 | 470 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
471 ngx_rbtree_delete(&ctx->sh->rbtree, node); |
2294 | 472 |
473 ngx_slab_free_locked(ctx->shpool, node); | |
474 } | |
980 | 475 } |
476 | |
477 | |
478 static ngx_int_t | |
2294 | 479 ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) |
980 | 480 { |
2294 | 481 ngx_http_limit_req_ctx_t *octx = data; |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
482 |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
483 size_t len; |
2294 | 484 ngx_http_limit_req_ctx_t *ctx; |
980 | 485 |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
486 ctx = shm_zone->data; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
487 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
488 if (octx) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
489 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
|
490 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, |
2294 | 491 "limit_req \"%V\" uses the \"%V\" variable " |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
492 "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
|
493 &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
|
494 return NGX_ERROR; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
495 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
496 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
497 ctx->sh = octx->sh; |
2294 | 498 ctx->shpool = octx->shpool; |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
499 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
500 return NGX_OK; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
501 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
502 |
2294 | 503 ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
980 | 504 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
505 if (shm_zone->shm.exists) { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
506 ctx->sh = ctx->shpool->data; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
507 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
508 return NGX_OK; |
980 | 509 } |
510 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
511 ctx->sh = ngx_slab_alloc(ctx->shpool, sizeof(ngx_http_limit_req_shctx_t)); |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
512 if (ctx->sh == NULL) { |
980 | 513 return NGX_ERROR; |
514 } | |
515 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
516 ctx->shpool->data = ctx->sh; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
517 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
518 ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, |
2294 | 519 ngx_http_limit_req_rbtree_insert_value); |
520 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
521 ngx_queue_init(&ctx->sh->queue); |
980 | 522 |
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
|
523 len = sizeof(" in limit_req zone \"\"") + shm_zone->shm.name.len; |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
524 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
525 ctx->shpool->log_ctx = ngx_slab_alloc(ctx->shpool, len); |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
526 if (ctx->shpool->log_ctx == NULL) { |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
527 return NGX_ERROR; |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
528 } |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
529 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
530 ngx_sprintf(ctx->shpool->log_ctx, " in limit_req zone \"%V\"%Z", |
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
|
531 &shm_zone->shm.name); |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
532 |
980 | 533 return NGX_OK; |
534 } | |
535 | |
536 | |
537 static void * | |
2294 | 538 ngx_http_limit_req_create_conf(ngx_conf_t *cf) |
980 | 539 { |
2294 | 540 ngx_http_limit_req_conf_t *conf; |
980 | 541 |
2294 | 542 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t)); |
980 | 543 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
|
544 return NULL; |
980 | 545 } |
546 | |
547 /* | |
548 * set by ngx_pcalloc(): | |
549 * | |
550 * conf->shm_zone = NULL; | |
2375 | 551 * conf->burst = 0; |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
552 * conf->nodelay = 0; |
980 | 553 */ |
554 | |
3185 | 555 conf->limit_log_level = NGX_CONF_UNSET_UINT; |
556 | |
980 | 557 return conf; |
558 } | |
559 | |
560 | |
561 static char * | |
2294 | 562 ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
980 | 563 { |
2294 | 564 ngx_http_limit_req_conf_t *prev = parent; |
565 ngx_http_limit_req_conf_t *conf = child; | |
980 | 566 |
567 if (conf->shm_zone == NULL) { | |
4440 | 568 conf->shm_zone = prev->shm_zone; |
569 conf->burst = prev->burst; | |
570 conf->nodelay = prev->nodelay; | |
980 | 571 } |
572 | |
3185 | 573 ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, |
574 NGX_LOG_ERR); | |
575 | |
576 conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ? | |
577 NGX_LOG_INFO : conf->limit_log_level + 1; | |
578 | |
980 | 579 return NGX_CONF_OK; |
580 } | |
581 | |
582 | |
583 static char * | |
2294 | 584 ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
980 | 585 { |
2294 | 586 u_char *p; |
587 size_t size, len; | |
588 ngx_str_t *value, name, s; | |
589 ngx_int_t rate, scale; | |
590 ngx_uint_t i; | |
591 ngx_shm_zone_t *shm_zone; | |
592 ngx_http_limit_req_ctx_t *ctx; | |
980 | 593 |
594 value = cf->args->elts; | |
595 | |
2294 | 596 ctx = NULL; |
597 size = 0; | |
598 rate = 1; | |
599 scale = 1; | |
600 name.len = 0; | |
601 | |
602 for (i = 1; i < cf->args->nelts; i++) { | |
603 | |
604 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | |
605 | |
606 name.data = value[i].data + 5; | |
607 | |
608 p = (u_char *) ngx_strchr(name.data, ':'); | |
609 | |
610 if (p) { | |
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
|
611 *p = '\0'; |
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
|
612 |
2294 | 613 name.len = p - name.data; |
614 | |
615 p++; | |
616 | |
617 s.len = value[i].data + value[i].len - p; | |
618 s.data = p; | |
619 | |
620 size = ngx_parse_size(&s); | |
621 if (size > 8191) { | |
622 continue; | |
623 } | |
624 } | |
625 | |
626 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
627 "invalid zone size \"%V\"", &value[i]); | |
628 return NGX_CONF_ERROR; | |
629 } | |
630 | |
631 if (ngx_strncmp(value[i].data, "rate=", 5) == 0) { | |
632 | |
633 len = value[i].len; | |
634 p = value[i].data + len - 3; | |
987 | 635 |
2294 | 636 if (ngx_strncmp(p, "r/s", 3) == 0) { |
637 scale = 1; | |
638 len -= 3; | |
639 | |
640 } else if (ngx_strncmp(p, "r/m", 3) == 0) { | |
641 scale = 60; | |
642 len -= 3; | |
643 } | |
644 | |
645 rate = ngx_atoi(value[i].data + 5, len - 5); | |
646 if (rate <= NGX_ERROR) { | |
647 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
648 "invalid rate \"%V\"", &value[i]); | |
649 return NGX_CONF_ERROR; | |
650 } | |
651 | |
652 continue; | |
653 } | |
654 | |
655 if (value[i].data[0] == '$') { | |
987 | 656 |
2294 | 657 value[i].len--; |
658 value[i].data++; | |
659 | |
660 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t)); | |
661 if (ctx == NULL) { | |
662 return NGX_CONF_ERROR; | |
663 } | |
664 | |
665 ctx->index = ngx_http_get_variable_index(cf, &value[i]); | |
666 if (ctx->index == NGX_ERROR) { | |
667 return NGX_CONF_ERROR; | |
668 } | |
669 | |
670 ctx->var = value[i]; | |
671 | |
672 continue; | |
673 } | |
674 | |
675 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
676 "invalid parameter \"%V\"", &value[i]); | |
987 | 677 return NGX_CONF_ERROR; |
678 } | |
679 | |
2294 | 680 if (name.len == 0 || size == 0) { |
681 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
682 "\"%V\" must have \"zone\" parameter", | |
683 &cmd->name); | |
987 | 684 return NGX_CONF_ERROR; |
685 } | |
686 | |
2294 | 687 if (ctx == NULL) { |
980 | 688 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2294 | 689 "no variable is defined for limit_req_zone \"%V\"", |
690 &cmd->name); | |
980 | 691 return NGX_CONF_ERROR; |
692 } | |
693 | |
2313 | 694 ctx->rate = rate * 1000 / scale; |
980 | 695 |
2294 | 696 shm_zone = ngx_shared_memory_add(cf, &name, size, |
697 &ngx_http_limit_req_module); | |
980 | 698 if (shm_zone == NULL) { |
699 return NGX_CONF_ERROR; | |
700 } | |
701 | |
987 | 702 if (shm_zone->data) { |
703 ctx = shm_zone->data; | |
704 | |
705 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
2294 | 706 "limit_req_zone \"%V\" is already bound to variable \"%V\"", |
707 &value[1], &ctx->var); | |
987 | 708 return NGX_CONF_ERROR; |
709 } | |
710 | |
2294 | 711 shm_zone->init = ngx_http_limit_req_init_zone; |
987 | 712 shm_zone->data = ctx; |
980 | 713 |
714 return NGX_CONF_OK; | |
715 } | |
716 | |
717 | |
718 static char * | |
2294 | 719 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
980 | 720 { |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
721 ngx_http_limit_req_conf_t *lrcf = conf; |
980 | 722 |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
723 ngx_int_t burst; |
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
724 ngx_str_t *value, s; |
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
725 ngx_uint_t i; |
2294 | 726 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
727 if (lrcf->shm_zone) { |
2294 | 728 return "is duplicate"; |
729 } | |
980 | 730 |
731 value = cf->args->elts; | |
732 | |
2294 | 733 burst = 0; |
734 | |
735 for (i = 1; i < cf->args->nelts; i++) { | |
736 | |
737 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | |
738 | |
739 s.len = value[i].len - 5; | |
740 s.data = value[i].data + 5; | |
741 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
742 lrcf->shm_zone = ngx_shared_memory_add(cf, &s, 0, |
2294 | 743 &ngx_http_limit_req_module); |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
744 if (lrcf->shm_zone == NULL) { |
2294 | 745 return NGX_CONF_ERROR; |
746 } | |
747 | |
748 continue; | |
749 } | |
750 | |
751 if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { | |
752 | |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
753 burst = ngx_atoi(value[i].data + 6, value[i].len - 6); |
2294 | 754 if (burst <= 0) { |
755 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
756 "invalid burst rate \"%V\"", &value[i]); | |
757 return NGX_CONF_ERROR; | |
758 } | |
759 | |
760 continue; | |
761 } | |
762 | |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
763 if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) { |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
764 lrcf->nodelay = 1; |
2294 | 765 continue; |
766 } | |
767 | |
768 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
769 "invalid parameter \"%V\"", &value[i]); | |
980 | 770 return NGX_CONF_ERROR; |
771 } | |
772 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
773 if (lrcf->shm_zone == NULL) { |
980 | 774 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2294 | 775 "\"%V\" must have \"zone\" parameter", |
776 &cmd->name); | |
980 | 777 return NGX_CONF_ERROR; |
778 } | |
779 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
780 if (lrcf->shm_zone->data == NULL) { |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
781 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2294 | 782 "unknown limit_req_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
|
783 &lrcf->shm_zone->shm.name); |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
784 return NGX_CONF_ERROR; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
785 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
786 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
787 lrcf->burst = burst * 1000; |
980 | 788 |
789 return NGX_CONF_OK; | |
790 } | |
791 | |
792 | |
793 static ngx_int_t | |
2294 | 794 ngx_http_limit_req_init(ngx_conf_t *cf) |
980 | 795 { |
796 ngx_http_handler_pt *h; | |
797 ngx_http_core_main_conf_t *cmcf; | |
798 | |
799 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
800 | |
801 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); | |
802 if (h == NULL) { | |
803 return NGX_ERROR; | |
804 } | |
805 | |
2294 | 806 *h = ngx_http_limit_req_handler; |
980 | 807 |
808 return NGX_OK; | |
809 } |