Mercurial > hg > nginx-vendor-1-0
comparison src/http/modules/ngx_http_limit_req_module.c @ 420:ad0a34a8efa6 NGINX_0_7_22
nginx 0.7.22
*) Feature: the "none" parameter in the "smtp_auth" directive.
Thanks to Maxim Dounin.
*) Feature: the "$cookie_..." variables.
*) Bugfix: the "directio" directive did not work in XFS filesystem.
*) Bugfix: the resolver did not understand big DNS responses.
Thanks to Zyb.
author | Igor Sysoev <http://sysoev.ru> |
---|---|
date | Thu, 20 Nov 2008 00:00:00 +0300 |
parents | ff86d646f9df |
children | e7dbea1ee115 |
comparison
equal
deleted
inserted
replaced
419:b986babf3f57 | 420:ad0a34a8efa6 |
---|---|
13 u_char color; | 13 u_char color; |
14 u_char dummy; | 14 u_char dummy; |
15 u_short len; | 15 u_short len; |
16 ngx_queue_t queue; | 16 ngx_queue_t queue; |
17 ngx_msec_t last; | 17 ngx_msec_t last; |
18 float rate; | 18 ngx_uint_t excess; /* integer value, 1 corresponds to 0.001 r/s */ |
19 u_char data[1]; | 19 u_char data[1]; |
20 } ngx_http_limit_req_node_t; | 20 } ngx_http_limit_req_node_t; |
21 | 21 |
22 | 22 |
23 typedef struct { | 23 typedef struct { |
24 ngx_rbtree_t *rbtree; | 24 ngx_rbtree_t *rbtree; |
25 ngx_queue_t *queue; | 25 ngx_queue_t *queue; |
26 ngx_slab_pool_t *shpool; | 26 ngx_slab_pool_t *shpool; |
27 float rate; | 27 ngx_uint_t rate; /* integer value, 1 corresponds to 0.001 r/s */ |
28 ngx_int_t index; | 28 ngx_int_t index; |
29 ngx_str_t var; | 29 ngx_str_t var; |
30 } ngx_http_limit_req_ctx_t; | 30 } ngx_http_limit_req_ctx_t; |
31 | 31 |
32 | 32 |
33 typedef struct { | 33 typedef struct { |
34 ngx_shm_zone_t *shm_zone; | 34 ngx_shm_zone_t *shm_zone; |
35 float burst; | 35 ngx_uint_t burst; /* integer value, 1 corresponds to 0.001 r/s */ |
36 ngx_uint_t nodelay; /* unsigned nodelay:1 */ | 36 ngx_uint_t nodelay;/* unsigned nodelay:1 */ |
37 } ngx_http_limit_req_conf_t; | 37 } ngx_http_limit_req_conf_t; |
38 | 38 |
39 | 39 |
40 static void ngx_http_limit_req_delay(ngx_http_request_t *r); | 40 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
41 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lzcf, | 41 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lzcf, |
105 | 105 |
106 | 106 |
107 static ngx_int_t | 107 static ngx_int_t |
108 ngx_http_limit_req_handler(ngx_http_request_t *r) | 108 ngx_http_limit_req_handler(ngx_http_request_t *r) |
109 { | 109 { |
110 float rate; | |
111 size_t len, n; | 110 size_t len, n; |
112 uint32_t hash; | 111 uint32_t hash; |
113 ngx_int_t rc; | 112 ngx_int_t rc; |
113 ngx_uint_t excess; | |
114 ngx_time_t *tp; | 114 ngx_time_t *tp; |
115 ngx_rbtree_node_t *node; | 115 ngx_rbtree_node_t *node; |
116 ngx_http_variable_value_t *vv; | 116 ngx_http_variable_value_t *vv; |
117 ngx_http_limit_req_ctx_t *ctx; | 117 ngx_http_limit_req_ctx_t *ctx; |
118 ngx_http_limit_req_node_t *lz; | 118 ngx_http_limit_req_node_t *lz; |
163 if (lz) { | 163 if (lz) { |
164 ngx_queue_remove(&lz->queue); | 164 ngx_queue_remove(&lz->queue); |
165 | 165 |
166 ngx_queue_insert_head(ctx->queue, &lz->queue); | 166 ngx_queue_insert_head(ctx->queue, &lz->queue); |
167 | 167 |
168 rate = lz->rate; | 168 excess = lz->excess; |
169 | 169 |
170 } else { | 170 } else { |
171 rate = 0.0; | 171 excess = 0; |
172 } | 172 } |
173 | 173 |
174 ngx_log_debug2(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, | 174 ngx_log_debug3(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
175 "limit_req: %i %.3f", rc, rate); | 175 "limit_req: %i %ui.%03ui", rc, excess / 1000, excess % 1000); |
176 | 176 |
177 if (rc == NGX_BUSY) { | 177 if (rc == NGX_BUSY) { |
178 ngx_shmtx_unlock(&ctx->shpool->mutex); | 178 ngx_shmtx_unlock(&ctx->shpool->mutex); |
179 | 179 |
180 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, | 180 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
181 "limiting requests, excess: %.3f", rate); | 181 "limiting requests, excess: %ui.%03ui", |
182 excess / 1000, excess % 1000); | |
182 | 183 |
183 return NGX_HTTP_SERVICE_UNAVAILABLE; | 184 return NGX_HTTP_SERVICE_UNAVAILABLE; |
184 } | 185 } |
185 | 186 |
186 if (rc == NGX_AGAIN) { | 187 if (rc == NGX_AGAIN) { |
189 if (lzcf->nodelay) { | 190 if (lzcf->nodelay) { |
190 return NGX_DECLINED; | 191 return NGX_DECLINED; |
191 } | 192 } |
192 | 193 |
193 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, | 194 ngx_log_error(NGX_LOG_WARN, r->connection->log, 0, |
194 "delaying request, excess: %.3f", rate); | 195 "delaying request, excess: %ui.%03ui", |
196 excess / 1000, excess % 1000); | |
195 | 197 |
196 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { | 198 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
197 return NGX_HTTP_INTERNAL_SERVER_ERROR; | 199 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
198 } | 200 } |
199 | 201 |
200 r->read_event_handler = ngx_http_test_reading; | 202 r->read_event_handler = ngx_http_test_reading; |
201 r->write_event_handler = ngx_http_limit_req_delay; | 203 r->write_event_handler = ngx_http_limit_req_delay; |
202 ngx_add_timer(r->connection->write, (ngx_msec_t) (rate * 1000)); | 204 ngx_add_timer(r->connection->write, (ngx_msec_t) excess); |
203 | 205 |
204 return NGX_AGAIN; | 206 return NGX_AGAIN; |
205 } | 207 } |
206 | 208 |
207 if (rc == NGX_OK) { | 209 if (rc == NGX_OK) { |
232 lz->len = (u_char) len; | 234 lz->len = (u_char) len; |
233 | 235 |
234 tp = ngx_timeofday(); | 236 tp = ngx_timeofday(); |
235 lz->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | 237 lz->last = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
236 | 238 |
237 lz->rate = 0.0; | 239 lz->excess = 0; |
238 ngx_memcpy(lz->data, vv->data, len); | 240 ngx_memcpy(lz->data, vv->data, len); |
239 | 241 |
240 ngx_rbtree_insert(ctx->rbtree, node); | 242 ngx_rbtree_insert(ctx->rbtree, node); |
241 | 243 |
242 ngx_queue_insert_head(ctx->queue, &lz->queue); | 244 ngx_queue_insert_head(ctx->queue, &lz->queue); |
310 | 312 |
311 static ngx_int_t | 313 static ngx_int_t |
312 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lzcf, ngx_uint_t hash, | 314 ngx_http_limit_req_lookup(ngx_http_limit_req_conf_t *lzcf, ngx_uint_t hash, |
313 u_char *data, size_t len, ngx_http_limit_req_node_t **lzp) | 315 u_char *data, size_t len, ngx_http_limit_req_node_t **lzp) |
314 { | 316 { |
315 ngx_int_t rc; | 317 ngx_int_t rc, excess; |
316 ngx_time_t *tp; | 318 ngx_time_t *tp; |
317 ngx_msec_t now; | 319 ngx_msec_t now; |
318 ngx_msec_int_t ms; | 320 ngx_msec_int_t ms; |
319 ngx_rbtree_node_t *node, *sentinel; | 321 ngx_rbtree_node_t *node, *sentinel; |
320 ngx_http_limit_req_ctx_t *ctx; | 322 ngx_http_limit_req_ctx_t *ctx; |
349 tp = ngx_timeofday(); | 351 tp = ngx_timeofday(); |
350 | 352 |
351 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | 353 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
352 ms = (ngx_msec_int_t) (now - lz->last); | 354 ms = (ngx_msec_int_t) (now - lz->last); |
353 | 355 |
354 lz->rate = lz->rate - ctx->rate * ngx_abs(ms) / 1000 + 1; | 356 excess = lz->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; |
355 | 357 |
356 if (lz->rate < 0.0) { | 358 if (excess < 0) { |
357 lz->rate = 0.0; | 359 excess = 0; |
358 } | 360 } |
359 | 361 |
362 lz->excess = excess; | |
360 lz->last = now; | 363 lz->last = now; |
361 | 364 |
362 *lzp = lz; | 365 *lzp = lz; |
363 | 366 |
364 if (lz->rate > lzcf->burst) { | 367 if ((ngx_uint_t) excess > lzcf->burst) { |
365 return NGX_BUSY; | 368 return NGX_BUSY; |
366 } | 369 } |
367 | 370 |
368 if (lz->rate > 0.0) { | 371 if (excess) { |
369 return NGX_AGAIN; | 372 return NGX_AGAIN; |
370 } | 373 } |
371 | 374 |
372 return NGX_OK; | 375 return NGX_OK; |
373 } | 376 } |
386 | 389 |
387 | 390 |
388 static void | 391 static void |
389 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) | 392 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) |
390 { | 393 { |
391 float rate; | 394 ngx_int_t excess; |
392 ngx_time_t *tp; | 395 ngx_time_t *tp; |
393 ngx_msec_t now; | 396 ngx_msec_t now; |
394 ngx_queue_t *q; | 397 ngx_queue_t *q; |
395 ngx_msec_int_t ms; | 398 ngx_msec_int_t ms; |
396 ngx_rbtree_node_t *node; | 399 ngx_rbtree_node_t *node; |
423 | 426 |
424 if (ms < 60000) { | 427 if (ms < 60000) { |
425 return; | 428 return; |
426 } | 429 } |
427 | 430 |
428 rate = lz->rate - ctx->rate * ms / 1000; | 431 excess = lz->excess - ctx->rate * ms / 1000; |
429 | 432 |
430 if (rate > 0.0) { | 433 if (excess > 0) { |
431 return; | 434 return; |
432 } | 435 } |
433 } | 436 } |
434 | 437 |
435 ngx_queue_remove(q); | 438 ngx_queue_remove(q); |
639 "no variable is defined for limit_req_zone \"%V\"", | 642 "no variable is defined for limit_req_zone \"%V\"", |
640 &cmd->name); | 643 &cmd->name); |
641 return NGX_CONF_ERROR; | 644 return NGX_CONF_ERROR; |
642 } | 645 } |
643 | 646 |
644 ctx->rate = (float) rate / scale; | 647 ctx->rate = rate * 1000 / scale; |
645 | 648 |
646 shm_zone = ngx_shared_memory_add(cf, &name, size, | 649 shm_zone = ngx_shared_memory_add(cf, &name, size, |
647 &ngx_http_limit_req_module); | 650 &ngx_http_limit_req_module); |
648 if (shm_zone == NULL) { | 651 if (shm_zone == NULL) { |
649 return NGX_CONF_ERROR; | 652 return NGX_CONF_ERROR; |
732 "unknown limit_req_zone \"%V\"", | 735 "unknown limit_req_zone \"%V\"", |
733 &lzcf->shm_zone->name); | 736 &lzcf->shm_zone->name); |
734 return NGX_CONF_ERROR; | 737 return NGX_CONF_ERROR; |
735 } | 738 } |
736 | 739 |
737 lzcf->burst = (float) burst; | 740 lzcf->burst = burst * 1000; |
738 | 741 |
739 return NGX_CONF_OK; | 742 return NGX_CONF_OK; |
740 } | 743 } |
741 | 744 |
742 | 745 |