Mercurial > hg > nginx-quic
annotate src/http/modules/ngx_http_limit_req_module.c @ 4664:356c91151658 stable-1.2
Merge of r4618: rewrite escaping fix (ticket #162).
The following code resulted in incorrect escaping of uri and possible
segfault:
location / {
rewrite ^(.*) $1?c=$1;
return 200 "$uri";
}
If there were arguments in a rewrite's replacement string, and length was
actually calculated (due to duplicate captures as in the example above,
or variables present), the is_args flag was set and incorrectly copied
after length calculation. This resulted in escaping applied to the uri part
of the replacement, resulting in incorrect escaping. Additionally, buffer
was allocated without escaping expected, thus this also resulted in buffer
overrun and possible segfault.
author | Maxim Dounin <mdounin@mdounin.ru> |
---|---|
date | Mon, 04 Jun 2012 11:07:19 +0000 |
parents | 778ef9c3fd2d |
children | 21d1e3bcb356 |
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; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
38 ngx_int_t index; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
39 ngx_str_t var; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
40 ngx_http_limit_req_node_t *node; |
2294 | 41 } ngx_http_limit_req_ctx_t; |
987 | 42 |
43 | |
44 typedef struct { | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
45 ngx_shm_zone_t *shm_zone; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
46 /* 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
|
47 ngx_uint_t burst; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
48 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
|
49 } ngx_http_limit_req_limit_t; |
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 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
52 typedef struct { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
53 ngx_array_t limits; |
3185 | 54 ngx_uint_t limit_log_level; |
55 ngx_uint_t delay_log_level; | |
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, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
61 ngx_uint_t hash, u_char *data, size_t len, ngx_uint_t *ep, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
62 ngx_uint_t account); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
63 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
|
64 ngx_uint_t n, ngx_uint_t *ep, ngx_http_limit_req_limit_t **limit); |
2294 | 65 static void ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, |
66 ngx_uint_t n); | |
980 | 67 |
2294 | 68 static void *ngx_http_limit_req_create_conf(ngx_conf_t *cf); |
69 static char *ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, | |
980 | 70 void *child); |
2294 | 71 static char *ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, |
980 | 72 void *conf); |
2294 | 73 static char *ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, |
980 | 74 void *conf); |
2294 | 75 static ngx_int_t ngx_http_limit_req_init(ngx_conf_t *cf); |
980 | 76 |
77 | |
3185 | 78 static ngx_conf_enum_t ngx_http_limit_req_log_levels[] = { |
79 { ngx_string("info"), NGX_LOG_INFO }, | |
80 { ngx_string("notice"), NGX_LOG_NOTICE }, | |
81 { ngx_string("warn"), NGX_LOG_WARN }, | |
82 { ngx_string("error"), NGX_LOG_ERR }, | |
83 { ngx_null_string, 0 } | |
84 }; | |
85 | |
86 | |
2294 | 87 static ngx_command_t ngx_http_limit_req_commands[] = { |
980 | 88 |
2294 | 89 { ngx_string("limit_req_zone"), |
987 | 90 NGX_HTTP_MAIN_CONF|NGX_CONF_TAKE3, |
2294 | 91 ngx_http_limit_req_zone, |
980 | 92 0, |
93 0, | |
94 NULL }, | |
95 | |
2294 | 96 { ngx_string("limit_req"), |
97 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE123, | |
98 ngx_http_limit_req, | |
980 | 99 NGX_HTTP_LOC_CONF_OFFSET, |
100 0, | |
101 NULL }, | |
102 | |
3185 | 103 { ngx_string("limit_req_log_level"), |
104 NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_HTTP_LOC_CONF|NGX_CONF_TAKE1, | |
105 ngx_conf_set_enum_slot, | |
106 NGX_HTTP_LOC_CONF_OFFSET, | |
107 offsetof(ngx_http_limit_req_conf_t, limit_log_level), | |
108 &ngx_http_limit_req_log_levels }, | |
109 | |
980 | 110 ngx_null_command |
111 }; | |
112 | |
113 | |
2294 | 114 static ngx_http_module_t ngx_http_limit_req_module_ctx = { |
980 | 115 NULL, /* preconfiguration */ |
2294 | 116 ngx_http_limit_req_init, /* postconfiguration */ |
980 | 117 |
118 NULL, /* create main configuration */ | |
119 NULL, /* init main configuration */ | |
120 | |
121 NULL, /* create server configuration */ | |
122 NULL, /* merge server configuration */ | |
123 | |
4499
778ef9c3fd2d
Fixed spelling in single-line comments.
Ruslan Ermilov <ru@nginx.com>
parents:
4497
diff
changeset
|
124 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
|
125 ngx_http_limit_req_merge_conf /* merge location configuration */ |
980 | 126 }; |
127 | |
128 | |
2294 | 129 ngx_module_t ngx_http_limit_req_module = { |
980 | 130 NGX_MODULE_V1, |
2294 | 131 &ngx_http_limit_req_module_ctx, /* module context */ |
132 ngx_http_limit_req_commands, /* module directives */ | |
980 | 133 NGX_HTTP_MODULE, /* module type */ |
134 NULL, /* init master */ | |
135 NULL, /* init module */ | |
136 NULL, /* init process */ | |
137 NULL, /* init thread */ | |
138 NULL, /* exit thread */ | |
139 NULL, /* exit process */ | |
140 NULL, /* exit master */ | |
141 NGX_MODULE_V1_PADDING | |
142 }; | |
143 | |
144 | |
145 static ngx_int_t | |
2294 | 146 ngx_http_limit_req_handler(ngx_http_request_t *r) |
980 | 147 { |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
148 size_t len; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
149 uint32_t hash; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
150 ngx_int_t rc; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
151 ngx_uint_t n, excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
152 ngx_msec_t delay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
153 ngx_http_variable_value_t *vv; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
154 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
|
155 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
|
156 ngx_http_limit_req_limit_t *limit, *limits; |
980 | 157 |
2294 | 158 if (r->main->limit_req_set) { |
984
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
159 return NGX_DECLINED; |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
160 } |
dd128232e6ba
count connection once per request
Igor Sysoev <igor@sysoev.ru>
parents:
981
diff
changeset
|
161 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
162 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
|
163 limits = lrcf->limits.elts; |
980 | 164 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
165 excess = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
166 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
167 rc = NGX_DECLINED; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
168 |
4424
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
169 #if (NGX_SUPPRESS_WARN) |
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
170 limit = NULL; |
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
171 #endif |
aacd7356c197
Limit req: unbreak compilation with MSVC.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4420
diff
changeset
|
172 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
173 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
|
174 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
175 limit = &limits[n]; |
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 ctx = limit->shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
178 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
179 vv = ngx_http_get_indexed_variable(r, ctx->index); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
180 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
181 if (vv == NULL || vv->not_found) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
182 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
183 } |
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 len = vv->len; |
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 if (len == 0) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
188 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
189 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
190 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
191 if (len > 65535) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
192 ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
193 "the value of the \"%V\" variable " |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
194 "is more than 65535 bytes: \"%v\"", |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
195 &ctx->var, vv); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
196 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
197 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
198 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
199 hash = ngx_crc32_short(vv->data, len); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
200 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
201 ngx_shmtx_lock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
202 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
203 rc = ngx_http_limit_req_lookup(limit, hash, vv->data, len, &excess, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
204 (n == lrcf->limits.nelts - 1)); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
205 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
206 ngx_shmtx_unlock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
207 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
208 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
|
209 "limit_req[%ui]: %i %ui.%03ui", |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
210 n, rc, excess / 1000, excess % 1000); |
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 if (rc != NGX_AGAIN) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
213 break; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
214 } |
980 | 215 } |
216 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
217 if (rc == NGX_DECLINED) { |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
218 return NGX_DECLINED; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
219 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
220 |
2294 | 221 r->main->limit_req_set = 1; |
980 | 222 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
223 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
|
224 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
225 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
|
226 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
|
227 "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
|
228 excess / 1000, excess % 1000, |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
229 &limit->shm_zone->shm.name); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
230 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
231 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
232 while (n--) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
233 ctx = limits[n].shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
234 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
235 if (ctx->node == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
236 continue; |
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 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
239 ngx_shmtx_lock(&ctx->shpool->mutex); |
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 ctx->node->count--; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
242 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
243 ngx_shmtx_unlock(&ctx->shpool->mutex); |
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 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
|
246 } |
980 | 247 |
248 return NGX_HTTP_SERVICE_UNAVAILABLE; | |
249 } | |
250 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
251 /* rc == NGX_AGAIN || rc == NGX_OK */ |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
252 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
253 if (rc == NGX_AGAIN) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
254 excess = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
255 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
256 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
257 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
|
258 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
259 if (!delay) { |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
260 return NGX_DECLINED; |
2294 | 261 } |
262 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
263 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
|
264 "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
|
265 excess / 1000, excess % 1000, &limit->shm_zone->shm.name); |
2294 | 266 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
267 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
|
268 return NGX_HTTP_INTERNAL_SERVER_ERROR; |
2294 | 269 } |
270 | |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
271 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
|
272 r->write_event_handler = ngx_http_limit_req_delay; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
273 ngx_add_timer(r->connection->write, delay); |
2294 | 274 |
3780
d94d7104f598
change order of limit_req lookup result processing
Igor Sysoev <igor@sysoev.ru>
parents:
3779
diff
changeset
|
275 return NGX_AGAIN; |
980 | 276 } |
277 | |
278 | |
279 static void | |
2294 | 280 ngx_http_limit_req_delay(ngx_http_request_t *r) |
281 { | |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
282 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
|
283 |
2294 | 284 ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, |
2973 | 285 "limit_req delay"); |
2294 | 286 |
2972
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
287 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
|
288 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
289 if (!wev->timedout) { |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
290 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
291 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
|
292 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
|
293 } |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
294 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
295 return; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
296 } |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
297 |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
298 wev->timedout = 0; |
c5ad288f851d
fix client write event handling in ngx_http_limit_req_module
Igor Sysoev <igor@sysoev.ru>
parents:
2912
diff
changeset
|
299 |
2294 | 300 if (ngx_handle_read_event(r->connection->read, 0) != NGX_OK) { |
301 ngx_http_finalize_request(r, NGX_HTTP_INTERNAL_SERVER_ERROR); | |
302 return; | |
303 } | |
304 | |
305 r->read_event_handler = ngx_http_block_reading; | |
306 r->write_event_handler = ngx_http_core_run_phases; | |
307 | |
308 ngx_http_core_run_phases(r); | |
309 } | |
310 | |
311 | |
312 static void | |
313 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
|
314 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
|
315 { |
2294 | 316 ngx_rbtree_node_t **p; |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
317 ngx_http_limit_req_node_t *lrn, *lrnt; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
318 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
319 for ( ;; ) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
320 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
321 if (node->key < temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
322 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
323 p = &temp->left; |
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 } else if (node->key > temp->key) { |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
326 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
327 p = &temp->right; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
328 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
329 } else { /* node->key == temp->key */ |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
330 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
331 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
|
332 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
|
333 |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
334 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
|
335 ? &temp->left : &temp->right; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
336 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
337 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
338 if (*p == sentinel) { |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
339 break; |
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
340 } |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
341 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
342 temp = *p; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
343 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
344 |
1743
4fc402c3ec73
optimize rbtree initialization and insert
Igor Sysoev <igor@sysoev.ru>
parents:
1406
diff
changeset
|
345 *p = node; |
1026
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
346 node->parent = temp; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
347 node->left = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
348 node->right = sentinel; |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
349 ngx_rbt_red(node); |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
350 } |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
351 |
38be15c1379a
fix duplicate rbtree keys case
Igor Sysoev <igor@sysoev.ru>
parents:
1012
diff
changeset
|
352 |
2294 | 353 static ngx_int_t |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
354 ngx_http_limit_req_lookup(ngx_http_limit_req_limit_t *limit, ngx_uint_t hash, |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
355 u_char *data, size_t len, ngx_uint_t *ep, ngx_uint_t account) |
980 | 356 { |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
357 size_t size; |
2313 | 358 ngx_int_t rc, excess; |
2294 | 359 ngx_time_t *tp; |
360 ngx_msec_t now; | |
361 ngx_msec_int_t ms; | |
362 ngx_rbtree_node_t *node, *sentinel; | |
363 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
|
364 ngx_http_limit_req_node_t *lr; |
2294 | 365 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
366 tp = ngx_timeofday(); |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
367 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
368 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
369 ctx = limit->shm_zone->data; |
2294 | 370 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
371 node = ctx->sh->rbtree.root; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
372 sentinel = ctx->sh->rbtree.sentinel; |
980 | 373 |
2294 | 374 while (node != sentinel) { |
375 | |
376 if (hash < node->key) { | |
377 node = node->left; | |
378 continue; | |
379 } | |
380 | |
381 if (hash > node->key) { | |
382 node = node->right; | |
383 continue; | |
384 } | |
385 | |
386 /* hash == node->key */ | |
387 | |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
388 lr = (ngx_http_limit_req_node_t *) &node->color; |
2294 | 389 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
390 rc = ngx_memn2cmp(data, lr->data, len, (size_t) lr->len); |
3191 | 391 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
392 if (rc == 0) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
393 ngx_queue_remove(&lr->queue); |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
394 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
|
395 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
396 ms = (ngx_msec_int_t) (now - lr->last); |
980 | 397 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
398 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
|
399 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
400 if (excess < 0) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
401 excess = 0; |
2294 | 402 } |
403 | |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
404 *ep = excess; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
405 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
406 if ((ngx_uint_t) excess > limit->burst) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
407 return NGX_BUSY; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
408 } |
2294 | 409 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
410 if (account) { |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
411 lr->excess = excess; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
412 lr->last = now; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
413 return NGX_OK; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
414 } |
2294 | 415 |
4497
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
416 lr->count++; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
417 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
418 ctx->node = lr; |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
419 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
420 return NGX_AGAIN; |
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 |
95ab6658654a
Fix of rbtree lookup on hash collisions.
Maxim Dounin <mdounin@mdounin.ru>
parents:
4424
diff
changeset
|
423 node = (rc < 0) ? node->left : node->right; |
980 | 424 } |
425 | |
3779
57aecfdcac3d
an excess was logged as 0.000 if requests were limited without delay:
Igor Sysoev <igor@sysoev.ru>
parents:
3525
diff
changeset
|
426 *ep = 0; |
2294 | 427 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
428 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
|
429 + offsetof(ngx_http_limit_req_node_t, data) |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
430 + len; |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
431 |
4419
7084faa7a4b4
Limit req: number of cleanup calls reduced.
Valentin Bartenev <vbart@nginx.com>
parents:
4418
diff
changeset
|
432 ngx_http_limit_req_expire(ctx, 1); |
7084faa7a4b4
Limit req: number of cleanup calls reduced.
Valentin Bartenev <vbart@nginx.com>
parents:
4418
diff
changeset
|
433 |
4418
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
434 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
|
435 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
436 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
|
437 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
|
438 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
439 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
|
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 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
|
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 } |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
444 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
445 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
|
446 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
447 ngx_rbtree_insert(&ctx->sh->rbtree, node); |
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 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
|
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 ngx_queue_insert_head(&ctx->sh->queue, &lr->queue); |
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->len = (u_char) len; |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
454 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
|
455 |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
456 ngx_memcpy(lr->data, data, len); |
aac79fc948cc
Limit req: allocation and initialization of a new node moved to the lookup
Valentin Bartenev <vbart@nginx.com>
parents:
4417
diff
changeset
|
457 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
458 if (account) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
459 lr->last = now; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
460 lr->count = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
461 return NGX_OK; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
462 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
463 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
464 lr->last = 0; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
465 lr->count = 1; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
466 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
467 ctx->node = lr; |
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 return NGX_AGAIN; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
470 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
471 |
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 static ngx_msec_t |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
474 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
|
475 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
|
476 { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
477 ngx_int_t excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
478 ngx_time_t *tp; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
479 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
|
480 ngx_msec_int_t ms; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
481 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
|
482 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
|
483 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
484 excess = *ep; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
485 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
486 if (excess == 0 || (*limit)->nodelay) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
487 max_delay = 0; |
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 } else { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
490 ctx = (*limit)->shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
491 max_delay = excess * 1000 / ctx->rate; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
492 } |
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 while (n--) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
495 ctx = limits[n].shm_zone->data; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
496 lr = ctx->node; |
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 if (lr == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
499 continue; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
500 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
501 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
502 ngx_shmtx_lock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
503 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
504 tp = ngx_timeofday(); |
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 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
507 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
|
508 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
509 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
|
510 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
511 if (excess < 0) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
512 excess = 0; |
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 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
515 lr->last = now; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
516 lr->excess = excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
517 lr->count--; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
518 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
519 ngx_shmtx_unlock(&ctx->shpool->mutex); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
520 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
521 ctx->node = NULL; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
522 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
523 if (limits[n].nodelay) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
524 continue; |
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 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
527 delay = excess * 1000 / ctx->rate; |
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 if (delay > max_delay) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
530 max_delay = delay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
531 *ep = excess; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
532 *limit = &limits[n]; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
533 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
534 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
535 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
536 return max_delay; |
2294 | 537 } |
538 | |
539 | |
540 static void | |
541 ngx_http_limit_req_expire(ngx_http_limit_req_ctx_t *ctx, ngx_uint_t n) | |
542 { | |
2313 | 543 ngx_int_t excess; |
2294 | 544 ngx_time_t *tp; |
545 ngx_msec_t now; | |
546 ngx_queue_t *q; | |
547 ngx_msec_int_t ms; | |
548 ngx_rbtree_node_t *node; | |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
549 ngx_http_limit_req_node_t *lr; |
2294 | 550 |
551 tp = ngx_timeofday(); | |
552 | |
553 now = (ngx_msec_t) (tp->sec * 1000 + tp->msec); | |
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) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
620 if (ngx_strcmp(ctx->var.data, octx->var.data) != 0) { |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
621 ngx_log_error(NGX_LOG_EMERG, shm_zone->shm.log, 0, |
2294 | 622 "limit_req \"%V\" uses the \"%V\" variable " |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
623 "while previously it used the \"%V\" variable", |
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
|
624 &shm_zone->shm.name, &ctx->var, &octx->var); |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
625 return NGX_ERROR; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
626 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
627 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
628 ctx->sh = octx->sh; |
2294 | 629 ctx->shpool = octx->shpool; |
993
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
630 |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
631 return NGX_OK; |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
632 } |
1b9a4d92173f
pass the inherited shm_zone data
Igor Sysoev <igor@sysoev.ru>
parents:
987
diff
changeset
|
633 |
2294 | 634 ctx->shpool = (ngx_slab_pool_t *) shm_zone->shm.addr; |
980 | 635 |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
636 if (shm_zone->shm.exists) { |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
637 ctx->sh = ctx->shpool->data; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
638 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
639 return NGX_OK; |
980 | 640 } |
641 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
642 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
|
643 if (ctx->sh == NULL) { |
980 | 644 return NGX_ERROR; |
645 } | |
646 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
647 ctx->shpool->data = ctx->sh; |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
648 |
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
649 ngx_rbtree_init(&ctx->sh->rbtree, &ctx->sh->sentinel, |
2294 | 650 ngx_http_limit_req_rbtree_insert_value); |
651 | |
2720
b3b8c66bd520
support attaching to an existent Win32 shared memory
Igor Sysoev <igor@sysoev.ru>
parents:
2716
diff
changeset
|
652 ngx_queue_init(&ctx->sh->queue); |
980 | 653 |
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
|
654 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
|
655 |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
656 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
|
657 if (ctx->shpool->log_ctx == NULL) { |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
658 return NGX_ERROR; |
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
659 } |
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 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
|
662 &shm_zone->shm.name); |
2611
2bce3f6416c6
improve ngx_slab_alloc() error logging
Igor Sysoev <igor@sysoev.ru>
parents:
2376
diff
changeset
|
663 |
980 | 664 return NGX_OK; |
665 } | |
666 | |
667 | |
668 static void * | |
2294 | 669 ngx_http_limit_req_create_conf(ngx_conf_t *cf) |
980 | 670 { |
2294 | 671 ngx_http_limit_req_conf_t *conf; |
980 | 672 |
2294 | 673 conf = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_conf_t)); |
980 | 674 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
|
675 return NULL; |
980 | 676 } |
677 | |
678 /* | |
679 * set by ngx_pcalloc(): | |
680 * | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
681 * conf->limits.elts = NULL; |
980 | 682 */ |
683 | |
3185 | 684 conf->limit_log_level = NGX_CONF_UNSET_UINT; |
685 | |
980 | 686 return conf; |
687 } | |
688 | |
689 | |
690 static char * | |
2294 | 691 ngx_http_limit_req_merge_conf(ngx_conf_t *cf, void *parent, void *child) |
980 | 692 { |
2294 | 693 ngx_http_limit_req_conf_t *prev = parent; |
694 ngx_http_limit_req_conf_t *conf = child; | |
980 | 695 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
696 if (conf->limits.elts == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
697 conf->limits = prev->limits; |
980 | 698 } |
699 | |
3185 | 700 ngx_conf_merge_uint_value(conf->limit_log_level, prev->limit_log_level, |
701 NGX_LOG_ERR); | |
702 | |
703 conf->delay_log_level = (conf->limit_log_level == NGX_LOG_INFO) ? | |
704 NGX_LOG_INFO : conf->limit_log_level + 1; | |
705 | |
980 | 706 return NGX_CONF_OK; |
707 } | |
708 | |
709 | |
710 static char * | |
2294 | 711 ngx_http_limit_req_zone(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
980 | 712 { |
2294 | 713 u_char *p; |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
714 size_t len; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
715 ssize_t size; |
2294 | 716 ngx_str_t *value, name, s; |
717 ngx_int_t rate, scale; | |
718 ngx_uint_t i; | |
719 ngx_shm_zone_t *shm_zone; | |
720 ngx_http_limit_req_ctx_t *ctx; | |
980 | 721 |
722 value = cf->args->elts; | |
723 | |
2294 | 724 ctx = NULL; |
725 size = 0; | |
726 rate = 1; | |
727 scale = 1; | |
728 name.len = 0; | |
729 | |
730 for (i = 1; i < cf->args->nelts; i++) { | |
731 | |
732 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | |
733 | |
734 name.data = value[i].data + 5; | |
735 | |
736 p = (u_char *) ngx_strchr(name.data, ':'); | |
737 | |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
738 if (p == NULL) { |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
739 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
|
740 "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
|
741 return NGX_CONF_ERROR; |
2294 | 742 } |
743 | |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
744 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
|
745 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
746 s.data = p + 1; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
747 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
|
748 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
749 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
|
750 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
751 if (size == NGX_ERROR) { |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
752 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
|
753 "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
|
754 return NGX_CONF_ERROR; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
755 } |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
756 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
757 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
|
758 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
|
759 "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
|
760 return NGX_CONF_ERROR; |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
761 } |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
762 |
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
763 continue; |
2294 | 764 } |
765 | |
766 if (ngx_strncmp(value[i].data, "rate=", 5) == 0) { | |
767 | |
768 len = value[i].len; | |
769 p = value[i].data + len - 3; | |
987 | 770 |
2294 | 771 if (ngx_strncmp(p, "r/s", 3) == 0) { |
772 scale = 1; | |
773 len -= 3; | |
774 | |
775 } else if (ngx_strncmp(p, "r/m", 3) == 0) { | |
776 scale = 60; | |
777 len -= 3; | |
778 } | |
779 | |
780 rate = ngx_atoi(value[i].data + 5, len - 5); | |
781 if (rate <= NGX_ERROR) { | |
782 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
783 "invalid rate \"%V\"", &value[i]); | |
784 return NGX_CONF_ERROR; | |
785 } | |
786 | |
787 continue; | |
788 } | |
789 | |
790 if (value[i].data[0] == '$') { | |
987 | 791 |
2294 | 792 value[i].len--; |
793 value[i].data++; | |
794 | |
795 ctx = ngx_pcalloc(cf->pool, sizeof(ngx_http_limit_req_ctx_t)); | |
796 if (ctx == NULL) { | |
797 return NGX_CONF_ERROR; | |
798 } | |
799 | |
800 ctx->index = ngx_http_get_variable_index(cf, &value[i]); | |
801 if (ctx->index == NGX_ERROR) { | |
802 return NGX_CONF_ERROR; | |
803 } | |
804 | |
805 ctx->var = value[i]; | |
806 | |
807 continue; | |
808 } | |
809 | |
810 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
811 "invalid parameter \"%V\"", &value[i]); | |
987 | 812 return NGX_CONF_ERROR; |
813 } | |
814 | |
4417
9e9d2e06f933
Limit req: improved error handling when parsing "zone" parameter of
Valentin Bartenev <vbart@nginx.com>
parents:
4416
diff
changeset
|
815 if (name.len == 0) { |
2294 | 816 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
817 "\"%V\" must have \"zone\" parameter", | |
818 &cmd->name); | |
987 | 819 return NGX_CONF_ERROR; |
820 } | |
821 | |
2294 | 822 if (ctx == NULL) { |
980 | 823 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
4416
8156a9bfc044
Limit req: error messages fixed.
Valentin Bartenev <vbart@nginx.com>
parents:
4412
diff
changeset
|
824 "no variable is defined for %V \"%V\"", |
8156a9bfc044
Limit req: error messages fixed.
Valentin Bartenev <vbart@nginx.com>
parents:
4412
diff
changeset
|
825 &cmd->name, &name); |
980 | 826 return NGX_CONF_ERROR; |
827 } | |
828 | |
2313 | 829 ctx->rate = rate * 1000 / scale; |
980 | 830 |
2294 | 831 shm_zone = ngx_shared_memory_add(cf, &name, size, |
832 &ngx_http_limit_req_module); | |
980 | 833 if (shm_zone == NULL) { |
834 return NGX_CONF_ERROR; | |
835 } | |
836 | |
987 | 837 if (shm_zone->data) { |
838 ctx = shm_zone->data; | |
839 | |
840 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
4416
8156a9bfc044
Limit req: error messages fixed.
Valentin Bartenev <vbart@nginx.com>
parents:
4412
diff
changeset
|
841 "%V \"%V\" is already bound to variable \"%V\"", |
8156a9bfc044
Limit req: error messages fixed.
Valentin Bartenev <vbart@nginx.com>
parents:
4412
diff
changeset
|
842 &cmd->name, &name, &ctx->var); |
987 | 843 return NGX_CONF_ERROR; |
844 } | |
845 | |
2294 | 846 shm_zone->init = ngx_http_limit_req_init_zone; |
987 | 847 shm_zone->data = ctx; |
980 | 848 |
849 return NGX_CONF_OK; | |
850 } | |
851 | |
852 | |
853 static char * | |
2294 | 854 ngx_http_limit_req(ngx_conf_t *cf, ngx_command_t *cmd, void *conf) |
980 | 855 { |
2374
7b11f9a1bfe1
rename "lz" to "lr" in variable names
Igor Sysoev <igor@sysoev.ru>
parents:
2313
diff
changeset
|
856 ngx_http_limit_req_conf_t *lrcf = conf; |
980 | 857 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
858 ngx_int_t burst; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
859 ngx_str_t *value, s; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
860 ngx_uint_t i, nodelay; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
861 ngx_shm_zone_t *shm_zone; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
862 ngx_http_limit_req_limit_t *limit, *limits; |
980 | 863 |
864 value = cf->args->elts; | |
865 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
866 shm_zone = NULL; |
2294 | 867 burst = 0; |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
868 nodelay = 0; |
2294 | 869 |
870 for (i = 1; i < cf->args->nelts; i++) { | |
871 | |
872 if (ngx_strncmp(value[i].data, "zone=", 5) == 0) { | |
873 | |
874 s.len = value[i].len - 5; | |
875 s.data = value[i].data + 5; | |
876 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
877 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
|
878 &ngx_http_limit_req_module); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
879 if (shm_zone == NULL) { |
2294 | 880 return NGX_CONF_ERROR; |
881 } | |
882 | |
883 continue; | |
884 } | |
885 | |
886 if (ngx_strncmp(value[i].data, "burst=", 6) == 0) { | |
887 | |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
888 burst = ngx_atoi(value[i].data + 6, value[i].len - 6); |
2294 | 889 if (burst <= 0) { |
890 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
891 "invalid burst rate \"%V\"", &value[i]); | |
892 return NGX_CONF_ERROR; | |
893 } | |
894 | |
895 continue; | |
896 } | |
897 | |
2300
159136c9808d
*) correct leaky bucket implementation
Igor Sysoev <igor@sysoev.ru>
parents:
2294
diff
changeset
|
898 if (ngx_strncmp(value[i].data, "nodelay", 7) == 0) { |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
899 nodelay = 1; |
2294 | 900 continue; |
901 } | |
902 | |
903 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, | |
904 "invalid parameter \"%V\"", &value[i]); | |
980 | 905 return NGX_CONF_ERROR; |
906 } | |
907 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
908 if (shm_zone == NULL) { |
980 | 909 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2294 | 910 "\"%V\" must have \"zone\" parameter", |
911 &cmd->name); | |
980 | 912 return NGX_CONF_ERROR; |
913 } | |
914 | |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
915 if (shm_zone->data == NULL) { |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
916 ngx_conf_log_error(NGX_LOG_EMERG, cf, 0, |
2294 | 917 "unknown limit_req_zone \"%V\"", |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
918 &shm_zone->shm.name); |
1011
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
919 return NGX_CONF_ERROR; |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
920 } |
19118c44303f
test length of variable and number of connections
Igor Sysoev <igor@sysoev.ru>
parents:
1002
diff
changeset
|
921 |
4420
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
922 limits = lrcf->limits.elts; |
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 if (limits == NULL) { |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
925 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
|
926 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
|
927 != NGX_OK) |
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 return NGX_CONF_ERROR; |
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 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
932 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
933 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
|
934 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
|
935 return "is duplicate"; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
936 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
937 } |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
938 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
939 limit = ngx_array_push(&lrcf->limits); |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
940 |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
941 limit->shm_zone = shm_zone; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
942 limit->burst = burst * 1000; |
9ce48f9eb85b
Limit req: support for multiple "limit_req" limits.
Valentin Bartenev <vbart@nginx.com>
parents:
4419
diff
changeset
|
943 limit->nodelay = nodelay; |
980 | 944 |
945 return NGX_CONF_OK; | |
946 } | |
947 | |
948 | |
949 static ngx_int_t | |
2294 | 950 ngx_http_limit_req_init(ngx_conf_t *cf) |
980 | 951 { |
952 ngx_http_handler_pt *h; | |
953 ngx_http_core_main_conf_t *cmcf; | |
954 | |
955 cmcf = ngx_http_conf_get_module_main_conf(cf, ngx_http_core_module); | |
956 | |
957 h = ngx_array_push(&cmcf->phases[NGX_HTTP_PREACCESS_PHASE].handlers); | |
958 if (h == NULL) { | |
959 return NGX_ERROR; | |
960 } | |
961 | |
2294 | 962 *h = ngx_http_limit_req_handler; |
980 | 963 |
964 return NGX_OK; | |
965 } |