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