Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_limit_req_module.c @ 7096:6b6e15bbda92
release-1.13.5 tag
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Tue, 05 Sep 2017 17:59:31 +0300 |
parents | 903fb1ddc07f |
children | bd6563e81cea |
rev | line source |
---|---|
980 | 1 |
2 /* | |
3 * Copyright (C) Igor Sysoev | |
4412 | 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; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
21 ngx_uint_t count; |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
22 u_char data[1]; |
2294 | 23 } ngx_http_limit_req_node_t; |
980 | 24 |
25 | |
26 typedef struct { | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
27 ngx_rbtree_t rbtree; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
28 ngx_rbtree_node_t sentinel; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
29 ngx_queue_t queue; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
30 } ngx_http_limit_req_shctx_t; |
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 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
33 typedef struct { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
34 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
|
35 ngx_slab_pool_t *shpool; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
36 /* 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
|
37 ngx_uint_t rate; |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
38 ngx_http_complex_value_t key; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
39 ngx_http_limit_req_node_t *node; |
2294 | 40 } ngx_http_limit_req_ctx_t; |
987 | 41 |
42 | |
43 typedef struct { | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
44 ngx_shm_zone_t *shm_zone; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
45 /* 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
|
46 ngx_uint_t burst; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
47 ngx_uint_t nodelay; /* unsigned nodelay:1 */ |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
48 } ngx_http_limit_req_limit_t; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
49 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
50 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
51 typedef struct { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
52 ngx_array_t limits; |
3185 | 53 ngx_uint_t limit_log_level; |
54 ngx_uint_t delay_log_level; | |
5117
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
55 ngx_uint_t status_code; |
2294 | 56 } ngx_http_limit_req_conf_t; |
980 | 57 |
58 | |
2294 | 59 static void ngx_http_limit_req_delay(ngx_http_request_t *r); |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
60 static ngx_int_t ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
61 ngx_uint_t hash, ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account); |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
62 static ngx_msec_t ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
63 ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit); |
2294 | 64 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
65 ngx_uint_t n); | |
980 | 66 |
2294 | 67 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); |
68 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, | |
980 | 69 void *child); |
2294 | 70 static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, |
980 | 71 void *conf); |
2294 | 72 static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, |
980 | 73 void *conf); |
2294 | 74 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); |
980 | 75 |
76 | |
3185 | 77 static ngx_conf_enum_t ngx_http_limit_req_log_levels[] = { |
78 { ngx_string("info"), NGX_LOG_INFO }, | |
79 { ngx_string("notice"), NGX_LOG_NOTICE }, | |
80 { ngx_string("warn"), NGX_LOG_WARN }, | |
81 { ngx_string("error"), NGX_LOG_ERR }, | |
82 { ngx_null_string, 0 } | |
83 }; | |
84 | |
85 | |
5117
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
86 static ngx_conf_num_bounds_t ngx_http_limit_req_status_bounds = { |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
87 ngx_conf_check_num_bounds, 400, 599 |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
88 }; |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
89 |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
90 |
2294 | 91 static ngx_command_t ngx_http_limit_req_commands[] = { |
980 | 92 |
2294 | 93 { ngx_string("limit_req_zone"), |
987 | 94 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, |
2294 | 95 ngx_http_limit_req_zone, |
980 | 96 0, |
97 0, | |
98 NULL }, | |
99 | |
2294 | 100 { ngx_string("limit_req"), |
101 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, | |
102 ngx_http_limit_req, | |
980 | 103 NGX_HTTP_LOC_CONF_OFFSET, |
104 0, | |
105 NULL }, | |
106 | |
3185 | 107 { ngx_string("limit_req_log_level"), |
108 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
109 ngx_conf_set_enum_slot, | |
110 NGX_HTTP_LOC_CONF_OFFSET, | |
111 offsetof(ngx_http_limit_req_conf_t, limit_log_level), | |
112 &ngx_http_limit_req_log_levels }, | |
113 | |
5117
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
114 { ngx_string("limit_req_status"), |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
115 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
116 ngx_conf_set_num_slot, |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
117 NGX_HTTP_LOC_CONF_OFFSET, |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
118 offsetof(ngx_http_limit_req_conf_t, status_code), |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
119 &ngx_http_limit_req_status_bounds }, |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
120 |
980 | 121 ngx_null_command |
122 }; | |
123 | |
124 | |
2294 | 125 static ngx_http_module_t ngx_http_limit_req_module_ctx = { |
980 | 126 NULL, /* preconfiguration */ |
2294 | 127 ngx_http_limit_req_init, /* postconfiguration */ |
980 | 128 |
129 NULL, /* create main configuration */ | |
130 NULL, /* init main configuration */ | |
131 | |
132 NULL, /* create server configuration */ | |
133 NULL, /* merge server configuration */ | |
134 | |
4499
778ef9c3fd2d
Fixed spelling in single-line comments.
Ruslan Ermilov <ru@nginx.com>
parents:
4497
diff
changeset
|
135 ngx_http_limit_req_create_conf, /* create location configuration */ |
778ef9c3fd2d
Fixed spelling in single-line comments.
Ruslan Ermilov <ru@nginx.com>
parents:
4497
diff
changeset
|
136 ngx_http_limit_req_merge_conf /* merge location configuration */ |
980 | 137 }; |
138 | |
139 | |
2294 | 140 ngx_module_t ngx_http_limit_req_module = { |
980 | 141 NGX_MODULE_V1, |
2294 | 142 &ngx_http_limit_req_module_ctx, /* module context */ |
143 ngx_http_limit_req_commands, /* module directives */ | |
980 | 144 NGX_HTTP_MODULE, /* module type */ |
145 NULL, /* init master */ | |
146 NULL, /* init module */ | |
147 NULL, /* init process */ | |
148 NULL, /* init thread */ | |
149 NULL, /* exit thread */ | |
150 NULL, /* exit process */ | |
151 NULL, /* exit master */ | |
152 NGX_MODULE_V1_PADDING | |
153 }; | |
154 | |
155 | |
156 static ngx_int_t | |
2294 | 157 ngx_http_limit_req_handler(ngx_http_request_t *r) |
980 | 158 { |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
159 uint32_t hash; |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
160 ngx_str_t key; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
161 ngx_int_t rc; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
162 ngx_uint_t n, excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
163 ngx_msec_t delay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
164 ngx_http_limit_req_ctx_t *ctx; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
165 ngx_http_limit_req_conf_t *lrcf; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
166 ngx_http_limit_req_limit_t *limit, *limits; |
980 | 167 |
2294 | 168 if (r->main->limit_req_set) { |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
169 return NGX_DECLINED; |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
170 } |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
171 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
172 lrcf = ngx_http_get_module_loc_conf(r, ngx_http_limit_req_module); |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
173 limits = lrcf->limits.elts; |
980 | 174 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
175 excess = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
176 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
177 rc = NGX_DECLINED; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
178 |
4424
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
179 #if (NGX_SUPPRESS_WARN) |
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
180 limit = NULL; |
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
181 #endif |
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
182 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
183 for (n = 0; n < lrcf->limits.nelts; n++) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
184 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
185 limit = &limits[n]; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
186 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
187 ctx = limit->shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
188 |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
189 if (ngx_http_complex_value(r, &ctx->key, &key) != NGX_OK) { |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
190 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
191 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
192 |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
193 if (key.len == 0) { |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
194 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
195 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
196 |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
197 if (key.len > 65535) { |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
198 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
199 "the value of the \"%V\" key " |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
200 "is more than 65535 bytes: \"%V\"", |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
201 &ctx->key.value, &key); |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
202 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
203 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
204 |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
205 hash = ngx_crc32_short(key.data, key.len); |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
206 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
207 ngx_shmtx_lock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
208 |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
209 rc = ngx_http_limit_req_lookup(limit, hash, &key, &excess, |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
210 (n == lrcf->limits.nelts - 1)); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
211 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
212 ngx_shmtx_unlock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
213 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
214 ngx_log_debug4(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
215 "limit_req[%ui]: %i %ui.%03ui", |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
216 n, rc, excess / 1000, excess % 1000); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
217 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
218 if (rc != NGX_AGAIN) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
219 break; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
220 } |
980 | 221 } |
222 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
223 if (rc == NGX_DECLINED) { |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
224 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
225 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
226 |
2294 | 227 r->main->limit_req_set = 1; |
980 | 228 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
229 if (rc == NGX_BUSY || rc == NGX_ERROR) { |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
230 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
231 if (rc == NGX_BUSY) { |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
232 ngx_log_error(lrcf->limit_log_level, r->connection->log, 0, |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
233 "limiting requests, excess: %ui.%03ui by zone \"%V\"", |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
234 excess / 1000, excess % 1000, |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
235 &limit->shm_zone->shm.name); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
236 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
237 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
238 while (n--) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
239 ctx = limits[n].shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
240 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
241 if (ctx->node == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
242 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
243 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
244 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
245 ngx_shmtx_lock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
246 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
247 ctx->node->count--; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
248 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
249 ngx_shmtx_unlock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
250 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
251 ctx->node = NULL; |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
252 } |
980 | 253 |
5117
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
254 return lrcf->status_code; |
980 | 255 } |
256 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
257 /* rc == NGX_AGAIN || rc == NGX_OK */ |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
258 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
259 if (rc == NGX_AGAIN) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
260 excess = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
261 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
262 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
263 delay = ngx_http_limit_req_account(limits, n, &excess, &limit); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
264 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
265 if (!delay) { |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
266 return NGX_DECLINED; |
2294 | 267 } |
268 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
269 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
|
270 "delaying request, excess: %ui.%03ui, by zone \"%V\"", |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
271 excess / 1000, excess % 1000, &limit->shm_zone->shm.name); |
2294 | 272 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
273 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
|
274 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
2294 | 275 } |
276 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
277 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
|
278 r->write_event_handler = ngx_http_limit_req_delay; |
6959
7fcf209d40c8
Limit req: fixed delaying subrequests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
6653
diff
changeset
|
279 |
7fcf209d40c8
Limit req: fixed delaying subrequests.
Maxim Dounin <mdounin@mdounin.ru>
parents:
6653
diff
changeset
|
280 r->connection->write->delayed = 1; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
281 ngx_add_timer(r->connection->write, delay); |
2294 | 282 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
283 return NGX_AGAIN; |
980 | 284 } |
285 | |
286 | |
287 static void | |
2294 | 288 ngx_http_limit_req_delay(ngx_http_request_t *r) |
289 { | |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
290 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
|
291 |
2294 | 292 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2973 | 293 "limit_req delay"); |
2294 | 294 |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
295 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
|
296 |
6961
903fb1ddc07f
Moved handling of wev->delayed to the connection event handler.
Maxim Dounin <mdounin@mdounin.ru>
parents:
6959
diff
changeset
|
297 if (wev->delayed) { |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
298 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
299 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
|
300 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
|
301 } |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
302 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
303 return; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
304 } |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
305 |
2294 | 306 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
307 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
308 return; | |
309 } | |
310 | |
311 r->read_event_handler = ngx_http_block_reading; | |
312 r->write_event_handler = ngx_http_core_run_phases; | |
313 | |
314 ngx_http_core_run_phases(r); | |
315 } | |
316 | |
317 | |
318 static void | |
319 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
|
320 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
|
321 { |
2294 | 322 ngx_rbtree_node_t **p; |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
323 ngx_http_limit_req_node_t *lrn, *lrnt; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
324 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
325 for ( ;; ) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
326 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
327 if (node->key < temp->key) { |
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 p = &temp->left; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
330 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
331 } else if (node->key > temp->key) { |
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 p = &temp->right; |
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 } else { /* node->key == temp->key */ |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
336 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
337 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
|
338 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
|
339 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
340 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
|
341 ? &temp->left : &temp->right; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
342 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
343 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
344 if (*p == sentinel) { |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
345 break; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
346 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
347 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
348 temp = *p; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
349 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
350 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
351 *p = node; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
352 node->parent = temp; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
353 node->left = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
354 node->right = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
355 ngx_rbt_red(node); |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
356 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
357 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
358 |
2294 | 359 static ngx_int_t |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
360 ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
361 ngx_str_t *key, ngx_uint_t *ep, ngx_uint_t account) |
980 | 362 { |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
363 size_t size; |
2313 | 364 ngx_int_t rc, excess; |
2294 | 365 ngx_msec_t now; |
366 ngx_msec_int_t ms; | |
367 ngx_rbtree_node_t *node, *sentinel; | |
368 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
|
369 ngx_http_limit_req_node_t *lr; |
2294 | 370 |
6653
7a6456398fc3
Simplified extraction of current time.
Ruslan Ermilov <ru@nginx.com>
parents:
6117
diff
changeset
|
371 now = ngx_current_msec; |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
372 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
373 ctx = limit->shm_zone->data; |
2294 | 374 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
375 node = ctx->sh->rbtree.root; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
376 sentinel = ctx->sh->rbtree.sentinel; |
980 | 377 |
2294 | 378 while (node != sentinel) { |
379 | |
380 if (hash < node->key) { | |
381 node = node->left; | |
382 continue; | |
383 } | |
384 | |
385 if (hash > node->key) { | |
386 node = node->right; | |
387 continue; | |
388 } | |
389 | |
390 /* hash == node->key */ | |
391 | |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
392 lr = (ngx_http_limit_req_node_t *) &node->color; |
2294 | 393 |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
394 rc = ngx_memn2cmp(key->data, lr->data, key->len, (size_t) lr->len); |
3191 | 395 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
396 if (rc == 0) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
397 ngx_queue_remove(&lr->queue); |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
398 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
3183
b87542338ac3
make limit_req to conform to the leaky bucket algorithm
Igor Sysoev <igor@sysoev.ru>
parents:
2973
diff
changeset
|
399 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
400 ms = (ngx_msec_int_t) (now - lr->last); |
980 | 401 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
402 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
403 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
404 if (excess < 0) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
405 excess = 0; |
2294 | 406 } |
407 | |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
408 *ep = excess; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
409 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
410 if ((ngx_uint_t) excess > limit->burst) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
411 return NGX_BUSY; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
412 } |
2294 | 413 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
414 if (account) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
415 lr->excess = excess; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
416 lr->last = now; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
417 return NGX_OK; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
418 } |
2294 | 419 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
420 lr->count++; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
421 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
422 ctx->node = lr; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
423 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
424 return NGX_AGAIN; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
425 } |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
426 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
427 node = (rc < 0) ? node->left : node->right; |
980 | 428 } |
429 | |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
430 *ep = 0; |
2294 | 431 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
432 size = offsetof(ngx_rbtree_node_t, color) |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
433 + offsetof(ngx_http_limit_req_node_t, data) |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
434 + key->len; |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
435 |
4419
7084faa7a4b4
Limit req: number of cleanup calls reduced.
Valentin Bartenev <vbart@nginx.com>
parents:
4418
diff
changeset
|
436 ngx_http_limit_req_expire(ctx, 1); |
7084faa7a4b4
Limit req: number of cleanup calls reduced.
Valentin Bartenev <vbart@nginx.com>
parents:
4418
diff
changeset
|
437 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
438 node = ngx_slab_alloc_locked(ctx->shpool, size); |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
439 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
440 if (node == NULL) { |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
441 ngx_http_limit_req_expire(ctx, 0); |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
442 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
443 node = ngx_slab_alloc_locked(ctx->shpool, size); |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
444 if (node == NULL) { |
5634
5024d29354f1
Core: slab log_nomem flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5411
diff
changeset
|
445 ngx_log_error(NGX_LOG_ALERT, ngx_cycle->log, 0, |
5024d29354f1
Core: slab log_nomem flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5411
diff
changeset
|
446 "could not allocate node%s", ctx->shpool->log_ctx); |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
447 return NGX_ERROR; |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
448 } |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
449 } |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
450 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
451 node->key = hash; |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
452 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
453 lr = (ngx_http_limit_req_node_t *) &node->color; |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
454 |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
455 lr->len = (u_short) key->len; |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
456 lr->excess = 0; |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
457 |
5863
102f85699420
Limit req: reduced number of parameters in the lookup function.
Valentin Bartenev <vbart@nginx.com>
parents:
5862
diff
changeset
|
458 ngx_memcpy(lr->data, key->data, key->len); |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
459 |
4832
949ea3d3cd1a
Limit req: fix of rbtree node insertion on hash collisions.
Valentin Bartenev <vbart@nginx.com>
parents:
4811
diff
changeset
|
460 ngx_rbtree_insert(&ctx->sh->rbtree, node); |
949ea3d3cd1a
Limit req: fix of rbtree node insertion on hash collisions.
Valentin Bartenev <vbart@nginx.com>
parents:
4811
diff
changeset
|
461 |
949ea3d3cd1a
Limit req: fix of rbtree node insertion on hash collisions.
Valentin Bartenev <vbart@nginx.com>
parents:
4811
diff
changeset
|
462 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
949ea3d3cd1a
Limit req: fix of rbtree node insertion on hash collisions.
Valentin Bartenev <vbart@nginx.com>
parents:
4811
diff
changeset
|
463 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
464 if (account) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
465 lr->last = now; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
466 lr->count = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
467 return NGX_OK; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
468 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
469 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
470 lr->last = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
471 lr->count = 1; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
472 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
473 ctx->node = lr; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
474 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
475 return NGX_AGAIN; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
476 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
477 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
478 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
479 static ngx_msec_t |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
480 ngx_http_limit_req_account(ngx_http_limit_req_limit_t *limits, ngx_uint_t n, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
481 ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit) |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
482 { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
483 ngx_int_t excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
484 ngx_msec_t now, delay, max_delay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
485 ngx_msec_int_t ms; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
486 ngx_http_limit_req_ctx_t *ctx; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
487 ngx_http_limit_req_node_t *lr; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
488 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
489 excess = *ep; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
490 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
491 if (excess == 0 || (*limit)->nodelay) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
492 max_delay = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
493 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
494 } else { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
495 ctx = (*limit)->shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
496 max_delay = excess * 1000 / ctx->rate; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
497 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
498 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
499 while (n--) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
500 ctx = limits[n].shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
501 lr = ctx->node; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
502 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
503 if (lr == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
504 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
505 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
506 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
507 ngx_shmtx_lock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
508 |
6653
7a6456398fc3
Simplified extraction of current time.
Ruslan Ermilov <ru@nginx.com>
parents:
6117
diff
changeset
|
509 now = ngx_current_msec; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
510 ms = (ngx_msec_int_t) (now - lr->last); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
511 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
512 excess = lr->excess - ctx->rate * ngx_abs(ms) / 1000 + 1000; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
513 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
514 if (excess < 0) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
515 excess = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
516 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
517 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
518 lr->last = now; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
519 lr->excess = excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
520 lr->count--; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
521 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
522 ngx_shmtx_unlock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
523 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
524 ctx->node = NULL; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
525 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
526 if (limits[n].nodelay) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
527 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
528 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
529 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
530 delay = excess * 1000 / ctx->rate; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
531 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
532 if (delay > max_delay) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
533 max_delay = delay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
534 *ep = excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
535 *limit = &limits[n]; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
536 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
537 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
538 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
539 return max_delay; |
2294 | 540 } |
541 | |
542 | |
543 static void | |
544 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) | |
545 { | |
2313 | 546 ngx_int_t excess; |
2294 | 547 ngx_msec_t now; |
548 ngx_queue_t *q; | |
549 ngx_msec_int_t ms; | |
550 ngx_rbtree_node_t *node; | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
551 ngx_http_limit_req_node_t *lr; |
2294 | 552 |
6653
7a6456398fc3
Simplified extraction of current time.
Ruslan Ermilov <ru@nginx.com>
parents:
6117
diff
changeset
|
553 now = ngx_current_msec; |
2294 | 554 |
555 /* | |
556 * n == 1 deletes one or two zero rate entries | |
557 * n == 0 deletes oldest entry by force | |
558 * and one or two zero rate entries | |
559 */ | |
560 | |
561 while (n < 3) { | |
562 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
563 if (ngx_queue_empty(&ctx->sh->queue)) { |
2294 | 564 return; |
565 } | |
566 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
567 q = ngx_queue_last(&ctx->sh->queue); |
2294 | 568 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
569 lr = ngx_queue_data(q, ngx_http_limit_req_node_t, queue); |
2294 | 570 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
571 if (lr->count) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
572 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
573 /* |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
574 * There is not much sense in looking further, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
575 * because we bump nodes on the lookup stage. |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
576 */ |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
577 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
578 return; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
579 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
580 |
2294 | 581 if (n++ != 0) { |
582 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
583 ms = (ngx_msec_int_t) (now - lr->last); |
2294 | 584 ms = ngx_abs(ms); |
585 | |
586 if (ms < 60000) { | |
587 return; | |
588 } | |
589 | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
590 excess = lr->excess - ctx->rate * ms / 1000; |
2294 | 591 |
2313 | 592 if (excess > 0) { |
2294 | 593 return; |
594 } | |
595 } | |
596 | |
597 ngx_queue_remove(q); | |
598 | |
599 node = (ngx_rbtree_node_t *) | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
600 ((u_char *) lr - offsetof(ngx_rbtree_node_t, color)); |
2294 | 601 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
602 ngx_rbtree_delete(&ctx->sh->rbtree, node); |
2294 | 603 |
604 ngx_slab_free_locked(ctx->shpool, node); | |
605 } | |
980 | 606 } |
607 | |
608 | |
609 static ngx_int_t | |
2294 | 610 ngx_http_limit_req_init_zone(ngx_shm_zone_t *shm_zone, void *data) |
980 | 611 { |
2294 | 612 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
|
613 |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
614 size_t len; |
2294 | 615 ngx_http_limit_req_ctx_t *ctx; |
980 | 616 |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
617 ctx = shm_zone->data; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
618 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
619 if (octx) { |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
620 if (ctx->key.value.len != octx->key.value.len |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
621 || ngx_strncmp(ctx->key.value.data, octx->key.value.data, |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
622 ctx->key.value.len) |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
623 != 0) |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
624 { |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
625 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
626 "limit_req \"%V\" uses the \"%V\" key " |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
627 "while previously it used the \"%V\" key", |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
628 &shm_zone->shm.name, &ctx->key.value, |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
629 &octx->key.value); |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
630 return NGX_ERROR; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
631 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
632 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
633 ctx->sh = octx->sh; |
2294 | 634 ctx->shpool = octx->shpool; |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
635 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
636 return NGX_OK; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
637 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
638 |
2294 | 639 ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
980 | 640 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
641 if (shm_zone->shm.exists) { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
642 ctx->sh = ctx->shpool->data; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
643 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
644 return NGX_OK; |
980 | 645 } |
646 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
647 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
|
648 if (ctx->sh == NULL) { |
980 | 649 return NGX_ERROR; |
650 } | |
651 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
652 ctx->shpool->data = ctx->sh; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
653 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
654 ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, |
2294 | 655 ngx_http_limit_req_rbtree_insert_value); |
656 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
657 ngx_queue_init(&ctx->sh->queue); |
980 | 658 |
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
|
659 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
|
660 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
661 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
|
662 if (ctx->shpool->log_ctx == NULL) { |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
663 return NGX_ERROR; |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
664 } |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
665 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
666 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
|
667 &shm_zone->shm.name); |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
668 |
5634
5024d29354f1
Core: slab log_nomem flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5411
diff
changeset
|
669 ctx->shpool->log_nomem = 0; |
5024d29354f1
Core: slab log_nomem flag.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5411
diff
changeset
|
670 |
980 | 671 return NGX_OK; |
672 } | |
673 | |
674 | |
675 static void * | |
2294 | 676 ngx_http_limit_req_create_conf(ngx_conf_t *cf) |
980 | 677 { |
2294 | 678 ngx_http_limit_req_conf_t *conf; |
980 | 679 |
2294 | 680 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t)); |
980 | 681 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
|
682 return NULL; |
980 | 683 } |
684 | |
685 /* | |
686 * set by ngx_pcalloc(): | |
687 * | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
688 * conf->limits.elts = NULL; |
980 | 689 */ |
690 | |
3185 | 691 conf->limit_log_level = NGX_CONF_UNSET_UINT; |
5117
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
692 conf->status_code = NGX_CONF_UNSET_UINT; |
3185 | 693 |
980 | 694 return conf; |
695 } | |
696 | |
697 | |
698 static char * | |
2294 | 699 ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
980 | 700 { |
2294 | 701 ngx_http_limit_req_conf_t *prev = parent; |
702 ngx_http_limit_req_conf_t *conf = child; | |
980 | 703 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
704 if (conf->limits.elts == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
705 conf->limits = prev->limits; |
980 | 706 } |
707 | |
3185 | 708 ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, |
709 NGX_LOG_ERR); | |
710 | |
711 conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ? | |
712 NGX_LOG_INFO : conf->limit_log_level + 1; | |
713 | |
5117
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
714 ngx_conf_merge_uint_value(conf->status_code, prev->status_code, |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
715 NGX_HTTP_SERVICE_UNAVAILABLE); |
00e4459739ed
The limit_req_status and limit_conn_status directives.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4832
diff
changeset
|
716 |
980 | 717 return NGX_CONF_OK; |
718 } | |
719 | |
720 | |
721 static char * | |
2294 | 722 ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
980 | 723 { |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
724 u_char *p; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
725 size_t len; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
726 ssize_t size; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
727 ngx_str_t *value, name, s; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
728 ngx_int_t rate, scale; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
729 ngx_uint_t i; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
730 ngx_shm_zone_t *shm_zone; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
731 ngx_http_limit_req_ctx_t *ctx; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
732 ngx_http_compile_complex_value_t ccv; |
980 | 733 |
734 value = cf->args->elts; | |
735 | |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
736 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t)); |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
737 if (ctx == NULL) { |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
738 return NGX_CONF_ERROR; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
739 } |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
740 |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
741 ngx_memzero(&ccv, sizeof(ngx_http_compile_complex_value_t)); |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
742 |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
743 ccv.cf = cf; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
744 ccv.value = &value[1]; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
745 ccv.complex_value = &ctx->key; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
746 |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
747 if (ngx_http_compile_complex_value(&ccv) != NGX_OK) { |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
748 return NGX_CONF_ERROR; |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
749 } |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
750 |
2294 | 751 size = 0; |
752 rate = 1; | |
753 scale = 1; | |
754 name.len = 0; | |
755 | |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
756 for (i = 2; i < cf->args->nelts; i++) { |
2294 | 757 |
758 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | |
759 | |
760 name.data = value[i].data + 5; | |
761 | |
762 p = (u_char *) ngx_strchr(name.data, ':'); | |
763 | |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
764 if (p == NULL) { |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
765 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
766 "invalid zone size \"%V\"", &value[i]); |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
767 return NGX_CONF_ERROR; |
2294 | 768 } |
769 | |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
770 name.len = p - name.data; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
771 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
772 s.data = p + 1; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
773 s.len = value[i].data + value[i].len - s.data; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
774 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
775 size = ngx_parse_size(&s); |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
776 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
777 if (size == NGX_ERROR) { |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
778 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
779 "invalid zone size \"%V\"", &value[i]); |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
780 return NGX_CONF_ERROR; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
781 } |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
782 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
783 if (size < (ssize_t) (8 * ngx_pagesize)) { |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
784 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
785 "zone \"%V\" is too small", &value[i]); |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
786 return NGX_CONF_ERROR; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
787 } |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
788 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
789 continue; |
2294 | 790 } |
791 | |
792 if (ngx_strncmp(value[i].data, "rate=", 5) == 0) { | |
793 | |
794 len = value[i].len; | |
795 p = value[i].data + len - 3; | |
987 | 796 |
2294 | 797 if (ngx_strncmp(p, "r/s", 3) == 0) { |
798 scale = 1; | |
799 len -= 3; | |
800 | |
801 } else if (ngx_strncmp(p, "r/m", 3) == 0) { | |
802 scale = 60; | |
803 len -= 3; | |
804 } | |
805 | |
806 rate = ngx_atoi(value[i].data + 5, len - 5); | |
5166
fc595eeb6c54
Limit req: rate should be non-zero.
Valentin Bartenev <vbart@nginx.com>
parents:
5117
diff
changeset
|
807 if (rate <= 0) { |
2294 | 808 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
809 "invalid rate \"%V\"", &value[i]); | |
810 return NGX_CONF_ERROR; | |
811 } | |
812 | |
813 continue; | |
814 } | |
815 | |
816 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
817 "invalid parameter \"%V\"", &value[i]); | |
987 | 818 return NGX_CONF_ERROR; |
819 } | |
820 | |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
821 if (name.len == 0) { |
2294 | 822 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
823 "\"%V\" must have \"zone\" parameter", | |
824 &cmd->name); | |
987 | 825 return NGX_CONF_ERROR; |
826 } | |
827 | |
2313 | 828 ctx->rate = rate * 1000 / scale; |
980 | 829 |
2294 | 830 shm_zone = ngx_shared_memory_add(cf, &name, size, |
831 &ngx_http_limit_req_module); | |
980 | 832 if (shm_zone == NULL) { |
833 return NGX_CONF_ERROR; | |
834 } | |
835 | |
987 | 836 if (shm_zone->data) { |
837 ctx = shm_zone->data; | |
838 | |
839 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
5862
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
840 "%V \"%V\" is already bound to key \"%V\"", |
ecbb99aa0e12
Limit req: use complex value in limit_req_zone.
Valentin Bartenev <vbart@nginx.com>
parents:
5846
diff
changeset
|
841 &cmd->name, &name, &ctx->key.value); |
987 | 842 return NGX_CONF_ERROR; |
843 } | |
844 | |
2294 | 845 shm_zone->init = ngx_http_limit_req_init_zone; |
987 | 846 shm_zone->data = ctx; |
980 | 847 |
848 return NGX_CONF_OK; | |
849 } | |
850 | |
851 | |
852 static char * | |
2294 | 853 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
980 | 854 { |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
855 ngx_http_limit_req_conf_t *lrcf = conf; |
980 | 856 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
857 ngx_int_t burst; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
858 ngx_str_t *value, s; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
859 ngx_uint_t i, nodelay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
860 ngx_shm_zone_t *shm_zone; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
861 ngx_http_limit_req_limit_t *limit, *limits; |
980 | 862 |
863 value = cf->args->elts; | |
864 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
865 shm_zone = NULL; |
2294 | 866 burst = 0; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
867 nodelay = 0; |
2294 | 868 |
869 for (i = 1; i < cf->args->nelts; i++) { | |
870 | |
871 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | |
872 | |
873 s.len = value[i].len - 5; | |
874 s.data = value[i].data + 5; | |
875 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
876 shm_zone = ngx_shared_memory_add(cf, &s, 0, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
877 &ngx_http_limit_req_module); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
878 if (shm_zone == NULL) { |
2294 | 879 return NGX_CONF_ERROR; |
880 } | |
881 | |
882 continue; | |
883 } | |
884 | |
885 if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { | |
886 | |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
887 burst = ngx_atoi(value[i].data + 6, value[i].len - 6); |
2294 | 888 if (burst <= 0) { |
889 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
890 "invalid burst rate \"%V\"", &value[i]); | |
891 return NGX_CONF_ERROR; | |
892 } | |
893 | |
894 continue; | |
895 } | |
896 | |
5411
5483d9e77b32
Limit req: fixed "nodelay" parsing.
Maxim Dounin <mdounin@mdounin.ru>
parents:
5166
diff
changeset
|
897 if (ngx_strcmp(value[i].data, "nodelay") == 0) { |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
898 nodelay = 1; |
2294 | 899 continue; |
900 } | |
901 | |
902 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
903 "invalid parameter \"%V\"", &value[i]); | |
980 | 904 return NGX_CONF_ERROR; |
905 } | |
906 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
907 if (shm_zone == NULL) { |
980 | 908 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2294 | 909 "\"%V\" must have \"zone\" parameter", |
910 &cmd->name); | |
980 | 911 return NGX_CONF_ERROR; |
912 } | |
913 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
914 limits = lrcf->limits.elts; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
915 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
916 if (limits == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
917 if (ngx_array_init(&lrcf->limits, cf->pool, 1, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
918 sizeof(ngx_http_limit_req_limit_t)) |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
919 != NGX_OK) |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
920 { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
921 return NGX_CONF_ERROR; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
922 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
923 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
924 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
925 for (i = 0; i < lrcf->limits.nelts; i++) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
926 if (shm_zone == limits[i].shm_zone) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
927 return "is duplicate"; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
928 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
929 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
930 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
931 limit = ngx_array_push(&lrcf->limits); |
4811
21d1e3bcb356
Added three missing checks for NULL after ngx_array_push() calls.
Valentin Bartenev <vbart@nginx.com>
parents:
4499
diff
changeset
|
932 if (limit == NULL) { |
21d1e3bcb356
Added three missing checks for NULL after ngx_array_push() calls.
Valentin Bartenev <vbart@nginx.com>
parents:
4499
diff
changeset
|
933 return NGX_CONF_ERROR; |
21d1e3bcb356
Added three missing checks for NULL after ngx_array_push() calls.
Valentin Bartenev <vbart@nginx.com>
parents:
4499
diff
changeset
|
934 } |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
935 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
936 limit->shm_zone = shm_zone; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
937 limit->burst = burst * 1000; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
938 limit->nodelay = nodelay; |
980 | 939 |
940 return NGX_CONF_OK; | |
941 } | |
942 | |
943 | |
944 static ngx_int_t | |
2294 | 945 ngx_http_limit_req_init(ngx_conf_t *cf) |
980 | 946 { |
947 ngx_http_handler_pt *h; | |
948 ngx_http_core_main_conf_t *cmcf; | |
949 | |
950 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
951 | |
952 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); | |
953 if (h == NULL) { | |
954 return NGX_ERROR; | |
955 } | |
956 | |
2294 | 957 *h = ngx_http_limit_req_handler; |
980 | 958 |
959 return NGX_OK; | |
960 } |