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 9d21dad0b5a1
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