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