Mercurial > hg > nginx-vendor-1-0
comparison src/http/modules/ngx_http_limit_req_module.c @ 602:c5122335e41d NGINX_0_8_53
nginx 0.8.53
*) Feature: now the "error_page" directive allows to change a status
code in a redirect.
*) Feature: the "gzip_disable" directive supports special "degradation"
mask.
*) Bugfix: a socket leak might occurred if file AIO was used.
Thanks to Maxim Dounin.
*) Bugfix: if the first server had no "listen" directive and there was
no explicit default server, then a next server with a "listen"
directive became the default server; the bug had appeared in 0.8.21.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Mon, 18 Oct 2010 00:00:00 +0400 |
parents | ff463db0be31 |
children | ad25218fd14b |
comparison
equal
deleted
inserted
replaced
601:b2afd36d87f4 | 602:c5122335e41d |
---|---|
49 } ngx_http_limit_req_conf_t; | 49 } ngx_http_limit_req_conf_t; |
50 | 50 |
51 | 51 |
52 static void ngx_http_limit_req_delay(ngx_http_request_t *r); | 52 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
53 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, | 53 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, |
54 ngx_uint_t hash, u_char *data, size_t len, ngx_http_limit_req_node_t **lrp); | 54 ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep); |
55 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, | 55 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
56 ngx_uint_t n); | 56 ngx_uint_t n); |
57 | 57 |
58 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); | 58 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); |
59 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, | 59 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, |
184 | 184 |
185 ngx_shmtx_lock(&ctx->shpool->mutex); | 185 ngx_shmtx_lock(&ctx->shpool->mutex); |
186 | 186 |
187 ngx_http_limit_req_expire(ctx, 1); | 187 ngx_http_limit_req_expire(ctx, 1); |
188 | 188 |
189 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &lr); | 189 rc = ngx_http_limit_req_lookup(lrcf, hash, vv->data, len, &excess); |
190 | |
191 if (lr) { | |
192 ngx_queue_remove(&lr->queue); | |
193 | |
194 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
195 | |
196 excess = lr->excess; | |
197 | |
198 } else { | |
199 excess = 0; | |
200 } | |
201 | 190 |
202 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 191 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
203 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); | 192 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); |
204 | 193 |
194 if (rc == NGX_DECLINED) { | |
195 | |
196 n = offsetof(ngx_rbtree_node_t, color) | |
197 + offsetof(ngx_http_limit_req_node_t, data) | |
198 + len; | |
199 | |
200 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
201 if (node == NULL) { | |
202 | |
203 ngx_http_limit_req_expire(ctx, 0); | |
204 | |
205 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
206 if (node == NULL) { | |
207 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
208 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
209 } | |
210 } | |
211 | |
212 lr = (ngx_http_limit_req_node_t *) &node->color; | |
213 | |
214 node->key = hash; | |
215 lr->len = (u_char) len; | |
216 | |
217 tp = ngx_timeofday(); | |
218 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
219 | |
220 lr->excess = 0; | |
221 ngx_memcpy(lr->data, vv->data, len); | |
222 | |
223 ngx_rbtree_insert(&ctx->sh->rbtree, node); | |
224 | |
225 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
226 | |
227 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
228 | |
229 return NGX_DECLINED; | |
230 } | |
231 | |
232 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
233 | |
234 if (rc == NGX_OK) { | |
235 return NGX_DECLINED; | |
236 } | |
237 | |
205 if (rc == NGX_BUSY) { | 238 if (rc == NGX_BUSY) { |
206 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
207 | |
208 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, | 239 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, |
209 "limiting requests, excess: %ui.%03ui by zone \"%V\"", | 240 "limiting requests, excess: %ui.%03ui by zone \"%V\"", |
210 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); | 241 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
211 | 242 |
212 return NGX_HTTP_SERVICE_UNAVAILABLE; | 243 return NGX_HTTP_SERVICE_UNAVAILABLE; |
213 } | 244 } |
214 | 245 |
215 if (rc == NGX_AGAIN) { | 246 /* rc == NGX_AGAIN */ |
216 ngx_shmtx_unlock(&ctx->shpool->mutex); | 247 |
217 | 248 if (lrcf->nodelay) { |
218 if (lrcf->nodelay) { | 249 return NGX_DECLINED; |
219 return NGX_DECLINED; | 250 } |
220 } | 251 |
221 | 252 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, |
222 ngx_log_error(lrcf->delay_log_level, r->connection->log, 0, | 253 "delaying request, excess: %ui.%03ui, by zone \"%V\"", |
223 "delaying request, excess: %ui.%03ui, by zone \"%V\"", | 254 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); |
224 excess / 1000, excess % 1000, &lrcf->shm_zone->shm.name); | 255 |
225 | 256 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
226 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { | 257 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
227 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 258 } |
228 } | 259 |
229 | 260 r->read_event_handler = ngx_http_test_reading; |
230 r->read_event_handler = ngx_http_test_reading; | 261 r->write_event_handler = ngx_http_limit_req_delay; |
231 r->write_event_handler = ngx_http_limit_req_delay; | 262 ngx_add_timer(r->connection->write, |
232 ngx_add_timer(r->connection->write, | 263 (ngx_msec_t) excess * 1000 / ctx->rate); |
233 (ngx_msec_t) excess * 1000 / ctx->rate); | 264 |
234 | 265 return NGX_AGAIN; |
235 return NGX_AGAIN; | |
236 } | |
237 | |
238 if (rc == NGX_OK) { | |
239 goto done; | |
240 } | |
241 | |
242 /* rc == NGX_DECLINED */ | |
243 | |
244 n = offsetof(ngx_rbtree_node_t, color) | |
245 + offsetof(ngx_http_limit_req_node_t, data) | |
246 + len; | |
247 | |
248 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
249 if (node == NULL) { | |
250 | |
251 ngx_http_limit_req_expire(ctx, 0); | |
252 | |
253 node = ngx_slab_alloc_locked(ctx->shpool, n); | |
254 if (node == NULL) { | |
255 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
256 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
257 } | |
258 } | |
259 | |
260 lr = (ngx_http_limit_req_node_t *) &node->color; | |
261 | |
262 node->key = hash; | |
263 lr->len = (u_char) len; | |
264 | |
265 tp = ngx_timeofday(); | |
266 lr->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
267 | |
268 lr->excess = 0; | |
269 ngx_memcpy(lr->data, vv->data, len); | |
270 | |
271 ngx_rbtree_insert(&ctx->sh->rbtree, node); | |
272 | |
273 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
274 | |
275 done: | |
276 | |
277 ngx_shmtx_unlock(&ctx->shpool->mutex); | |
278 | |
279 return NGX_DECLINED; | |
280 } | 266 } |
281 | 267 |
282 | 268 |
283 static void | 269 static void |
284 ngx_http_limit_req_delay(ngx_http_request_t *r) | 270 ngx_http_limit_req_delay(ngx_http_request_t *r) |
354 } | 340 } |
355 | 341 |
356 | 342 |
357 static ngx_int_t | 343 static ngx_int_t |
358 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, | 344 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lrcf, ngx_uint_t hash, |
359 u_char *data, size_t len, ngx_http_limit_req_node_t **lrp) | 345 u_char *data, size_t len, ngx_uint_t *ep) |
360 { | 346 { |
361 ngx_int_t rc, excess; | 347 ngx_int_t rc, excess; |
362 ngx_time_t *tp; | 348 ngx_time_t *tp; |
363 ngx_msec_t now; | 349 ngx_msec_t now; |
364 ngx_msec_int_t ms; | 350 ngx_msec_int_t ms; |
389 lr = (ngx_http_limit_req_node_t *) &node->color; | 375 lr = (ngx_http_limit_req_node_t *) &node->color; |
390 | 376 |
391 rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); | 377 rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); |
392 | 378 |
393 if (rc == 0) { | 379 if (rc == 0) { |
380 ngx_queue_remove(&lr->queue); | |
381 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); | |
394 | 382 |
395 tp = ngx_timeofday(); | 383 tp = ngx_timeofday(); |
396 | 384 |
397 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | 385 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
398 ms = (ngx_msec_int_t) (now - lr->last); | 386 ms = (ngx_msec_int_t) (now - lr->last); |
401 | 389 |
402 if (excess < 0) { | 390 if (excess < 0) { |
403 excess = 0; | 391 excess = 0; |
404 } | 392 } |
405 | 393 |
394 *ep = excess; | |
395 | |
406 if ((ngx_uint_t) excess > lrcf->burst) { | 396 if ((ngx_uint_t) excess > lrcf->burst) { |
407 *lrp = lr; | |
408 return NGX_BUSY; | 397 return NGX_BUSY; |
409 } | 398 } |
410 | 399 |
411 lr->excess = excess; | 400 lr->excess = excess; |
412 lr->last = now; | 401 lr->last = now; |
413 | |
414 *lrp = lr; | |
415 | 402 |
416 if (excess) { | 403 if (excess) { |
417 return NGX_AGAIN; | 404 return NGX_AGAIN; |
418 } | 405 } |
419 | 406 |
425 } while (node != sentinel && hash == node->key); | 412 } while (node != sentinel && hash == node->key); |
426 | 413 |
427 break; | 414 break; |
428 } | 415 } |
429 | 416 |
430 *lrp = NULL; | 417 *ep = 0; |
431 | 418 |
432 return NGX_DECLINED; | 419 return NGX_DECLINED; |
433 } | 420 } |
434 | 421 |
435 | 422 |