├── CHANGES
├── README
├── check.patch
├── check_1.11.1+.patch
├── check_1.11.5+.patch
├── check_1.12.1+.patch
├── check_1.2.1.patch
├── check_1.2.2+.patch
├── check_1.2.6+.patch
├── check_1.5.12+.patch
├── check_1.7.2+.patch
├── check_1.7.5+.patch
├── check_1.9.2+.patch
├── config
├── doc
├── README.txt
└── README.wiki
├── nginx-sticky-module.patch
├── nginx-tests
└── fastcgi_check.t
├── ngx_http_upstream_check_module.c
├── ngx_http_upstream_check_module.h
├── ngx_http_upstream_jvm_route_module.patch
├── test
├── README
├── inc
│ ├── Module
│ │ ├── AutoInstall.pm
│ │ ├── Install.pm
│ │ └── Install
│ │ │ ├── AutoInstall.pm
│ │ │ ├── Base.pm
│ │ │ ├── Can.pm
│ │ │ ├── Fetch.pm
│ │ │ ├── Include.pm
│ │ │ ├── Makefile.pm
│ │ │ ├── Metadata.pm
│ │ │ ├── TestBase.pm
│ │ │ ├── Win32.pm
│ │ │ └── WriteAll.pm
│ ├── Spiffy.pm
│ └── Test
│ │ ├── Base.pm
│ │ ├── Base
│ │ └── Filter.pm
│ │ ├── Builder.pm
│ │ ├── Builder
│ │ └── Module.pm
│ │ └── More.pm
├── lib
│ └── Test
│ │ ├── Nginx.pm
│ │ └── Nginx
│ │ ├── LWP.pm
│ │ ├── Socket.pm
│ │ └── Util.pm
├── ragel
│ ├── Makefile
│ ├── http11.c
│ ├── http11_parser.c
│ ├── http11_parser.h
│ ├── http11_parser.rl
│ ├── http11_parser_common.rl
│ ├── http11_response.c
│ ├── http11_response.h
│ ├── http11_response.rl
│ ├── http11_response_common.rl
│ ├── ragel_http_client.c
│ └── ragel_http_server.c
├── t
│ ├── check_interface.t
│ ├── http_check.t
│ ├── ssl_hello_check.t
│ └── tcp_check.t
└── test.sh
├── upstream_fair.patch
└── util
├── chomp.rb
├── chomp.sh
├── update-readme.sh
└── wiki2pod.pl
/CHANGES:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/yzprofile/nginx_upstream_check_module/a27c411d39da5bb7449ab33ccf61fe5da3a43a2f/CHANGES
--------------------------------------------------------------------------------
/README:
--------------------------------------------------------------------------------
1 | Name
2 | nginx_http_upstream_check_module - support upstream health check with
3 | Nginx
4 |
5 | Synopsis
6 | http {
7 |
8 | upstream cluster {
9 |
10 | # simple round-robin
11 | server 192.168.0.1:80;
12 | server 192.168.0.2:80;
13 |
14 | check interval=5000 rise=1 fall=3 timeout=4000;
15 |
16 | #check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;
17 |
18 | #check interval=3000 rise=2 fall=5 timeout=1000 type=http;
19 | #check_http_send "HEAD / HTTP/1.0\r\n\r\n";
20 | #check_http_expect_alive http_2xx http_3xx;
21 | }
22 |
23 | server {
24 | listen 80;
25 |
26 | location / {
27 | proxy_pass http://cluster;
28 | }
29 |
30 | location /status {
31 | check_status;
32 |
33 | access_log off;
34 | allow SOME.IP.ADD.RESS;
35 | deny all;
36 | }
37 | }
38 |
39 | }
40 |
41 | Description
42 | Add the support of health check with the upstream servers.
43 |
44 | Directives
45 | check
46 | syntax: *check interval=milliseconds [fall=count] [rise=count]
47 | [timeout=milliseconds] [default_down=true|false]
48 | [type=tcp|http|ssl_hello|mysql|ajp|fastcgi]*
49 |
50 | default: *none, if parameters omitted, default parameters are
51 | interval=30000 fall=5 rise=2 timeout=1000 default_down=true type=tcp*
52 |
53 | context: *upstream*
54 |
55 | description: Add the health check for the upstream servers.
56 |
57 | The parameters' meanings are:
58 |
59 | * *interval*: the check request's interval time.
60 |
61 | * *fall*(fall_count): After fall_count check failures, the server is
62 | marked down.
63 |
64 | * *rise*(rise_count): After rise_count check success, the server is
65 | marked up.
66 |
67 | * *timeout*: the check request's timeout.
68 |
69 | * *default_down*: set initial state of backend server, default is
70 | down.
71 |
72 | * *port*: specify the check port in the backend servers. It can be
73 | different with the original servers port. Default the port is 0 and
74 | it means the same as the original backend server.
75 |
76 | * *type*: the check protocol type:
77 |
78 | 1. *tcp* is a simple tcp socket connect and peek one byte.
79 |
80 | 2. *ssl_hello* sends a client ssl hello packet and receives the
81 | server ssl hello packet.
82 |
83 | 3. *http* sends a http request packet, receives and parses the http
84 | response to diagnose if the upstream server is alive.
85 |
86 | 4. *mysql* connects to the mysql server, receives the greeting
87 | response to diagnose if the upstream server is alive.
88 |
89 | 5. *ajp* sends a AJP Cping packet, receives and parses the AJP
90 | Cpong response to diagnose if the upstream server is alive.
91 |
92 | 6. *fastcgi* send a fastcgi request, receives and parses the
93 | fastcgi response to diagnose if the upstream server is alive.
94 |
95 | check_http_send
96 | syntax: *check_http_send http_packet*
97 |
98 | default: *"GET / HTTP/1.0\r\n\r\n"*
99 |
100 | context: *upstream*
101 |
102 | description: If you set the check type is http, then the check function
103 | will sends this http packet to check the upstream server.
104 |
105 | check_http_expect_alive
106 | syntax: *check_http_expect_alive [ http_2xx | http_3xx | http_4xx |
107 | http_5xx ]*
108 |
109 | default: *http_2xx | http_3xx*
110 |
111 | context: *upstream*
112 |
113 | description: These status codes indicate the upstream server's http
114 | response is ok, the backend is alive.
115 |
116 | check_keepalive_requests
117 | syntax: *check_keepalive_requests num*
118 |
119 | default: *check_keepalive_requests 1*
120 |
121 | context: *upstream*
122 |
123 | description: The directive specifies the number of requests sent on a
124 | connection, the default vaule 1 indicates that nginx will certainly
125 | close the connection after a request.
126 |
127 | check_fastcgi_param
128 | Syntax: *check_fastcgi_params parameter value*
129 |
130 | default: see below
131 |
132 | context: *upstream*
133 |
134 | description: If you set the check type is fastcgi, then the check
135 | function will sends this fastcgi headers to check the upstream server.
136 | The default directive looks like:
137 |
138 | check_fastcgi_param "REQUEST_METHOD" "GET";
139 | check_fastcgi_param "REQUEST_URI" "/";
140 | check_fastcgi_param "SCRIPT_FILENAME" "index.php";
141 |
142 | check_shm_size
143 | syntax: *check_shm_size size*
144 |
145 | default: *1M*
146 |
147 | context: *http*
148 |
149 | description: Default size is one megabytes. If you check thousands of
150 | servers, the shared memory for health check may be not enough, you can
151 | enlarge it with this directive.
152 |
153 | check_status
154 | syntax: *check_status [html|csv|json]*
155 |
156 | default: *none*
157 |
158 | context: *location*
159 |
160 | description: Display the health checking servers' status by HTTP. This
161 | directive should be set in the http block.
162 |
163 | You can specify the default display format. The formats can be `html`,
164 | `csv` or `json`. The default type is `html`. It also supports to specify
165 | the format by the request argument. Suppose your `check_status` location
166 | is '/status', the argument of `format` can change the display page's
167 | format. You can do like this:
168 |
169 | /status?format=html
170 | /status?format=csv
171 | /status?format=json
172 |
173 | At present, you can fetch the list of servers with the same status by
174 | the argument of `status`. For example:
175 |
176 | /status?format=html&status=down
177 | /status?format=csv&status=up
178 |
179 | Below it's the sample html page:
180 |
181 |
183 |
Nginx http upstream check status
184 | Nginx http upstream check status
185 | Check upstream server number: 1, generation: 3
186 | Index |
187 | Upstream |
188 | Name |
189 | Status |
190 | Rise counts |
191 | Fall counts |
192 | Check type |
193 | Check port |
194 | 0 |
195 | backend |
196 | 106.187.48.116:80 |
197 | up |
198 | 39 |
199 | 0 |
200 | http |
201 | 80 |
202 |
203 | Below it's the sample of csv page:
204 |
205 | 0,backend,106.187.48.116:80,up,46,0,http,80
206 |
207 | Below it's the sample of json page:
208 |
209 | {"servers": {
210 | "total": 1,
211 | "generation": 3,
212 | "server": [
213 | {"index": 0, "upstream": "backend", "name": "106.187.48.116:80", "status": "up", "rise": 58, "fall": 0, "type": "http", "port": 80}
214 | ]
215 | }}
216 |
217 | Installation
218 | Download the latest version of the release tarball of this module from
219 | github ()
220 |
221 | Grab the nginx source code from nginx.org (), for
222 | example, the version 1.0.14 (see nginx compatibility), and then build
223 | the source with this module:
224 |
225 | $ wget 'http://nginx.org/download/nginx-1.0.14.tar.gz'
226 | $ tar -xzvf nginx-1.0.14.tar.gz
227 | $ cd nginx-1.0.14/
228 | $ patch -p1 < /path/to/nginx_http_upstream_check_module/check.patch
229 |
230 | $ ./configure --add-module=/path/to/nginx_http_upstream_check_module
231 |
232 | $ make
233 | $ make install
234 |
235 | Note
236 | If you use nginx-1.2.1 or nginx-1.3.0, the nginx upstream round robin
237 | module changed greatly. You should use the patch named
238 | 'check_1.2.1.patch'.
239 |
240 | If you use nginx-1.2.2+ or nginx-1.3.1+, It added the upstream
241 | least_conn module. You should use the patch named 'check_1.2.2+.patch'.
242 |
243 | If you use nginx-1.2.6+ or nginx-1.3.9+, It adjusted the round robin
244 | module. You should use the patch named 'check_1.2.6+.patch'.
245 |
246 | If you use nginx-1.5.12+, You should use the patch named
247 | 'check_1.5.12+.patch'.
248 |
249 | If you use nginx-1.7.2+, You should use the patch named
250 | 'check_1.7.2+.patch'.
251 |
252 | The patch just adds the support for the official Round-Robin, Ip_hash
253 | and least_conn upstream module. But it's easy to expand my module to
254 | other upstream modules. See the patch for detail.
255 |
256 | If you want to add the support for upstream fair module, you can do it
257 | like this:
258 |
259 | $ git clone git://github.com/gnosek/nginx-upstream-fair.git
260 | $ cd nginx-upstream-fair
261 | $ patch -p2 < /path/to/nginx_http_upstream_check_module/upstream_fair.patch
262 | $ cd /path/to/nginx-1.0.14
263 | $ ./configure --add-module=/path/to/nginx_http_upstream_check_module --add-module=/path/to/nginx-upstream-fair-module
264 | $ make
265 | $ make install
266 |
267 | If you want to add the support for nginx sticky module, you can do it
268 | like this:
269 |
270 | $ svn checkout http://nginx-sticky-module.googlecode.com/svn/trunk/ nginx-sticky-module
271 | $ cd nginx-sticky-module
272 | $ patch -p0 < /path/to/nginx_http_upstream_check_module/nginx-sticky-module.patch
273 | $ cd /path/to/nginx-1.0.14
274 | $ ./configure --add-module=/path/to/nginx_http_upstream_check_module --add-module=/path/to/nginx-sticky-module
275 | $ make
276 | $ make install
277 |
278 | Note that, the nginx-sticky-module also needs the original check.patch.
279 |
280 | Compatibility
281 | * The module version 0.1.5 should be compatibility with 0.7.67+
282 |
283 | * The module version 0.1.8 should be compatibility with Nginx-1.0.14+
284 |
285 | Notes
286 | TODO
287 | Known Issues
288 | Changelogs
289 | v0.3
290 | * support keepalive check requests
291 |
292 | * fastcgi check requests
293 |
294 | * json/csv check status page support
295 |
296 | v0.1
297 | * first release
298 |
299 | Authors
300 | Weibin Yao(姚伟斌) *yaoweibin at gmail dot com*
301 |
302 | Matthieu Tourne
303 |
304 | Copyright & License
305 | This README template copy from agentzh ().
306 |
307 | The health check part is borrowed the design of Jack Lindamood's
308 | healthcheck module healthcheck_nginx_upstreams
309 | ();
310 |
311 | This module is licensed under the BSD license.
312 |
313 | Copyright (C) 2014 by Weibin Yao
314 |
315 | Copyright (C) 2010-2014 Alibaba Group Holding Limited
316 |
317 | Copyright (C) 2014 by LiangBin Li
318 |
319 | Copyright (C) 2014 by Zhuo Yuan
320 |
321 | Copyright (C) 2012 by Matthieu Tourne
322 |
323 | All rights reserved.
324 |
325 | Redistribution and use in source and binary forms, with or without
326 | modification, are permitted provided that the following conditions are
327 | met:
328 |
329 | * Redistributions of source code must retain the above copyright
330 | notice, this list of conditions and the following disclaimer.
331 |
332 | * Redistributions in binary form must reproduce the above copyright
333 | notice, this list of conditions and the following disclaimer in the
334 | documentation and/or other materials provided with the distribution.
335 |
336 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
337 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
338 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
339 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
340 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
341 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
342 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
343 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
344 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
345 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
346 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
347 |
348 |
--------------------------------------------------------------------------------
/check.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
2 | index fd9ecbe..d3849b6 100644
3 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
5 | @@ -9,6 +9,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 |
14 | typedef struct {
15 | /* the round robin data must be first */
16 | @@ -182,6 +186,12 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
17 |
18 | if (!peer->down) {
19 |
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
22 | + "get ip_hash peer, check_index: %ui",
23 | + peer->check_index);
24 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
25 | +#endif
26 | if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
27 | break;
28 | }
29 | @@ -190,6 +200,9 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
30 | peer->fails = 0;
31 | break;
32 | }
33 | +#if (NGX_HTTP_UPSTREAM_CHECK)
34 | + }
35 | +#endif
36 | }
37 |
38 | iphp->rrp.tried[n] |= m;
39 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
40 | index afc9b2e..1c0344e 100644
41 | --- a/src/http/ngx_http_upstream_round_robin.c
42 | +++ b/src/http/ngx_http_upstream_round_robin.c
43 | @@ -9,6 +9,9 @@
44 | #include
45 | #include
46 |
47 | +#if (NGX_HTTP_UPSTREAM_CHECK)
48 | +#include "ngx_http_upstream_check_module.h"
49 | +#endif
50 |
51 | static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,
52 | const void *two);
53 | @@ -75,6 +78,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
54 | peers->peer[n].down = server[i].down;
55 | peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
56 | peers->peer[n].current_weight = peers->peer[n].weight;
57 | +
58 | +#if (NGX_HTTP_UPSTREAM_CHECK)
59 | + if (!server[i].down) {
60 | + peers->peer[n].check_index =
61 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
62 | + }
63 | + else {
64 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
65 | + }
66 | +#endif
67 | +
68 | n++;
69 | }
70 | }
71 | @@ -128,6 +142,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
72 | backup->peer[n].max_fails = server[i].max_fails;
73 | backup->peer[n].fail_timeout = server[i].fail_timeout;
74 | backup->peer[n].down = server[i].down;
75 | +
76 | +#if (NGX_HTTP_UPSTREAM_CHECK)
77 | + if (!server[i].down) {
78 | + backup->peer[n].check_index =
79 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
80 | + }
81 | + else {
82 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
83 | + }
84 | +#endif
85 | +
86 | n++;
87 | }
88 | }
89 | @@ -186,6 +211,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
90 | peers->peer[i].current_weight = 1;
91 | peers->peer[i].max_fails = 1;
92 | peers->peer[i].fail_timeout = 10;
93 | +#if (NGX_HTTP_UPSTREAM_CHECK)
94 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
95 | +#endif
96 | }
97 |
98 | us->peer.data = peers;
99 | @@ -302,6 +330,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
100 | peers->peer[0].current_weight = 1;
101 | peers->peer[0].max_fails = 1;
102 | peers->peer[0].fail_timeout = 10;
103 | +#if (NGX_HTTP_UPSTREAM_CHECK)
104 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
105 | +#endif
106 |
107 | } else {
108 |
109 | @@ -334,6 +365,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
110 | peers->peer[i].current_weight = 1;
111 | peers->peer[i].max_fails = 1;
112 | peers->peer[i].fail_timeout = 10;
113 | +#if (NGX_HTTP_UPSTREAM_CHECK)
114 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
115 | +#endif
116 | }
117 | }
118 |
119 | @@ -411,7 +445,11 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
120 |
121 | if (rrp->peers->single) {
122 | peer = &rrp->peers->peer[0];
123 | -
124 | +#if (NGX_HTTP_UPSTREAM_CHECK)
125 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
126 | + return NGX_BUSY;
127 | + }
128 | +#endif
129 | } else {
130 |
131 | /* there are several peers */
132 | @@ -438,6 +476,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
133 |
134 | if (!peer->down) {
135 |
136 | +#if (NGX_HTTP_UPSTREAM_CHECK)
137 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
138 | + "get rr peer, check_index: %ui",
139 | + peer->check_index);
140 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
141 | +#endif
142 | if (peer->max_fails == 0
143 | || peer->fails < peer->max_fails)
144 | {
145 | @@ -448,6 +492,9 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
146 | peer->fails = 0;
147 | break;
148 | }
149 | +#if (NGX_HTTP_UPSTREAM_CHECK)
150 | + }
151 | +#endif
152 |
153 | peer->current_weight = 0;
154 |
155 | @@ -486,6 +533,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
156 |
157 | if (!peer->down) {
158 |
159 | +#if (NGX_HTTP_UPSTREAM_CHECK)
160 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
161 | + "get rr peer2, check_index: %ui",
162 | + peer->check_index);
163 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
164 | +#endif
165 | if (peer->max_fails == 0
166 | || peer->fails < peer->max_fails)
167 | {
168 | @@ -496,6 +549,9 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
169 | peer->fails = 0;
170 | break;
171 | }
172 | +#if (NGX_HTTP_UPSTREAM_CHECK)
173 | + }
174 | +#endif
175 |
176 | peer->current_weight = 0;
177 |
178 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
179 | index 6d285ab..354cca2 100644
180 | --- a/src/http/ngx_http_upstream_round_robin.h
181 | +++ b/src/http/ngx_http_upstream_round_robin.h
182 | @@ -28,6 +28,10 @@ typedef struct {
183 | ngx_uint_t max_fails;
184 | time_t fail_timeout;
185 |
186 | +#if (NGX_HTTP_UPSTREAM_CHECK)
187 | + ngx_uint_t check_index;
188 | +#endif
189 | +
190 | ngx_uint_t down; /* unsigned down:1; */
191 |
192 | #if (NGX_HTTP_SSL)
193 |
--------------------------------------------------------------------------------
/check_1.11.1+.patch:
--------------------------------------------------------------------------------
1 | diff --git src/http/modules/ngx_http_upstream_hash_module.c src/http/modules/ngx_http_upstream_hash_module.c
2 | --- src/http/modules/ngx_http_upstream_hash_module.c 2016-05-31 15:43:51.000000000 +0200
3 | +++ src/http/modules/ngx_http_upstream_hash_module.c 2016-06-22 17:20:19.553955295 +0200
4 | @@ -9,6 +9,9 @@
5 | #include
6 | #include
7 |
8 | +#if (NGX_HTTP_UPSTREAM_CHECK)
9 | +#include "ngx_http_upstream_check_module.h"
10 | +#endif
11 |
12 | typedef struct {
13 | uint32_t hash;
14 | @@ -235,6 +238,16 @@
15 | goto next;
16 | }
17 |
18 | +#if (NGX_HTTP_UPSTREAM_CHECK)
19 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
20 | + "get hash peer, check_index: %ui",
21 | + peer->check_index);
22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
23 | + goto next;
24 | + }
25 | +#endif
26 | +
27 | +
28 | if (peer->max_fails
29 | && peer->fails >= peer->max_fails
30 | && now - peer->checked <= peer->fail_timeout)
31 | @@ -535,6 +548,15 @@
32 | continue;
33 | }
34 |
35 | +#if (NGX_HTTP_UPSTREAM_CHECK)
36 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
37 | + "get consistent_hash peer, check_index: %ui",
38 | + peer->check_index);
39 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
40 | + continue;
41 | + }
42 | +#endif
43 | +
44 | if (peer->server.len != server->len
45 | || ngx_strncmp(peer->server.data, server->data, server->len)
46 | != 0)
47 | diff --git src/http/modules/ngx_http_upstream_ip_hash_module.c src/http/modules/ngx_http_upstream_ip_hash_module.c
48 | --- src/http/modules/ngx_http_upstream_ip_hash_module.c 2016-05-31 15:43:51.000000000 +0200
49 | +++ src/http/modules/ngx_http_upstream_ip_hash_module.c 2016-06-22 17:21:38.465741397 +0200
50 | @@ -9,6 +9,9 @@
51 | #include
52 | #include
53 |
54 | +#if (NGX_HTTP_UPSTREAM_CHECK)
55 | +#include "ngx_http_upstream_check_module.h"
56 | +#endif
57 |
58 | typedef struct {
59 | /* the round robin data must be first */
60 | @@ -205,6 +208,15 @@
61 | goto next;
62 | }
63 |
64 | +#if (NGX_HTTP_UPSTREAM_CHECK)
65 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
66 | + "get ip_hash peer, check_index: %ui",
67 | + peer->check_index);
68 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
69 | + goto next;
70 | + }
71 | +#endif
72 | +
73 | if (peer->max_fails
74 | && peer->fails >= peer->max_fails
75 | && now - peer->checked <= peer->fail_timeout)
76 | diff --git src/http/modules/ngx_http_upstream_least_conn_module.c src/http/modules/ngx_http_upstream_least_conn_module.c
77 | --- src/http/modules/ngx_http_upstream_least_conn_module.c 2016-05-31 15:43:51.000000000 +0200
78 | +++ src/http/modules/ngx_http_upstream_least_conn_module.c 2016-06-22 17:23:04.165509237 +0200
79 | @@ -9,6 +9,10 @@
80 | #include
81 | #include
82 |
83 | +#if (NGX_HTTP_UPSTREAM_CHECK)
84 | +#include "ngx_http_upstream_check_module.h"
85 | +#endif
86 | +
87 |
88 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
89 | ngx_http_upstream_srv_conf_t *us);
90 | @@ -148,6 +152,16 @@
91 | continue;
92 | }
93 |
94 | +#if (NGX_HTTP_UPSTREAM_CHECK)
95 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
96 | + "get least_conn peer, check_index: %ui",
97 | + peer->check_index);
98 | +
99 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
100 | + continue;
101 | + }
102 | +#endif
103 | +
104 | if (peer->max_fails
105 | && peer->fails >= peer->max_fails
106 | && now - peer->checked <= peer->fail_timeout)
107 | @@ -199,6 +213,16 @@
108 | continue;
109 | }
110 |
111 | +#if (NGX_HTTP_UPSTREAM_CHECK)
112 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
113 | + "get least_conn peer, check_index: %ui",
114 | + peer->check_index);
115 | +
116 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
117 | + continue;
118 | + }
119 | +#endif
120 | +
121 | if (peer->conns * best->weight != best->conns * peer->weight) {
122 | continue;
123 | }
124 |
125 | diff --git src/http/ngx_http_upstream_round_robin.c src/http/ngx_http_upstream_round_robin.c
126 | --- src/http/ngx_http_upstream_round_robin.c 2016-05-31 15:43:51.000000000 +0200
127 | +++ src/http/ngx_http_upstream_round_robin.c 2016-06-22 17:27:03.200862423 +0200
128 | @@ -9,6 +9,9 @@
129 | #include
130 | #include
131 |
132 | +#if (NGX_HTTP_UPSTREAM_CHECK)
133 | +#include "ngx_http_upstream_check_module.h"
134 | +#endif
135 |
136 | #define ngx_http_upstream_tries(p) ((p)->number \
137 | + ((p)->next ? (p)->next->number : 0))
138 | @@ -96,7 +99,14 @@
139 | peer[n].fail_timeout = server[i].fail_timeout;
140 | peer[n].down = server[i].down;
141 | peer[n].server = server[i].name;
142 | -
143 | +#if (NGX_HTTP_UPSTREAM_CHECK)
144 | + if (!server[i].down) {
145 | + peer[n].check_index =
146 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
147 | + } else {
148 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
149 | + }
150 | +#endif
151 | *peerp = &peer[n];
152 | peerp = &peer[n].next;
153 | n++;
154 | @@ -159,7 +169,15 @@
155 | peer[n].fail_timeout = server[i].fail_timeout;
156 | peer[n].down = server[i].down;
157 | peer[n].server = server[i].name;
158 | -
159 | +#if (NGX_HTTP_UPSTREAM_CHECK)
160 | + if (!server[i].down) {
161 | + peer[n].check_index =
162 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
163 | + }
164 | + else {
165 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
166 | + }
167 | +#endif
168 | *peerp = &peer[n];
169 | peerp = &peer[n].next;
170 | n++;
171 | @@ -225,6 +243,9 @@
172 | peer[i].current_weight = 0;
173 | peer[i].max_fails = 1;
174 | peer[i].fail_timeout = 10;
175 | +#if (NGX_HTTP_UPSTREAM_CHECK)
176 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
177 | +#endif
178 | *peerp = &peer[i];
179 | peerp = &peer[i].next;
180 | }
181 | @@ -339,6 +360,9 @@
182 | peer[0].current_weight = 0;
183 | peer[0].max_fails = 1;
184 | peer[0].fail_timeout = 10;
185 | +#if (NGX_HTTP_UPSTREAM_CHECK)
186 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR;
187 | +#endif
188 | peers->peer = peer;
189 |
190 | } else {
191 | @@ -381,6 +405,9 @@
192 | peer[i].current_weight = 0;
193 | peer[i].max_fails = 1;
194 | peer[i].fail_timeout = 10;
195 | +#if (NGX_HTTP_UPSTREAM_CHECK)
196 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
197 | +#endif
198 | *peerp = &peer[i];
199 | peerp = &peer[i].next;
200 | }
201 | @@ -441,6 +468,12 @@
202 | goto failed;
203 | }
204 |
205 | +#if (NGX_HTTP_UPSTREAM_CHECK)
206 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
207 | + goto failed;
208 | + }
209 | +#endif
210 | +
211 | rrp->current = peer;
212 |
213 | } else {
214 | @@ -542,6 +575,12 @@
215 | continue;
216 | }
217 |
218 | +#if (NGX_HTTP_UPSTREAM_CHECK)
219 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
220 | + continue;
221 | + }
222 | +#endif
223 | +
224 | if (peer->max_fails
225 | && peer->fails >= peer->max_fails
226 | && now - peer->checked <= peer->fail_timeout)
227 | diff --git src/http/ngx_http_upstream_round_robin.h src/http/ngx_http_upstream_round_robin.h
228 | --- src/http/ngx_http_upstream_round_robin.h 2016-05-31 15:43:51.000000000 +0200
229 | +++ src/http/ngx_http_upstream_round_robin.h 2016-06-22 17:27:47.316743162 +0200
230 | @@ -35,6 +35,10 @@
231 | ngx_uint_t max_fails;
232 | time_t fail_timeout;
233 |
234 | +#if (NGX_HTTP_UPSTREAM_CHECK)
235 | + ngx_uint_t check_index;
236 | +#endif
237 | +
238 | ngx_uint_t down; /* unsigned down:1; */
239 |
240 | #if (NGX_HTTP_SSL)
241 |
242 |
--------------------------------------------------------------------------------
/check_1.11.5+.patch:
--------------------------------------------------------------------------------
1 | diff --git src/http/modules/ngx_http_upstream_hash_module.c src/http/modules/ngx_http_upstream_hash_module.c
2 | --- src/http/modules/ngx_http_upstream_hash_module.c
3 | +++ src/http/modules/ngx_http_upstream_hash_module.c
4 | @@ -9,6 +9,9 @@
5 | #include
6 | #include
7 |
8 | +#if (NGX_HTTP_UPSTREAM_CHECK)
9 | +#include "ngx_http_upstream_check_module.h"
10 | +#endif
11 |
12 | typedef struct {
13 | uint32_t hash;
14 | @@ -235,6 +238,16 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
15 | goto next;
16 | }
17 |
18 | +#if (NGX_HTTP_UPSTREAM_CHECK)
19 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
20 | + "get hash peer, check_index: %ui",
21 | + peer->check_index);
22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
23 | + goto next;
24 | + }
25 | +#endif
26 | +
27 | +
28 | if (peer->max_fails
29 | && peer->fails >= peer->max_fails
30 | && now - peer->checked <= peer->fail_timeout)
31 | @@ -538,6 +551,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
32 | continue;
33 | }
34 |
35 | +#if (NGX_HTTP_UPSTREAM_CHECK)
36 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
37 | + "get consistent_hash peer, check_index: %ui",
38 | + peer->check_index);
39 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
40 | + continue;
41 | + }
42 | +#endif
43 | +
44 | if (peer->server.len != server->len
45 | || ngx_strncmp(peer->server.data, server->data, server->len)
46 | != 0)
47 | diff --git src/http/modules/ngx_http_upstream_ip_hash_module.c src/http/modules/ngx_http_upstream_ip_hash_module.c
48 | --- src/http/modules/ngx_http_upstream_ip_hash_module.c
49 | +++ src/http/modules/ngx_http_upstream_ip_hash_module.c
50 | @@ -9,6 +9,9 @@
51 | #include
52 | #include
53 |
54 | +#if (NGX_HTTP_UPSTREAM_CHECK)
55 | +#include "ngx_http_upstream_check_module.h"
56 | +#endif
57 |
58 | typedef struct {
59 | /* the round robin data must be first */
60 | @@ -205,6 +208,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
61 | goto next;
62 | }
63 |
64 | +#if (NGX_HTTP_UPSTREAM_CHECK)
65 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
66 | + "get ip_hash peer, check_index: %ui",
67 | + peer->check_index);
68 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
69 | + goto next;
70 | + }
71 | +#endif
72 | +
73 | if (peer->max_fails
74 | && peer->fails >= peer->max_fails
75 | && now - peer->checked <= peer->fail_timeout)
76 | diff --git src/http/modules/ngx_http_upstream_least_conn_module.c src/http/modules/ngx_http_upstream_least_conn_module.c
77 | --- src/http/modules/ngx_http_upstream_least_conn_module.c
78 | +++ src/http/modules/ngx_http_upstream_least_conn_module.c
79 | @@ -9,6 +9,10 @@
80 | #include
81 | #include
82 |
83 | +#if (NGX_HTTP_UPSTREAM_CHECK)
84 | +#include "ngx_http_upstream_check_module.h"
85 | +#endif
86 | +
87 |
88 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
89 | ngx_http_upstream_srv_conf_t *us);
90 | @@ -147,6 +151,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
91 | continue;
92 | }
93 |
94 | +#if (NGX_HTTP_UPSTREAM_CHECK)
95 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
96 | + "get least_conn peer, check_index: %ui",
97 | + peer->check_index);
98 | +
99 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
100 | + continue;
101 | + }
102 | +#endif
103 | +
104 | if (peer->max_fails
105 | && peer->fails >= peer->max_fails
106 | && now - peer->checked <= peer->fail_timeout)
107 | @@ -202,6 +216,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
108 | continue;
109 | }
110 |
111 | +#if (NGX_HTTP_UPSTREAM_CHECK)
112 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
113 | + "get least_conn peer, check_index: %ui",
114 | + peer->check_index);
115 | +
116 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
117 | + continue;
118 | + }
119 | +#endif
120 | +
121 | if (peer->conns * best->weight != best->conns * peer->weight) {
122 | continue;
123 | }
124 | diff --git src/http/ngx_http_upstream_round_robin.c src/http/ngx_http_upstream_round_robin.c
125 | --- src/http/ngx_http_upstream_round_robin.c
126 | +++ src/http/ngx_http_upstream_round_robin.c
127 | @@ -9,6 +9,9 @@
128 | #include
129 | #include
130 |
131 | +#if (NGX_HTTP_UPSTREAM_CHECK)
132 | +#include "ngx_http_upstream_check_module.h"
133 | +#endif
134 |
135 | #define ngx_http_upstream_tries(p) ((p)->number \
136 | + ((p)->next ? (p)->next->number : 0))
137 | @@ -97,7 +100,14 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
138 | peer[n].fail_timeout = server[i].fail_timeout;
139 | peer[n].down = server[i].down;
140 | peer[n].server = server[i].name;
141 | -
142 | +#if (NGX_HTTP_UPSTREAM_CHECK)
143 | + if (!server[i].down) {
144 | + peer[n].check_index =
145 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
146 | + } else {
147 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
148 | + }
149 | +#endif
150 | *peerp = &peer[n];
151 | peerp = &peer[n].next;
152 | n++;
153 | @@ -161,7 +171,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
154 | peer[n].fail_timeout = server[i].fail_timeout;
155 | peer[n].down = server[i].down;
156 | peer[n].server = server[i].name;
157 | -
158 | +#if (NGX_HTTP_UPSTREAM_CHECK)
159 | + if (!server[i].down) {
160 | + peer[n].check_index =
161 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
162 | + }
163 | + else {
164 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
165 | + }
166 | +#endif
167 | *peerp = &peer[n];
168 | peerp = &peer[n].next;
169 | n++;
170 | @@ -228,6 +246,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
171 | peer[i].max_conns = 0;
172 | peer[i].max_fails = 1;
173 | peer[i].fail_timeout = 10;
174 | +#if (NGX_HTTP_UPSTREAM_CHECK)
175 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
176 | +#endif
177 | *peerp = &peer[i];
178 | peerp = &peer[i].next;
179 | }
180 | @@ -344,6 +365,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
181 | peer[0].max_conns = 0;
182 | peer[0].max_fails = 1;
183 | peer[0].fail_timeout = 10;
184 | +#if (NGX_HTTP_UPSTREAM_CHECK)
185 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR;
186 | +#endif
187 | peers->peer = peer;
188 |
189 | } else {
190 | @@ -378,6 +402,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
191 | peer[i].max_conns = 0;
192 | peer[i].max_fails = 1;
193 | peer[i].fail_timeout = 10;
194 | +#if (NGX_HTTP_UPSTREAM_CHECK)
195 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
196 | +#endif
197 | *peerp = &peer[i];
198 | peerp = &peer[i].next;
199 | }
200 | @@ -443,6 +470,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
201 | goto failed;
202 | }
203 |
204 | +#if (NGX_HTTP_UPSTREAM_CHECK)
205 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
206 | + goto failed;
207 | + }
208 | +#endif
209 | +
210 | rrp->current = peer;
211 |
212 | } else {
213 | @@ -537,6 +570,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
214 | continue;
215 | }
216 |
217 | +#if (NGX_HTTP_UPSTREAM_CHECK)
218 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
219 | + continue;
220 | + }
221 | +#endif
222 | +
223 | if (peer->max_fails
224 | && peer->fails >= peer->max_fails
225 | && now - peer->checked <= peer->fail_timeout)
226 | diff --git src/http/ngx_http_upstream_round_robin.h src/http/ngx_http_upstream_round_robin.h
227 | --- src/http/ngx_http_upstream_round_robin.h
228 | +++ src/http/ngx_http_upstream_round_robin.h
229 | @@ -38,6 +38,10 @@ struct ngx_http_upstream_rr_peer_s {
230 | ngx_msec_t slow_start;
231 | ngx_msec_t start_time;
232 |
233 | +#if (NGX_HTTP_UPSTREAM_CHECK)
234 | + ngx_uint_t check_index;
235 | +#endif
236 | +
237 | ngx_uint_t down;
238 |
239 | #if (NGX_HTTP_SSL || NGX_COMPAT)
240 |
--------------------------------------------------------------------------------
/check_1.12.1+.patch:
--------------------------------------------------------------------------------
1 | diff -burN nginx-1.12.1_orig/src/http/modules/ngx_http_upstream_hash_module.c nginx-1.12.1/src/http/modules/ngx_http_upstream_hash_module.c
2 | --- nginx-1.12.1_orig/src/http/modules/ngx_http_upstream_hash_module.c 2017-07-11 13:24:08.000000000 +0000
3 | +++ nginx-1.12.1/src/http/modules/ngx_http_upstream_hash_module.c 2017-07-13 17:58:44.687213233 +0000
4 | @@ -9,6 +9,9 @@
5 | #include
6 | #include
7 |
8 | +#if (NGX_HTTP_UPSTREAM_CHECK)
9 | +#include "ngx_http_upstream_check_module.h"
10 | +#endif
11 |
12 | typedef struct {
13 | uint32_t hash;
14 | @@ -235,6 +238,14 @@
15 | goto next;
16 | }
17 |
18 | +#if (NGX_HTTP_UPSTREAM_CHECK)
19 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
20 | + "get hash peer, check_index: %ui", peer->check_index);
21 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
22 | + goto next;
23 | + }
24 | +#endif
25 | +
26 | if (peer->max_fails
27 | && peer->fails >= peer->max_fails
28 | && now - peer->checked <= peer->fail_timeout)
29 | @@ -538,6 +549,15 @@
30 | continue;
31 | }
32 |
33 | +#if (NGX_HTTP_UPSTREAM_CHECK)
34 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
35 | + "get consistent_hash peer, check_index: %ui",
36 | + peer->check_index);
37 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
38 | + continue;
39 | + }
40 | +#endif
41 | +
42 | if (peer->server.len != server->len
43 | || ngx_strncmp(peer->server.data, server->data, server->len)
44 | != 0)
45 | diff -burN nginx-1.12.1_orig/src/http/modules/ngx_http_upstream_ip_hash_module.c nginx-1.12.1/src/http/modules/ngx_http_upstream_ip_hash_module.c
46 | --- nginx-1.12.1_orig/src/http/modules/ngx_http_upstream_ip_hash_module.c 2017-07-11 13:24:08.000000000 +0000
47 | +++ nginx-1.12.1/src/http/modules/ngx_http_upstream_ip_hash_module.c 2017-07-13 17:59:48.205692500 +0000
48 | @@ -9,6 +9,9 @@
49 | #include
50 | #include
51 |
52 | +#if (NGX_HTTP_UPSTREAM_CHECK)
53 | +#include "ngx_http_upstream_check_module.h"
54 | +#endif
55 |
56 | typedef struct {
57 | /* the round robin data must be first */
58 | @@ -205,6 +208,15 @@
59 | goto next;
60 | }
61 |
62 | +#if (NGX_HTTP_UPSTREAM_CHECK)
63 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
64 | + "get ip_hash peer, check_index: %ui",
65 | + peer->check_index);
66 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
67 | + goto next;
68 | + }
69 | +#endif
70 | +
71 | if (peer->max_fails
72 | && peer->fails >= peer->max_fails
73 | && now - peer->checked <= peer->fail_timeout)
74 | diff -burN nginx-1.12.1_orig/src/http/modules/ngx_http_upstream_least_conn_module.c nginx-1.12.1/src/http/modules/ngx_http_upstream_least_conn_module.c
75 | --- nginx-1.12.1_orig/src/http/modules/ngx_http_upstream_least_conn_module.c 2017-07-11 13:24:08.000000000 +0000
76 | +++ nginx-1.12.1/src/http/modules/ngx_http_upstream_least_conn_module.c 2017-07-13 18:05:34.417398156 +0000
77 | @@ -9,6 +9,10 @@
78 | #include
79 | #include
80 |
81 | +#if (NGX_HTTP_UPSTREAM_CHECK)
82 | +#include "ngx_http_upstream_check_module.h"
83 | +#endif
84 | +
85 |
86 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
87 | ngx_http_upstream_srv_conf_t *us);
88 | @@ -147,6 +151,16 @@
89 | continue;
90 | }
91 |
92 | +#if (NGX_HTTP_UPSTREAM_CHECK)
93 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
94 | + "get least_conn peer, check_index: %ui",
95 | + peer->check_index);
96 | +
97 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
98 | + continue;
99 | + }
100 | +#endif
101 | +
102 | if (peer->max_fails
103 | && peer->fails >= peer->max_fails
104 | && now - peer->checked <= peer->fail_timeout)
105 | @@ -202,6 +216,16 @@
106 | continue;
107 | }
108 |
109 | +#if (NGX_HTTP_UPSTREAM_CHECK)
110 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
111 | + "get least_conn peer, check_index: %ui",
112 | + peer->check_index);
113 | +
114 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
115 | + continue;
116 | + }
117 | +#endif
118 | +
119 | if (peer->conns * best->weight != best->conns * peer->weight) {
120 | continue;
121 | }
122 | diff -burN nginx-1.12.1_orig/src/http/ngx_http_upstream_round_robin.c nginx-1.12.1/src/http/ngx_http_upstream_round_robin.c
123 | --- nginx-1.12.1_orig/src/http/ngx_http_upstream_round_robin.c 2017-07-11 13:24:09.000000000 +0000
124 | +++ nginx-1.12.1/src/http/ngx_http_upstream_round_robin.c 2017-07-13 18:13:00.510764315 +0000
125 | @@ -9,6 +9,10 @@
126 | #include
127 | #include
128 |
129 | +#if (NGX_HTTP_UPSTREAM_CHECK)
130 | +#include "ngx_http_upstream_check_module.h"
131 | +#endif
132 | +
133 |
134 | #define ngx_http_upstream_tries(p) ((p)->number \
135 | + ((p)->next ? (p)->next->number : 0))
136 | @@ -98,6 +102,15 @@
137 | peer[n].down = server[i].down;
138 | peer[n].server = server[i].name;
139 |
140 | +#if (NGX_HTTP_UPSTREAM_CHECK)
141 | + if (!server[i].down) {
142 | + peer[n].check_index =
143 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
144 | + } else {
145 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
146 | + }
147 | +#endif
148 | +
149 | *peerp = &peer[n];
150 | peerp = &peer[n].next;
151 | n++;
152 | @@ -162,6 +175,16 @@
153 | peer[n].down = server[i].down;
154 | peer[n].server = server[i].name;
155 |
156 | +#if (NGX_HTTP_UPSTREAM_CHECK)
157 | + if (!server[i].down) {
158 | + peer[n].check_index =
159 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
160 | + }
161 | + else {
162 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
163 | + }
164 | +#endif
165 | +
166 | *peerp = &peer[n];
167 | peerp = &peer[n].next;
168 | n++;
169 | @@ -228,6 +251,9 @@
170 | peer[i].max_conns = 0;
171 | peer[i].max_fails = 1;
172 | peer[i].fail_timeout = 10;
173 | +#if (NGX_HTTP_UPSTREAM_CHECK)
174 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
175 | +#endif
176 | *peerp = &peer[i];
177 | peerp = &peer[i].next;
178 | }
179 | @@ -344,6 +370,9 @@
180 | peer[0].max_conns = 0;
181 | peer[0].max_fails = 1;
182 | peer[0].fail_timeout = 10;
183 | +#if (NGX_HTTP_UPSTREAM_CHECK)
184 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR;
185 | +#endif
186 | peers->peer = peer;
187 |
188 | } else {
189 | @@ -378,6 +407,9 @@
190 | peer[i].max_conns = 0;
191 | peer[i].max_fails = 1;
192 | peer[i].fail_timeout = 10;
193 | +#if (NGX_HTTP_UPSTREAM_CHECK)
194 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
195 | +#endif
196 | *peerp = &peer[i];
197 | peerp = &peer[i].next;
198 | }
199 | @@ -443,6 +475,12 @@
200 | goto failed;
201 | }
202 |
203 | +#if (NGX_HTTP_UPSTREAM_CHECK)
204 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
205 | + goto failed;
206 | + }
207 | +#endif
208 | +
209 | rrp->current = peer;
210 |
211 | } else {
212 | @@ -537,6 +575,12 @@
213 | continue;
214 | }
215 |
216 | +#if (NGX_HTTP_UPSTREAM_CHECK)
217 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
218 | + continue;
219 | + }
220 | +#endif
221 | +
222 | if (peer->max_fails
223 | && peer->fails >= peer->max_fails
224 | && now - peer->checked <= peer->fail_timeout)
225 | diff -burN nginx-1.12.1_orig/src/http/ngx_http_upstream_round_robin.h nginx-1.12.1/src/http/ngx_http_upstream_round_robin.h
226 | --- nginx-1.12.1_orig/src/http/ngx_http_upstream_round_robin.h 2017-07-11 13:24:09.000000000 +0000
227 | +++ nginx-1.12.1/src/http/ngx_http_upstream_round_robin.h 2017-07-13 18:13:30.254055435 +0000
228 | @@ -38,6 +38,10 @@
229 | ngx_msec_t slow_start;
230 | ngx_msec_t start_time;
231 |
232 | +#if (NGX_HTTP_UPSTREAM_CHECK)
233 | + ngx_uint_t check_index;
234 | +#endif
235 | +
236 | ngx_uint_t down;
237 |
238 | #if (NGX_HTTP_SSL || NGX_COMPAT)
239 |
--------------------------------------------------------------------------------
/check_1.2.1.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
2 | index 100ea34..642b01b 100644
3 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
5 | @@ -9,6 +9,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 |
14 | typedef struct {
15 | /* the round robin data must be first */
16 | @@ -182,6 +186,12 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
17 |
18 | if (!peer->down) {
19 |
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
22 | + "get ip_hash peer, check_index: %ui",
23 | + peer->check_index);
24 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
25 | +#endif
26 | if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
27 | break;
28 | }
29 | @@ -190,6 +200,9 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
30 | peer->checked = now;
31 | break;
32 | }
33 | +#if (NGX_HTTP_UPSTREAM_CHECK)
34 | + }
35 | +#endif
36 | }
37 |
38 | iphp->rrp.tried[n] |= m;
39 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
40 | index 214de7b..309725b 100644
41 | --- a/src/http/ngx_http_upstream_round_robin.c
42 | +++ b/src/http/ngx_http_upstream_round_robin.c
43 | @@ -9,6 +9,9 @@
44 | #include
45 | #include
46 |
47 | +#if (NGX_HTTP_UPSTREAM_CHECK)
48 | +#include "ngx_http_upstream_check_module.h"
49 | +#endif
50 |
51 | static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,
52 | const void *two);
53 | @@ -83,7 +86,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
54 | peers->peer[n].weight = server[i].weight;
55 | peers->peer[n].effective_weight = server[i].weight;
56 | peers->peer[n].current_weight = 0;
57 | - n++;
58 | +
59 | +#if (NGX_HTTP_UPSTREAM_CHECK)
60 | + if (!server[i].down) {
61 | + peers->peer[n].check_index =
62 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
63 | + }
64 | + else {
65 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
66 | + }
67 | +#endif
68 | + n++;
69 | }
70 | }
71 |
72 | @@ -137,6 +150,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
73 | backup->peer[n].max_fails = server[i].max_fails;
74 | backup->peer[n].fail_timeout = server[i].fail_timeout;
75 | backup->peer[n].down = server[i].down;
76 | +
77 | +#if (NGX_HTTP_UPSTREAM_CHECK)
78 | + if (!server[i].down) {
79 | + backup->peer[n].check_index =
80 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
81 | + }
82 | + else {
83 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
84 | + }
85 | +#endif
86 | +
87 | n++;
88 | }
89 | }
90 | @@ -196,6 +220,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
91 | peers->peer[i].current_weight = 0;
92 | peers->peer[i].max_fails = 1;
93 | peers->peer[i].fail_timeout = 10;
94 | +#if (NGX_HTTP_UPSTREAM_CHECK)
95 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
96 | +#endif
97 | }
98 |
99 | us->peer.data = peers;
100 | @@ -313,6 +340,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
101 | peers->peer[0].current_weight = 0;
102 | peers->peer[0].max_fails = 1;
103 | peers->peer[0].fail_timeout = 10;
104 | +#if (NGX_HTTP_UPSTREAM_CHECK)
105 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
106 | +#endif
107 |
108 | } else {
109 |
110 | @@ -346,6 +376,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
111 | peers->peer[i].current_weight = 0;
112 | peers->peer[i].max_fails = 1;
113 | peers->peer[i].fail_timeout = 10;
114 | +#if (NGX_HTTP_UPSTREAM_CHECK)
115 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
116 | +#endif
117 | }
118 | }
119 |
120 | @@ -419,7 +452,11 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
121 |
122 | if (rrp->peers->single) {
123 | peer = &rrp->peers->peer[0];
124 | -
125 | +#if (NGX_HTTP_UPSTREAM_CHECK)
126 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
127 | + return NGX_BUSY;
128 | + }
129 | +#endif
130 | } else {
131 |
132 | /* there are several peers */
133 | @@ -517,6 +554,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
134 | continue;
135 | }
136 |
137 | +#if (NGX_HTTP_UPSTREAM_CHECK)
138 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
139 | + continue;
140 | + }
141 | +#endif
142 | +
143 | if (peer->max_fails
144 | && peer->fails >= peer->max_fails
145 | && now - peer->checked <= peer->fail_timeout)
146 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
147 | index 4de3cae..164867b 100644
148 | --- a/src/http/ngx_http_upstream_round_robin.h
149 | +++ b/src/http/ngx_http_upstream_round_robin.h
150 | @@ -30,6 +30,10 @@ typedef struct {
151 | ngx_uint_t max_fails;
152 | time_t fail_timeout;
153 |
154 | +#if (NGX_HTTP_UPSTREAM_CHECK)
155 | + ngx_uint_t check_index;
156 | +#endif
157 | +
158 | ngx_uint_t down; /* unsigned down:1; */
159 |
160 | #if (NGX_HTTP_SSL)
161 |
--------------------------------------------------------------------------------
/check_1.2.2+.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
2 | index 89ccc2b..a552044 100644
3 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
5 | @@ -9,6 +9,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 |
14 | typedef struct {
15 | /* the round robin data must be first */
16 | @@ -208,6 +212,12 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
17 |
18 | if (!peer->down) {
19 |
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
22 | + "get ip_hash peer, check_index: %ui",
23 | + peer->check_index);
24 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
25 | +#endif
26 | if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
27 | break;
28 | }
29 | @@ -216,6 +226,9 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
30 | peer->checked = now;
31 | break;
32 | }
33 | +#if (NGX_HTTP_UPSTREAM_CHECK)
34 | + }
35 | +#endif
36 | }
37 |
38 | iphp->rrp.tried[n] |= m;
39 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c
40 | index 50e68b2..f2f32cc 100644
41 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c
42 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c
43 | @@ -9,6 +9,10 @@
44 | #include
45 | #include
46 |
47 | +#if (NGX_HTTP_UPSTREAM_CHECK)
48 | +#include "ngx_http_upstream_check_module.h"
49 | +#endif
50 | +
51 |
52 | typedef struct {
53 | ngx_uint_t *conns;
54 | @@ -203,6 +207,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
55 | continue;
56 | }
57 |
58 | +#if (NGX_HTTP_UPSTREAM_CHECK)
59 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
60 | + "get least_conn peer, check_index: %ui",
61 | + peer->check_index);
62 | +
63 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
64 | + continue;
65 | + }
66 | +#endif
67 | +
68 | if (peer->max_fails
69 | && peer->fails >= peer->max_fails
70 | && now - peer->checked <= peer->fail_timeout)
71 | @@ -256,6 +270,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
72 | continue;
73 | }
74 |
75 | +#if (NGX_HTTP_UPSTREAM_CHECK)
76 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
77 | + "get least_conn peer, check_index: %ui",
78 | + peer->check_index);
79 | +
80 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
81 | + continue;
82 | + }
83 | +#endif
84 | +
85 | if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
86 | continue;
87 | }
88 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
89 | index c4998fc..f3e9378 100644
90 | --- a/src/http/ngx_http_upstream_round_robin.c
91 | +++ b/src/http/ngx_http_upstream_round_robin.c
92 | @@ -9,6 +9,9 @@
93 | #include
94 | #include
95 |
96 | +#if (NGX_HTTP_UPSTREAM_CHECK)
97 | +#include "ngx_http_upstream_check_module.h"
98 | +#endif
99 |
100 | static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,
101 | const void *two);
102 | @@ -87,7 +90,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
103 | peers->peer[n].weight = server[i].weight;
104 | peers->peer[n].effective_weight = server[i].weight;
105 | peers->peer[n].current_weight = 0;
106 | - n++;
107 | +
108 | +#if (NGX_HTTP_UPSTREAM_CHECK)
109 | + if (!server[i].down) {
110 | + peers->peer[n].check_index =
111 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
112 | + }
113 | + else {
114 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
115 | + }
116 | +#endif
117 | + n++;
118 | }
119 | }
120 |
121 | @@ -145,6 +158,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
122 | backup->peer[n].max_fails = server[i].max_fails;
123 | backup->peer[n].fail_timeout = server[i].fail_timeout;
124 | backup->peer[n].down = server[i].down;
125 | +
126 | +#if (NGX_HTTP_UPSTREAM_CHECK)
127 | + if (!server[i].down) {
128 | + backup->peer[n].check_index =
129 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
130 | + }
131 | + else {
132 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
133 | + }
134 | +#endif
135 | +
136 | n++;
137 | }
138 | }
139 | @@ -206,6 +230,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
140 | peers->peer[i].current_weight = 0;
141 | peers->peer[i].max_fails = 1;
142 | peers->peer[i].fail_timeout = 10;
143 | +#if (NGX_HTTP_UPSTREAM_CHECK)
144 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
145 | +#endif
146 | }
147 |
148 | us->peer.data = peers;
149 | @@ -323,6 +350,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
150 | peers->peer[0].current_weight = 0;
151 | peers->peer[0].max_fails = 1;
152 | peers->peer[0].fail_timeout = 10;
153 | +#if (NGX_HTTP_UPSTREAM_CHECK)
154 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
155 | +#endif
156 |
157 | } else {
158 |
159 | @@ -356,6 +386,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
160 | peers->peer[i].current_weight = 0;
161 | peers->peer[i].max_fails = 1;
162 | peers->peer[i].fail_timeout = 10;
163 | +#if (NGX_HTTP_UPSTREAM_CHECK)
164 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
165 | +#endif
166 | }
167 | }
168 |
169 | @@ -429,7 +462,11 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
170 |
171 | if (rrp->peers->single) {
172 | peer = &rrp->peers->peer[0];
173 | -
174 | +#if (NGX_HTTP_UPSTREAM_CHECK)
175 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
176 | + return NGX_BUSY;
177 | + }
178 | +#endif
179 | } else {
180 |
181 | /* there are several peers */
182 | @@ -527,6 +564,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
183 | continue;
184 | }
185 |
186 | +#if (NGX_HTTP_UPSTREAM_CHECK)
187 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
188 | + continue;
189 | + }
190 | +#endif
191 | +
192 | if (peer->max_fails
193 | && peer->fails >= peer->max_fails
194 | && now - peer->checked <= peer->fail_timeout)
195 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
196 | index 3f8cbf8..1613168 100644
197 | --- a/src/http/ngx_http_upstream_round_robin.h
198 | +++ b/src/http/ngx_http_upstream_round_robin.h
199 | @@ -30,6 +30,10 @@ typedef struct {
200 | ngx_uint_t max_fails;
201 | time_t fail_timeout;
202 |
203 | +#if (NGX_HTTP_UPSTREAM_CHECK)
204 | + ngx_uint_t check_index;
205 | +#endif
206 | +
207 | ngx_uint_t down; /* unsigned down:1; */
208 |
209 | #if (NGX_HTTP_SSL)
210 |
--------------------------------------------------------------------------------
/check_1.2.6+.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
2 | index 89ccc2b..a552044 100644
3 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
5 | @@ -9,6 +9,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 |
14 | typedef struct {
15 | /* the round robin data must be first */
16 | @@ -208,6 +212,12 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
17 |
18 | if (!peer->down) {
19 |
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
22 | + "get ip_hash peer, check_index: %ui",
23 | + peer->check_index);
24 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
25 | +#endif
26 | if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
27 | break;
28 | }
29 | @@ -216,6 +226,9 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
30 | peer->checked = now;
31 | break;
32 | }
33 | +#if (NGX_HTTP_UPSTREAM_CHECK)
34 | + }
35 | +#endif
36 | }
37 |
38 | iphp->rrp.tried[n] |= m;
39 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c
40 | index 21156ae..c57393d 100644
41 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c
42 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c
43 | @@ -9,6 +9,10 @@
44 | #include
45 | #include
46 |
47 | +#if (NGX_HTTP_UPSTREAM_CHECK)
48 | +#include "ngx_http_upstream_check_module.h"
49 | +#endif
50 | +
51 |
52 | typedef struct {
53 | ngx_uint_t *conns;
54 | @@ -203,6 +207,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
55 | continue;
56 | }
57 |
58 | +#if (NGX_HTTP_UPSTREAM_CHECK)
59 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
60 | + "get least_conn peer, check_index: %ui",
61 | + peer->check_index);
62 | +
63 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
64 | + continue;
65 | + }
66 | +#endif
67 | +
68 | if (peer->max_fails
69 | && peer->fails >= peer->max_fails
70 | && now - peer->checked <= peer->fail_timeout)
71 | @@ -256,6 +270,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
72 | continue;
73 | }
74 |
75 | +#if (NGX_HTTP_UPSTREAM_CHECK)
76 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
77 | + "get least_conn peer, check_index: %ui",
78 | + peer->check_index);
79 | +
80 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
81 | + continue;
82 | + }
83 | +#endif
84 | +
85 | if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
86 | continue;
87 | }
88 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
89 | index 4b78cff..f077b46 100644
90 | --- a/src/http/ngx_http_upstream_round_robin.c
91 | +++ b/src/http/ngx_http_upstream_round_robin.c
92 | @@ -9,6 +9,9 @@
93 | #include
94 | #include
95 |
96 | +#if (NGX_HTTP_UPSTREAM_CHECK)
97 | +#include "ngx_http_upstream_check_module.h"
98 | +#endif
99 |
100 | static ngx_int_t ngx_http_upstream_cmp_servers(const void *one,
101 | const void *two);
102 | @@ -87,7 +90,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
103 | peers->peer[n].weight = server[i].weight;
104 | peers->peer[n].effective_weight = server[i].weight;
105 | peers->peer[n].current_weight = 0;
106 | - n++;
107 | +
108 | +#if (NGX_HTTP_UPSTREAM_CHECK)
109 | + if (!server[i].down) {
110 | + peers->peer[n].check_index =
111 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
112 | + }
113 | + else {
114 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
115 | + }
116 | +#endif
117 | + n++;
118 | }
119 | }
120 |
121 | @@ -145,6 +158,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
122 | backup->peer[n].max_fails = server[i].max_fails;
123 | backup->peer[n].fail_timeout = server[i].fail_timeout;
124 | backup->peer[n].down = server[i].down;
125 | +
126 | +#if (NGX_HTTP_UPSTREAM_CHECK)
127 | + if (!server[i].down) {
128 | + backup->peer[n].check_index =
129 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
130 | + }
131 | + else {
132 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
133 | + }
134 | +#endif
135 | +
136 | n++;
137 | }
138 | }
139 | @@ -206,6 +230,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
140 | peers->peer[i].current_weight = 0;
141 | peers->peer[i].max_fails = 1;
142 | peers->peer[i].fail_timeout = 10;
143 | +#if (NGX_HTTP_UPSTREAM_CHECK)
144 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
145 | +#endif
146 | }
147 |
148 | us->peer.data = peers;
149 | @@ -323,6 +350,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
150 | peers->peer[0].current_weight = 0;
151 | peers->peer[0].max_fails = 1;
152 | peers->peer[0].fail_timeout = 10;
153 | +#if (NGX_HTTP_UPSTREAM_CHECK)
154 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
155 | +#endif
156 |
157 | } else {
158 |
159 | @@ -356,6 +386,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
160 | peers->peer[i].current_weight = 0;
161 | peers->peer[i].max_fails = 1;
162 | peers->peer[i].fail_timeout = 10;
163 | +#if (NGX_HTTP_UPSTREAM_CHECK)
164 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
165 | +#endif
166 | }
167 | }
168 |
169 | @@ -434,6 +467,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
170 | goto failed;
171 | }
172 |
173 | +#if (NGX_HTTP_UPSTREAM_CHECK)
174 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
175 | + goto failed;
176 | + }
177 | +#endif
178 | +
179 | } else {
180 |
181 | /* there are several peers */
182 | @@ -531,6 +570,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
183 | continue;
184 | }
185 |
186 | +#if (NGX_HTTP_UPSTREAM_CHECK)
187 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
188 | + continue;
189 | + }
190 | +#endif
191 | +
192 | if (peer->max_fails
193 | && peer->fails >= peer->max_fails
194 | && now - peer->checked <= peer->fail_timeout)
195 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
196 | index 3f8cbf8..1613168 100644
197 | --- a/src/http/ngx_http_upstream_round_robin.h
198 | +++ b/src/http/ngx_http_upstream_round_robin.h
199 | @@ -30,6 +30,10 @@ typedef struct {
200 | ngx_uint_t max_fails;
201 | time_t fail_timeout;
202 |
203 | +#if (NGX_HTTP_UPSTREAM_CHECK)
204 | + ngx_uint_t check_index;
205 | +#endif
206 | +
207 | ngx_uint_t down; /* unsigned down:1; */
208 |
209 | #if (NGX_HTTP_SSL)
210 |
--------------------------------------------------------------------------------
/check_1.5.12+.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
2 | index 041883f..b1bc7d0 100644
3 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
5 | @@ -9,6 +9,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 |
14 | typedef struct {
15 | /* the round robin data must be first */
16 | @@ -212,6 +216,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
17 | goto next_try;
18 | }
19 |
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
22 | + "get ip_hash peer, check_index: %ui",
23 | + peer->check_index);
24 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
25 | + goto next_try;
26 | + }
27 | +#endif
28 | +
29 | if (peer->max_fails
30 | && peer->fails >= peer->max_fails
31 | && now - peer->checked <= peer->fail_timeout)
32 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c
33 | index dbef95d..dc9b518 100644
34 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c
35 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c
36 | @@ -9,6 +9,10 @@
37 | #include
38 | #include
39 |
40 | +#if (NGX_HTTP_UPSTREAM_CHECK)
41 | +#include "ngx_http_upstream_check_module.h"
42 | +#endif
43 | +
44 |
45 | typedef struct {
46 | ngx_uint_t *conns;
47 | @@ -203,6 +207,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
48 | continue;
49 | }
50 |
51 | +#if (NGX_HTTP_UPSTREAM_CHECK)
52 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
53 | + "get least_conn peer, check_index: %ui",
54 | + peer->check_index);
55 | +
56 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
57 | + continue;
58 | + }
59 | +#endif
60 | +
61 | if (peer->max_fails
62 | && peer->fails >= peer->max_fails
63 | && now - peer->checked <= peer->fail_timeout)
64 | @@ -256,6 +270,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
65 | continue;
66 | }
67 |
68 | +#if (NGX_HTTP_UPSTREAM_CHECK)
69 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
70 | + "get least_conn peer, check_index: %ui",
71 | + peer->check_index);
72 | +
73 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
74 | + continue;
75 | + }
76 | +#endif
77 | +
78 | if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
79 | continue;
80 | }
81 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
82 | index 85ff558..2fe9bb6 100644
83 | --- a/src/http/ngx_http_upstream_round_robin.c
84 | +++ b/src/http/ngx_http_upstream_round_robin.c
85 | @@ -9,6 +9,9 @@
86 | #include
87 | #include
88 |
89 | +#if (NGX_HTTP_UPSTREAM_CHECK)
90 | +#include "ngx_http_upstream_check_module.h"
91 | +#endif
92 |
93 | static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
94 | ngx_http_upstream_rr_peer_data_t *rrp);
95 | @@ -85,6 +88,14 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
96 | peers->peer[n].max_fails = server[i].max_fails;
97 | peers->peer[n].fail_timeout = server[i].fail_timeout;
98 | peers->peer[n].down = server[i].down;
99 | +#if (NGX_HTTP_UPSTREAM_CHECK)
100 | + if (!server[i].down) {
101 | + peers->peer[n].check_index =
102 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
103 | + } else {
104 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
105 | + }
106 | +#endif
107 | n++;
108 | }
109 | }
110 | @@ -139,6 +150,17 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
111 | backup->peer[n].max_fails = server[i].max_fails;
112 | backup->peer[n].fail_timeout = server[i].fail_timeout;
113 | backup->peer[n].down = server[i].down;
114 | +
115 | +#if (NGX_HTTP_UPSTREAM_CHECK)
116 | + if (!server[i].down) {
117 | + backup->peer[n].check_index =
118 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
119 | + }
120 | + else {
121 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
122 | + }
123 | +#endif
124 | +
125 | n++;
126 | }
127 | }
128 | @@ -196,6 +218,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
129 | peers->peer[i].current_weight = 0;
130 | peers->peer[i].max_fails = 1;
131 | peers->peer[i].fail_timeout = 10;
132 | +#if (NGX_HTTP_UPSTREAM_CHECK)
133 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
134 | +#endif
135 | }
136 |
137 | us->peer.data = peers;
138 | @@ -302,6 +327,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
139 | peers->peer[0].current_weight = 0;
140 | peers->peer[0].max_fails = 1;
141 | peers->peer[0].fail_timeout = 10;
142 | +#if (NGX_HTTP_UPSTREAM_CHECK)
143 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
144 | +#endif
145 |
146 | } else {
147 |
148 | @@ -342,6 +370,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
149 | peers->peer[i].current_weight = 0;
150 | peers->peer[i].max_fails = 1;
151 | peers->peer[i].fail_timeout = 10;
152 | +#if (NGX_HTTP_UPSTREAM_CHECK)
153 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
154 | +#endif
155 | }
156 | }
157 |
158 | @@ -399,6 +430,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
159 | goto failed;
160 | }
161 |
162 | +#if (NGX_HTTP_UPSTREAM_CHECK)
163 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
164 | + goto failed;
165 | + }
166 | +#endif
167 | +
168 | } else {
169 |
170 | /* there are several peers */
171 | @@ -498,6 +535,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
172 | continue;
173 | }
174 |
175 | +#if (NGX_HTTP_UPSTREAM_CHECK)
176 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
177 | + continue;
178 | + }
179 | +#endif
180 | +
181 | if (peer->max_fails
182 | && peer->fails >= peer->max_fails
183 | && now - peer->checked <= peer->fail_timeout)
184 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
185 | index ea90ab9..a6fb33f 100644
186 | --- a/src/http/ngx_http_upstream_round_robin.h
187 | +++ b/src/http/ngx_http_upstream_round_robin.h
188 | @@ -30,6 +30,10 @@ typedef struct {
189 | ngx_uint_t max_fails;
190 | time_t fail_timeout;
191 |
192 | +#if (NGX_HTTP_UPSTREAM_CHECK)
193 | + ngx_uint_t check_index;
194 | +#endif
195 | +
196 | ngx_uint_t down; /* unsigned down:1; */
197 |
198 | #if (NGX_HTTP_SSL)
199 |
--------------------------------------------------------------------------------
/check_1.7.2+.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c
2 | index 777e180..e302f52 100644
3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c
5 | @@ -9,6 +9,9 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 |
13 | typedef struct {
14 | uint32_t hash;
15 | @@ -240,6 +243,14 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
16 | goto next;
17 | }
18 |
19 | +#if (NGX_HTTP_UPSTREAM_CHECK)
20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
21 | + "get hash peer, check_index: %ui",
22 | + peer->check_index);
23 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
24 | + goto next;
25 | + }
26 | +#endif
27 | if (peer->max_fails
28 | && peer->fails >= peer->max_fails
29 | && now - peer->checked <= peer->fail_timeout)
30 | @@ -506,6 +517,14 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
31 | continue;
32 | }
33 |
34 | +#if (NGX_HTTP_UPSTREAM_CHECK)
35 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
36 | + "get consistent_hash peer, check_index: %ui",
37 | + peer->check_index);
38 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
39 | + continue;
40 | + }
41 | +#endif
42 | if (peer->server.len != server->len
43 | || ngx_strncmp(peer->server.data, server->data, server->len)
44 | != 0)
45 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
46 | index 148d73a..913e395 100644
47 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
48 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
49 | @@ -9,6 +9,9 @@
50 | #include
51 | #include
52 |
53 | +#if (NGX_HTTP_UPSTREAM_CHECK)
54 | +#include "ngx_http_upstream_check_module.h"
55 | +#endif
56 |
57 | typedef struct {
58 | /* the round robin data must be first */
59 | @@ -212,6 +215,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
60 | goto next_try;
61 | }
62 |
63 | +#if (NGX_HTTP_UPSTREAM_CHECK)
64 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
65 | + "get ip_hash peer, check_index: %ui",
66 | + peer->check_index);
67 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
68 | + goto next_try;
69 | + }
70 | +#endif
71 | +
72 | if (peer->max_fails
73 | && peer->fails >= peer->max_fails
74 | && now - peer->checked <= peer->fail_timeout)
75 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c
76 | index dbef95d..bbabb68 100644
77 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c
78 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c
79 | @@ -9,6 +9,9 @@
80 | #include
81 | #include
82 |
83 | +#if (NGX_HTTP_UPSTREAM_CHECK)
84 | +#include "ngx_http_upstream_check_module.h"
85 | +#endif
86 |
87 | typedef struct {
88 | ngx_uint_t *conns;
89 | @@ -203,6 +206,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
90 | continue;
91 | }
92 |
93 | +#if (NGX_HTTP_UPSTREAM_CHECK)
94 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
95 | + "get least_conn peer, check_index: %ui",
96 | + peer->check_index);
97 | +
98 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
99 | + continue;
100 | + }
101 | +#endif
102 | +
103 | if (peer->max_fails
104 | && peer->fails >= peer->max_fails
105 | && now - peer->checked <= peer->fail_timeout)
106 | @@ -256,6 +269,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
107 | continue;
108 | }
109 |
110 | +#if (NGX_HTTP_UPSTREAM_CHECK)
111 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
112 | + "get least_conn peer, check_index: %ui",
113 | + peer->check_index);
114 | +
115 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
116 | + continue;
117 | + }
118 | +#endif
119 | +
120 | if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
121 | continue;
122 | }
123 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
124 | index 37c835c..54aa44d 100644
125 | --- a/src/http/ngx_http_upstream_round_robin.c
126 | +++ b/src/http/ngx_http_upstream_round_robin.c
127 | @@ -9,6 +9,9 @@
128 | #include
129 | #include
130 |
131 | +#if (NGX_HTTP_UPSTREAM_CHECK)
132 | +#include "ngx_http_upstream_check_module.h"
133 | +#endif
134 |
135 | static ngx_http_upstream_rr_peer_t *ngx_http_upstream_get_peer(
136 | ngx_http_upstream_rr_peer_data_t *rrp);
137 | @@ -88,6 +91,14 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
138 | peer[n].fail_timeout = server[i].fail_timeout;
139 | peer[n].down = server[i].down;
140 | peer[n].server = server[i].name;
141 | +#if (NGX_HTTP_UPSTREAM_CHECK)
142 | + if (!server[i].down) {
143 | + peers->peer[n].check_index =
144 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
145 | + } else {
146 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
147 | + }
148 | +#endif
149 | n++;
150 | }
151 | }
152 | @@ -144,6 +155,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
153 | peer[n].fail_timeout = server[i].fail_timeout;
154 | peer[n].down = server[i].down;
155 | peer[n].server = server[i].name;
156 | +#if (NGX_HTTP_UPSTREAM_CHECK)
157 | + if (!server[i].down) {
158 | + backup->peer[n].check_index =
159 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
160 | + }
161 | + else {
162 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
163 | + }
164 | +#endif
165 | n++;
166 | }
167 | }
168 | @@ -203,6 +223,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
169 | peer[i].current_weight = 0;
170 | peer[i].max_fails = 1;
171 | peer[i].fail_timeout = 10;
172 | +#if (NGX_HTTP_UPSTREAM_CHECK)
173 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
174 | +#endif
175 | }
176 |
177 | us->peer.data = peers;
178 | @@ -312,7 +335,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
179 | peer[0].current_weight = 0;
180 | peer[0].max_fails = 1;
181 | peer[0].fail_timeout = 10;
182 | -
183 | +#if (NGX_HTTP_UPSTREAM_CHECK)
184 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
185 | +#endif
186 | } else {
187 |
188 | for (i = 0; i < ur->naddrs; i++) {
189 | @@ -352,6 +377,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
190 | peer[i].current_weight = 0;
191 | peer[i].max_fails = 1;
192 | peer[i].fail_timeout = 10;
193 | +#if (NGX_HTTP_UPSTREAM_CHECK)
194 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
195 | +#endif
196 | }
197 | }
198 |
199 | @@ -411,6 +439,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
200 | goto failed;
201 | }
202 |
203 | +#if (NGX_HTTP_UPSTREAM_CHECK)
204 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
205 | + goto failed;
206 | + }
207 | +#endif
208 | +
209 | } else {
210 |
211 | /* there are several peers */
212 | @@ -508,6 +542,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
213 | continue;
214 | }
215 |
216 | +#if (NGX_HTTP_UPSTREAM_CHECK)
217 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
218 | + continue;
219 | + }
220 | +#endif
221 | +
222 | if (peer->max_fails
223 | && peer->fails >= peer->max_fails
224 | && now - peer->checked <= peer->fail_timeout)
225 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
226 | index 9db82a6..6e19a65 100644
227 | --- a/src/http/ngx_http_upstream_round_robin.h
228 | +++ b/src/http/ngx_http_upstream_round_robin.h
229 | @@ -31,6 +31,10 @@ typedef struct {
230 | ngx_uint_t max_fails;
231 | time_t fail_timeout;
232 |
233 | +#if (NGX_HTTP_UPSTREAM_CHECK)
234 | + ngx_uint_t check_index;
235 | +#endif
236 | +
237 | ngx_uint_t down; /* unsigned down:1; */
238 |
239 | #if (NGX_HTTP_SSL)
240 |
--------------------------------------------------------------------------------
/check_1.7.5+.patch:
--------------------------------------------------------------------------------
1 | diff --git a/src/http/modules/ngx_http_upstream_hash_module.c b/src/http/modules/ngx_http_upstream_hash_module.c
2 | index 777e180..b6b7830 100644
3 | --- a/src/http/modules/ngx_http_upstream_hash_module.c
4 | +++ b/src/http/modules/ngx_http_upstream_hash_module.c
5 | @@ -9,6 +9,9 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 |
13 | typedef struct {
14 | uint32_t hash;
15 | @@ -240,6 +243,15 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
16 | goto next;
17 | }
18 |
19 | +#if (NGX_HTTP_UPSTREAM_CHECK)
20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
21 | + "get hash peer, check_index: %ui",
22 | + peer->check_index);
23 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
24 | + goto next;
25 | + }
26 | +#endif
27 | +
28 | if (peer->max_fails
29 | && peer->fails >= peer->max_fails
30 | && now - peer->checked <= peer->fail_timeout)
31 | @@ -506,6 +518,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
32 | continue;
33 | }
34 |
35 | +#if (NGX_HTTP_UPSTREAM_CHECK)
36 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
37 | + "get consistent_hash peer, check_index: %ui",
38 | + peer->check_index);
39 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
40 | + continue;
41 | + }
42 | +#endif
43 | +
44 | if (peer->server.len != server->len
45 | || ngx_strncmp(peer->server.data, server->data, server->len)
46 | != 0)
47 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c
48 | index 148d73a..913e395 100644
49 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c
50 | +++ b/src/http/modules/ngx_http_upstream_ip_hash_module.c
51 | @@ -9,6 +9,9 @@
52 | #include
53 | #include
54 |
55 | +#if (NGX_HTTP_UPSTREAM_CHECK)
56 | +#include "ngx_http_upstream_check_module.h"
57 | +#endif
58 |
59 | typedef struct {
60 | /* the round robin data must be first */
61 | @@ -212,6 +215,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
62 | goto next_try;
63 | }
64 |
65 | +#if (NGX_HTTP_UPSTREAM_CHECK)
66 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
67 | + "get ip_hash peer, check_index: %ui",
68 | + peer->check_index);
69 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
70 | + goto next_try;
71 | + }
72 | +#endif
73 | +
74 | if (peer->max_fails
75 | && peer->fails >= peer->max_fails
76 | && now - peer->checked <= peer->fail_timeout)
77 | diff --git a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c
78 | index 623bc9b..a223839 100644
79 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c
80 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c
81 | @@ -9,6 +9,9 @@
82 | #include
83 | #include
84 |
85 | +#if (NGX_HTTP_UPSTREAM_CHECK)
86 | +#include "ngx_http_upstream_check_module.h"
87 | +#endif
88 |
89 | typedef struct {
90 | ngx_uint_t *conns;
91 | @@ -203,6 +206,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
92 | continue;
93 | }
94 |
95 | +#if (NGX_HTTP_UPSTREAM_CHECK)
96 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
97 | + "get least_conn peer, check_index: %ui",
98 | + peer->check_index);
99 | +
100 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
101 | + continue;
102 | + }
103 | +#endif
104 | +
105 | if (peer->max_fails
106 | && peer->fails >= peer->max_fails
107 | && now - peer->checked <= peer->fail_timeout)
108 | @@ -256,6 +269,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
109 | continue;
110 | }
111 |
112 | +#if (NGX_HTTP_UPSTREAM_CHECK)
113 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
114 | + "get least_conn peer, check_index: %ui",
115 | + peer->check_index);
116 | +
117 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
118 | + continue;
119 | + }
120 | +#endif
121 | +
122 | if (lcp->conns[i] * best->weight != lcp->conns[p] * peer->weight) {
123 | continue;
124 | }
125 | diff --git a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c
126 | index 2d0649b..b9789eb 100644
127 | --- a/src/http/ngx_http_upstream_round_robin.c
128 | +++ b/src/http/ngx_http_upstream_round_robin.c
129 | @@ -9,6 +9,9 @@
130 | #include
131 | #include
132 |
133 | +#if (NGX_HTTP_UPSTREAM_CHECK)
134 | +#include "ngx_http_upstream_check_module.h"
135 | +#endif
136 |
137 | #define ngx_http_upstream_tries(p) ((p)->number \
138 | + ((p)->next ? (p)->next->number : 0))
139 | @@ -92,6 +95,14 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
140 | peer[n].fail_timeout = server[i].fail_timeout;
141 | peer[n].down = server[i].down;
142 | peer[n].server = server[i].name;
143 | +#if (NGX_HTTP_UPSTREAM_CHECK)
144 | + if (!server[i].down) {
145 | + peers->peer[n].check_index =
146 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
147 | + } else {
148 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
149 | + }
150 | +#endif
151 | n++;
152 | }
153 | }
154 | @@ -148,6 +159,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
155 | peer[n].fail_timeout = server[i].fail_timeout;
156 | peer[n].down = server[i].down;
157 | peer[n].server = server[i].name;
158 | +#if (NGX_HTTP_UPSTREAM_CHECK)
159 | + if (!server[i].down) {
160 | + backup->peer[n].check_index =
161 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
162 | + }
163 | + else {
164 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
165 | + }
166 | +#endif
167 | n++;
168 | }
169 | }
170 | @@ -207,6 +227,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
171 | peer[i].current_weight = 0;
172 | peer[i].max_fails = 1;
173 | peer[i].fail_timeout = 10;
174 | +#if (NGX_HTTP_UPSTREAM_CHECK)
175 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
176 | +#endif
177 | }
178 |
179 | us->peer.data = peers;
180 | @@ -316,7 +339,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
181 | peer[0].current_weight = 0;
182 | peer[0].max_fails = 1;
183 | peer[0].fail_timeout = 10;
184 | -
185 | +#if (NGX_HTTP_UPSTREAM_CHECK)
186 | + peers->peer[0].check_index = (ngx_uint_t) NGX_ERROR;
187 | +#endif
188 | } else {
189 |
190 | for (i = 0; i < ur->naddrs; i++) {
191 | @@ -356,6 +381,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
192 | peer[i].current_weight = 0;
193 | peer[i].max_fails = 1;
194 | peer[i].fail_timeout = 10;
195 | +#if (NGX_HTTP_UPSTREAM_CHECK)
196 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
197 | +#endif
198 | }
199 | }
200 |
201 | @@ -415,6 +443,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
202 | goto failed;
203 | }
204 |
205 | +#if (NGX_HTTP_UPSTREAM_CHECK)
206 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
207 | + goto failed;
208 | + }
209 | +#endif
210 | +
211 | } else {
212 |
213 | /* there are several peers */
214 | @@ -507,6 +541,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
215 | continue;
216 | }
217 |
218 | +#if (NGX_HTTP_UPSTREAM_CHECK)
219 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
220 | + continue;
221 | + }
222 | +#endif
223 | +
224 | if (peer->max_fails
225 | && peer->fails >= peer->max_fails
226 | && now - peer->checked <= peer->fail_timeout)
227 | diff --git a/src/http/ngx_http_upstream_round_robin.h b/src/http/ngx_http_upstream_round_robin.h
228 | index 9db82a6..6e19a65 100644
229 | --- a/src/http/ngx_http_upstream_round_robin.h
230 | +++ b/src/http/ngx_http_upstream_round_robin.h
231 | @@ -31,6 +31,10 @@ typedef struct {
232 | ngx_uint_t max_fails;
233 | time_t fail_timeout;
234 |
235 | +#if (NGX_HTTP_UPSTREAM_CHECK)
236 | + ngx_uint_t check_index;
237 | +#endif
238 | +
239 | ngx_uint_t down; /* unsigned down:1; */
240 |
241 | #if (NGX_HTTP_SSL)
242 |
--------------------------------------------------------------------------------
/check_1.9.2+.patch:
--------------------------------------------------------------------------------
1 | diff --git src/http/modules/ngx_http_upstream_hash_module.c src/http/modules/ngx_http_upstream_hash_module.c
2 | index 1e2e05c..44a72e2 100644
3 | --- src/http/modules/ngx_http_upstream_hash_module.c
4 | +++ src/http/modules/ngx_http_upstream_hash_module.c
5 | @@ -9,6 +9,9 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 |
13 | typedef struct {
14 | uint32_t hash;
15 | @@ -235,6 +238,15 @@ ngx_http_upstream_get_hash_peer(ngx_peer_connection_t *pc, void *data)
16 | goto next;
17 | }
18 |
19 | +#if (NGX_HTTP_UPSTREAM_CHECK)
20 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
21 | + "get hash peer, check_index: %ui",
22 | + peer->check_index);
23 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
24 | + goto next;
25 | + }
26 | +#endif
27 | +
28 | if (peer->max_fails
29 | && peer->fails >= peer->max_fails
30 | && now - peer->checked <= peer->fail_timeout)
31 | @@ -535,6 +547,15 @@ ngx_http_upstream_get_chash_peer(ngx_peer_connection_t *pc, void *data)
32 | continue;
33 | }
34 |
35 | +#if (NGX_HTTP_UPSTREAM_CHECK)
36 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
37 | + "get consistent_hash peer, check_index: %ui",
38 | + peer->check_index);
39 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
40 | + continue;
41 | + }
42 | +#endif
43 | +
44 | if (peer->server.len != server->len
45 | || ngx_strncmp(peer->server.data, server->data, server->len)
46 | != 0)
47 | diff --git src/http/modules/ngx_http_upstream_ip_hash_module.c src/http/modules/ngx_http_upstream_ip_hash_module.c
48 | index 401b58e..ba656bd 100644
49 | --- src/http/modules/ngx_http_upstream_ip_hash_module.c
50 | +++ src/http/modules/ngx_http_upstream_ip_hash_module.c
51 | @@ -9,6 +9,9 @@
52 | #include
53 | #include
54 |
55 | +#if (NGX_HTTP_UPSTREAM_CHECK)
56 | +#include "ngx_http_upstream_check_module.h"
57 | +#endif
58 |
59 | typedef struct {
60 | /* the round robin data must be first */
61 | @@ -205,6 +208,15 @@ ngx_http_upstream_get_ip_hash_peer(ngx_peer_connection_t *pc, void *data)
62 | goto next;
63 | }
64 |
65 | +#if (NGX_HTTP_UPSTREAM_CHECK)
66 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
67 | + "get ip_hash peer, check_index: %ui",
68 | + peer->check_index);
69 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
70 | + goto next;
71 | + }
72 | +#endif
73 | +
74 | if (peer->max_fails
75 | && peer->fails >= peer->max_fails
76 | && now - peer->checked <= peer->fail_timeout)
77 | diff --git src/http/modules/ngx_http_upstream_least_conn_module.c src/http/modules/ngx_http_upstream_least_conn_module.c
78 | index 92951bd..48aca2c 100644
79 | --- src/http/modules/ngx_http_upstream_least_conn_module.c
80 | +++ src/http/modules/ngx_http_upstream_least_conn_module.c
81 | @@ -9,6 +9,9 @@
82 | #include
83 | #include
84 |
85 | +#if (NGX_HTTP_UPSTREAM_CHECK)
86 | +#include "ngx_http_upstream_check_module.h"
87 | +#endif
88 |
89 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r,
90 | ngx_http_upstream_srv_conf_t *us);
91 | @@ -148,6 +151,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
92 | continue;
93 | }
94 |
95 | +#if (NGX_HTTP_UPSTREAM_CHECK)
96 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
97 | + "get least_conn peer, check_index: %ui",
98 | + peer->check_index);
99 | +
100 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
101 | + continue;
102 | + }
103 | +#endif
104 | +
105 | if (peer->max_fails
106 | && peer->fails >= peer->max_fails
107 | && now - peer->checked <= peer->fail_timeout)
108 | @@ -199,6 +212,16 @@ ngx_http_upstream_get_least_conn_peer(ngx_peer_connection_t *pc, void *data)
109 | continue;
110 | }
111 |
112 | +#if (NGX_HTTP_UPSTREAM_CHECK)
113 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
114 | + "get least_conn peer, check_index: %ui",
115 | + peer->check_index);
116 | +
117 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
118 | + continue;
119 | + }
120 | +#endif
121 | +
122 | if (peer->conns * best->weight != best->conns * peer->weight) {
123 | continue;
124 | }
125 | diff --git src/http/ngx_http_upstream_round_robin.c src/http/ngx_http_upstream_round_robin.c
126 | index d6ae33b..416572a 100644
127 | --- src/http/ngx_http_upstream_round_robin.c
128 | +++ src/http/ngx_http_upstream_round_robin.c
129 | @@ -9,6 +9,9 @@
130 | #include
131 | #include
132 |
133 | +#if (NGX_HTTP_UPSTREAM_CHECK)
134 | +#include "ngx_http_upstream_check_module.h"
135 | +#endif
136 |
137 | #define ngx_http_upstream_tries(p) ((p)->number \
138 | + ((p)->next ? (p)->next->number : 0))
139 | @@ -96,7 +99,14 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
140 | peer[n].fail_timeout = server[i].fail_timeout;
141 | peer[n].down = server[i].down;
142 | peer[n].server = server[i].name;
143 | -
144 | +#if (NGX_HTTP_UPSTREAM_CHECK)
145 | + if (!server[i].down) {
146 | + peer[n].check_index =
147 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
148 | + } else {
149 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
150 | + }
151 | +#endif
152 | *peerp = &peer[n];
153 | peerp = &peer[n].next;
154 | n++;
155 | @@ -159,7 +169,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
156 | peer[n].fail_timeout = server[i].fail_timeout;
157 | peer[n].down = server[i].down;
158 | peer[n].server = server[i].name;
159 | -
160 | +#if (NGX_HTTP_UPSTREAM_CHECK)
161 | + if (!server[i].down) {
162 | + peer[n].check_index =
163 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
164 | + }
165 | + else {
166 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR;
167 | + }
168 | +#endif
169 | *peerp = &peer[n];
170 | peerp = &peer[n].next;
171 | n++;
172 | @@ -225,6 +243,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf,
173 | peer[i].current_weight = 0;
174 | peer[i].max_fails = 1;
175 | peer[i].fail_timeout = 10;
176 | +#if (NGX_HTTP_UPSTREAM_CHECK)
177 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
178 | +#endif
179 | *peerp = &peer[i];
180 | peerp = &peer[i].next;
181 | }
182 | @@ -339,6 +360,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
183 | peer[0].current_weight = 0;
184 | peer[0].max_fails = 1;
185 | peer[0].fail_timeout = 10;
186 | +#if (NGX_HTTP_UPSTREAM_CHECK)
187 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR;
188 | +#endif
189 | peers->peer = peer;
190 |
191 | } else {
192 | @@ -381,6 +405,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r,
193 | peer[i].current_weight = 0;
194 | peer[i].max_fails = 1;
195 | peer[i].fail_timeout = 10;
196 | +#if (NGX_HTTP_UPSTREAM_CHECK)
197 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR;
198 | +#endif
199 | *peerp = &peer[i];
200 | peerp = &peer[i].next;
201 | }
202 | @@ -441,6 +468,12 @@ ngx_http_upstream_get_round_robin_peer(ngx_peer_connection_t *pc, void *data)
203 | goto failed;
204 | }
205 |
206 | +#if (NGX_HTTP_UPSTREAM_CHECK)
207 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
208 | + goto failed;
209 | + }
210 | +#endif
211 | +
212 | rrp->current = peer;
213 |
214 | } else {
215 | @@ -542,6 +575,12 @@ ngx_http_upstream_get_peer(ngx_http_upstream_rr_peer_data_t *rrp)
216 | continue;
217 | }
218 |
219 | +#if (NGX_HTTP_UPSTREAM_CHECK)
220 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
221 | + continue;
222 | + }
223 | +#endif
224 | +
225 | if (peer->max_fails
226 | && peer->fails >= peer->max_fails
227 | && now - peer->checked <= peer->fail_timeout)
228 | diff --git src/http/ngx_http_upstream_round_robin.h src/http/ngx_http_upstream_round_robin.h
229 | index f2c573f..75e0ed6 100644
230 | --- src/http/ngx_http_upstream_round_robin.h
231 | +++ src/http/ngx_http_upstream_round_robin.h
232 | @@ -35,6 +35,10 @@ struct ngx_http_upstream_rr_peer_s {
233 | ngx_uint_t max_fails;
234 | time_t fail_timeout;
235 |
236 | +#if (NGX_HTTP_UPSTREAM_CHECK)
237 | + ngx_uint_t check_index;
238 | +#endif
239 | +
240 | ngx_uint_t down; /* unsigned down:1; */
241 |
242 | #if (NGX_HTTP_SSL)
243 |
--------------------------------------------------------------------------------
/config:
--------------------------------------------------------------------------------
1 | ngx_feature="ngx_http_upstream_check_module"
2 | ngx_feature_name=
3 | ngx_feature_run=no
4 | ngx_feature_incs=
5 | ngx_feature_path="$ngx_addon_dir"
6 | ngx_feature_deps="$ngx_addon_dir/ngx_http_upstream_check_module.h"
7 | ngx_check_src="$ngx_addon_dir/ngx_http_upstream_check_module.c"
8 | ngx_feature_test="int a;"
9 | . auto/feature
10 |
11 | if [ $ngx_found = yes ]; then
12 | have=NGX_HTTP_UPSTREAM_CHECK . auto/have
13 | CORE_INCS="$CORE_INCS $ngx_feature_path"
14 | ngx_addon_name=ngx_http_upstream_check_module
15 | HTTP_MODULES="$HTTP_MODULES ngx_http_upstream_check_module"
16 | NGX_ADDON_DEPS="$NGX_ADDON_DEPS $ngx_feature_deps"
17 | NGX_ADDON_SRCS="$NGX_ADDON_SRCS $ngx_check_src"
18 | else
19 | cat << END
20 | $0: error: the ngx_http_upstream_check_module addon error.
21 | END
22 | exit 1
23 | fi
24 |
--------------------------------------------------------------------------------
/doc/README.wiki:
--------------------------------------------------------------------------------
1 | = Name =
2 |
3 | '''nginx_http_upstream_check_module''' - support upstream health check with Nginx
4 |
5 | = Synopsis =
6 |
7 |
8 |
9 | http {
10 |
11 | upstream cluster {
12 |
13 | # simple round-robin
14 | server 192.168.0.1:80;
15 | server 192.168.0.2:80;
16 |
17 | check interval=5000 rise=1 fall=3 timeout=4000;
18 |
19 | #check interval=3000 rise=2 fall=5 timeout=1000 type=ssl_hello;
20 |
21 | #check interval=3000 rise=2 fall=5 timeout=1000 type=http;
22 | #check_http_send "HEAD / HTTP/1.0\r\n\r\n";
23 | #check_http_expect_alive http_2xx http_3xx;
24 | }
25 |
26 | server {
27 | listen 80;
28 |
29 | location / {
30 | proxy_pass http://cluster;
31 | }
32 |
33 | location /status {
34 | check_status;
35 |
36 | access_log off;
37 | allow SOME.IP.ADD.RESS;
38 | deny all;
39 | }
40 | }
41 |
42 | }
43 |
44 |
45 | = Description =
46 |
47 | Add the support of health check with the upstream servers.
48 |
49 | = Directives =
50 |
51 | == check ==
52 |
53 | '''syntax:''' ''check interval=milliseconds [fall=count] [rise=count] [timeout=milliseconds] [default_down=true|false] [type=tcp|http|ssl_hello|mysql|ajp|fastcgi]''
54 |
55 | '''default:''' ''none, if parameters omitted, default parameters are interval=30000 fall=5 rise=2 timeout=1000 default_down=true type=tcp''
56 |
57 | '''context:''' ''upstream''
58 |
59 | '''description:''' Add the health check for the upstream servers.
60 |
61 | The parameters' meanings are:
62 |
63 | * ''interval'': the check request's interval time.
64 | * ''fall''(fall_count): After fall_count check failures, the server is marked down.
65 | * ''rise''(rise_count): After rise_count check success, the server is marked up.
66 | * ''timeout'': the check request's timeout.
67 | * ''default_down'': set initial state of backend server, default is down.
68 | * ''port'': specify the check port in the backend servers. It can be different with the original servers port. Default the port is 0 and it means the same as the original backend server.
69 | * ''type'': the check protocol type:
70 | # ''tcp'' is a simple tcp socket connect and peek one byte.
71 | # ''ssl_hello'' sends a client ssl hello packet and receives the server ssl hello packet.
72 | # ''http'' sends a http request packet, receives and parses the http response to diagnose if the upstream server is alive.
73 | # ''mysql'' connects to the mysql server, receives the greeting response to diagnose if the upstream server is alive.
74 | # ''ajp'' sends a AJP Cping packet, receives and parses the AJP Cpong response to diagnose if the upstream server is alive.
75 | # ''fastcgi'' send a fastcgi request, receives and parses the fastcgi response to diagnose if the upstream server is alive.
76 |
77 | == check_http_send ==
78 |
79 | '''syntax:''' ''check_http_send http_packet''
80 |
81 | '''default:''' ''"GET / HTTP/1.0\r\n\r\n"''
82 |
83 | '''context:''' ''upstream''
84 |
85 | '''description:''' If you set the check type is http, then the check function will sends this http packet to check the upstream server.
86 |
87 | == check_http_expect_alive ==
88 |
89 | '''syntax:''' ''check_http_expect_alive [ http_2xx | http_3xx | http_4xx | http_5xx ]''
90 |
91 | '''default:''' ''http_2xx | http_3xx''
92 |
93 | '''context:''' ''upstream''
94 |
95 | '''description:''' These status codes indicate the upstream server's http response is ok, the backend is alive.
96 |
97 | == check_keepalive_requests ==
98 |
99 | '''syntax:''' ''check_keepalive_requests num''
100 |
101 | '''default:''' ''check_keepalive_requests 1''
102 |
103 | '''context:''' ''upstream''
104 |
105 | '''description:''' The directive specifies the number of requests sent on a connection, the default vaule 1 indicates that nginx will certainly close the connection after a request.
106 |
107 | == check_fastcgi_param ==
108 |
109 | '''Syntax:''' ''check_fastcgi_params parameter value''
110 |
111 | '''default:''' see below
112 |
113 | '''context:''' ''upstream''
114 |
115 | '''description:''' If you set the check type is fastcgi, then the check function will sends this fastcgi headers to check the upstream server. The default directive looks like:
116 |
117 |
118 | check_fastcgi_param "REQUEST_METHOD" "GET";
119 | check_fastcgi_param "REQUEST_URI" "/";
120 | check_fastcgi_param "SCRIPT_FILENAME" "index.php";
121 |
122 |
123 | == check_shm_size ==
124 |
125 | '''syntax:''' ''check_shm_size size''
126 |
127 | '''default:''' ''1M''
128 |
129 | '''context:''' ''http''
130 |
131 | '''description:''' Default size is one megabytes. If you check thousands of servers, the shared memory for health check may be not enough, you can enlarge it with this directive.
132 |
133 | == check_status ==
134 |
135 | '''syntax:''' ''check_status [html|csv|json]''
136 |
137 | '''default:''' ''none''
138 |
139 | '''context:''' ''location''
140 |
141 | '''description:''' Display the health checking servers' status by HTTP. This directive should be set in the http block.
142 |
143 | You can specify the default display format. The formats can be `html`, `csv` or `json`. The default type is `html`. It also supports to specify the format by the request argument. Suppose your `check_status` location is '/status', the argument of `format` can change the display page's format. You can do like this:
144 |
145 |
146 | /status?format=html
147 | /status?format=csv
148 | /status?format=json
149 |
150 |
151 | At present, you can fetch the list of servers with the same status by the argument of `status`. For example:
152 |
153 |
154 | /status?format=html&status=down
155 | /status?format=csv&status=up
156 |
157 |
158 | Below it's the sample html page:
159 |
160 |
161 |
163 |
164 |
165 | Nginx http upstream check status
166 |
167 |
168 | Nginx http upstream check status
169 | Check upstream server number: 1, generation: 3
170 |
171 |
172 | Index |
173 | Upstream |
174 | Name |
175 | Status |
176 | Rise counts |
177 | Fall counts |
178 | Check type |
179 | Check port |
180 |
181 |
182 | 0 |
183 | backend |
184 | 106.187.48.116:80 |
185 | up |
186 | 39 |
187 | 0 |
188 | http |
189 | 80 |
190 |
191 |
192 |
193 |
194 |
195 | Below it's the sample of csv page:
196 |
197 |
198 | 0,backend,106.187.48.116:80,up,46,0,http,80
199 |
200 |
201 | Below it's the sample of json page:
202 |
203 |
204 | {"servers": {
205 | "total": 1,
206 | "generation": 3,
207 | "server": [
208 | {"index": 0, "upstream": "backend", "name": "106.187.48.116:80", "status": "up", "rise": 58, "fall": 0, "type": "http", "port": 80}
209 | ]
210 | }}
211 |
212 |
213 |
214 | = Installation =
215 |
216 | Download the latest version of the release tarball of this module from [http://github.com/yaoweibin/nginx_upstream_check_module github]
217 |
218 | Grab the nginx source code from [http://nginx.org/ nginx.org], for example, the version 1.0.14 (see nginx compatibility), and then build the source with this module:
219 |
220 |
221 | $ wget 'http://nginx.org/download/nginx-1.0.14.tar.gz'
222 | $ tar -xzvf nginx-1.0.14.tar.gz
223 | $ cd nginx-1.0.14/
224 | $ patch -p1 < /path/to/nginx_http_upstream_check_module/check.patch
225 |
226 | $ ./configure --add-module=/path/to/nginx_http_upstream_check_module
227 |
228 | $ make
229 | $ make install
230 |
231 |
232 | = Note =
233 |
234 | If you use nginx-1.2.1 or nginx-1.3.0, the nginx upstream round robin module changed greatly. You should use the patch named 'check_1.2.1.patch'.
235 |
236 | If you use nginx-1.2.2+ or nginx-1.3.1+, It added the upstream least_conn module. You should use the patch named 'check_1.2.2+.patch'.
237 |
238 | If you use nginx-1.2.6+ or nginx-1.3.9+, It adjusted the round robin module. You should use the patch named 'check_1.2.6+.patch'.
239 |
240 | If you use nginx-1.5.12+, You should use the patch named 'check_1.5.12+.patch'.
241 |
242 | If you use nginx-1.7.2+, You should use the patch named 'check_1.7.2+.patch'.
243 |
244 | The patch just adds the support for the official Round-Robin, Ip_hash and least_conn upstream module. But it's easy to expand my module to other upstream modules. See the patch for detail.
245 |
246 | If you want to add the support for upstream fair module, you can do it like this:
247 |
248 |
249 | $ git clone git://github.com/gnosek/nginx-upstream-fair.git
250 | $ cd nginx-upstream-fair
251 | $ patch -p2 < /path/to/nginx_http_upstream_check_module/upstream_fair.patch
252 | $ cd /path/to/nginx-1.0.14
253 | $ ./configure --add-module=/path/to/nginx_http_upstream_check_module --add-module=/path/to/nginx-upstream-fair-module
254 | $ make
255 | $ make install
256 |
257 |
258 | If you want to add the support for nginx sticky module, you can do it like this:
259 |
260 |
261 | $ svn checkout http://nginx-sticky-module.googlecode.com/svn/trunk/ nginx-sticky-module
262 | $ cd nginx-sticky-module
263 | $ patch -p0 < /path/to/nginx_http_upstream_check_module/nginx-sticky-module.patch
264 | $ cd /path/to/nginx-1.0.14
265 | $ ./configure --add-module=/path/to/nginx_http_upstream_check_module --add-module=/path/to/nginx-sticky-module
266 | $ make
267 | $ make install
268 |
269 |
270 | Note that, the nginx-sticky-module also needs the original check.patch.
271 |
272 |
273 | = Compatibility =
274 |
275 | * The module version 0.1.5 should be compatibility with 0.7.67+
276 | * The module version 0.1.8 should be compatibility with Nginx-1.0.14+
277 |
278 | = Notes =
279 |
280 | = TODO =
281 |
282 | = Known Issues =
283 |
284 | = Changelogs =
285 |
286 | == v0.3 ==
287 | * support keepalive check requests
288 | * fastcgi check requests
289 | * json/csv check status page support
290 |
291 | == v0.1 ==
292 | * first release
293 |
294 | = Authors =
295 |
296 | Weibin Yao(姚伟斌) ''yaoweibin at gmail dot com''
297 |
298 | Matthieu Tourne
299 |
300 |
301 | = Copyright & License =
302 |
303 | This README template copy from [http://github.com/agentzh agentzh].
304 |
305 | The health check part is borrowed the design of Jack Lindamood's healthcheck module [http://github.com/cep21/healthcheck_nginx_upstreams healthcheck_nginx_upstreams];
306 |
307 | This module is licensed under the BSD license.
308 |
309 | Copyright (C) 2014 by Weibin Yao
310 |
311 | Copyright (C) 2010-2014 Alibaba Group Holding Limited
312 |
313 | Copyright (C) 2014 by LiangBin Li
314 |
315 | Copyright (C) 2014 by Zhuo Yuan
316 |
317 | Copyright (C) 2012 by Matthieu Tourne
318 |
319 | All rights reserved.
320 |
321 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
322 |
323 | * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
324 | * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
325 |
326 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
327 |
328 |
--------------------------------------------------------------------------------
/nginx-sticky-module.patch:
--------------------------------------------------------------------------------
1 | Index: ngx_http_sticky_module.c
2 | ===================================================================
3 | --- ngx_http_sticky_module.c (revision 45)
4 | +++ ngx_http_sticky_module.c (working copy)
5 | @@ -10,6 +10,11 @@
6 |
7 | #include "ngx_http_sticky_misc.h"
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 | +
14 | /* define a peer */
15 | typedef struct {
16 | ngx_http_upstream_rr_peer_t *rr_peer;
17 | @@ -287,6 +292,16 @@
18 | return NGX_BUSY;
19 | }
20 |
21 | +#if (NGX_HTTP_UPSTREAM_CHECK)
22 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
23 | + "get sticky peer, check_index: %ui",
24 | + peer->check_index);
25 | +
26 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
27 | + return NGX_BUSY;
28 | + }
29 | +#endif
30 | +
31 | /* if it's been ignored for long enought (fail_timeout), reset timeout */
32 | /* do this check before testing peer->fails ! :) */
33 | if (now - peer->accessed > peer->fail_timeout) {
34 | @@ -303,6 +318,14 @@
35 | /* ensure the peer is not marked as down */
36 | if (!peer->down) {
37 |
38 | +#if (NGX_HTTP_UPSTREAM_CHECK)
39 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
40 | + "get sticky peer, check_index: %ui",
41 | + peer->check_index);
42 | +
43 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
44 | +#endif
45 | +
46 | /* if it's not failedi, use it */
47 | if (peer->max_fails == 0 || peer->fails < peer->max_fails) {
48 | selected_peer = (ngx_int_t)n;
49 | @@ -317,6 +340,9 @@
50 | /* mark the peer as tried */
51 | iphp->rrp.tried[n] |= m;
52 | }
53 | +#if (NGX_HTTP_UPSTREAM_CHECK)
54 | + }
55 | +#endif
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/nginx-tests/fastcgi_check.t:
--------------------------------------------------------------------------------
1 | #!/usr/bin/perl
2 |
3 | use warnings;
4 | use strict;
5 |
6 | use Test::More;
7 |
8 | BEGIN { use FindBin; chdir($FindBin::Bin); }
9 |
10 | use lib 'lib';
11 | use Test::Nginx;
12 |
13 | ###############################################################################
14 |
15 | select STDERR; $| = 1;
16 | select STDOUT; $| = 1;
17 |
18 | eval { require FCGI; };
19 | plan(skip_all => 'FCGI not installed') if $@;
20 | plan(skip_all => 'win32') if $^O eq 'MSWin32';
21 |
22 | my $t = Test::Nginx->new()->has(qw/http fastcgi/)->plan(30)
23 | ->write_file_expand('nginx.conf', <<'EOF');
24 |
25 | %%TEST_GLOBALS%%
26 |
27 | daemon off;
28 |
29 | events {
30 | }
31 |
32 | http {
33 | %%TEST_GLOBALS_HTTP%%
34 |
35 | server {
36 | listen 127.0.0.1:8080;
37 | server_name localhost;
38 |
39 | location / {
40 | fastcgi_pass 127.0.0.1:8081;
41 | fastcgi_param REQUEST_URI $request_uri;
42 | }
43 | }
44 | }
45 |
46 | EOF
47 |
48 | $t->run_daemon(\&fastcgi_daemon);
49 | $t->run();
50 |
51 | ###############################################################################
52 |
53 | like(http_get('/'), qr/SEE-THIS/, 'fastcgi request');
54 | like(http_get('/redir'), qr/302/, 'fastcgi redirect');
55 | like(http_get('/'), qr/^3$/m, 'fastcgi third request');
56 |
57 | unlike(http_head('/'), qr/SEE-THIS/, 'no data in HEAD');
58 |
59 | like(http_get('/stderr'), qr/SEE-THIS/, 'large stderr handled');
60 |
61 | $t->stop();
62 | $t->stop_daemons();
63 |
64 | ###############################################################################
65 |
66 | $t->write_file_expand('nginx.conf', <<'EOF');
67 |
68 | %%TEST_GLOBALS%%
69 |
70 | daemon off;
71 |
72 | worker_processes auto;
73 |
74 | events {
75 | accept_mutex off;
76 | }
77 |
78 | http {
79 | %%TEST_GLOBALS_HTTP%%
80 |
81 | upstream fastcgi {
82 | server 127.0.0.1:8081;
83 | check interval=3000 rise=2 fall=3 timeout=1000 type=fastcgi default_down=false;
84 | check_fastcgi_param "REQUEST_METHOD" "GET";
85 | check_fastcgi_param "REQUEST_URI" "/redir";
86 | check_http_expect_alive http_3xx;
87 | }
88 |
89 | server {
90 | listen 127.0.0.1:8080;
91 | server_name localhost;
92 |
93 | location / {
94 | fastcgi_pass fastcgi;
95 | fastcgi_param REQUEST_URI $request_uri;
96 | }
97 | }
98 | }
99 |
100 | EOF
101 |
102 | $t->run();
103 | $t->run_daemon(\&fastcgi_daemon);
104 |
105 | ###############################################################################
106 |
107 | like(http_get('/'), qr/SEE-THIS/, 'fastcgi request default_down=false');
108 | like(http_get('/redir'), qr/302/, 'fastcgi redirect default_down=false');
109 | like(http_get('/'), qr/^3$/m, 'fastcgi third request default_down=false');
110 |
111 | unlike(http_head('/'), qr/SEE-THIS/, 'no data in HEAD default_down=false');
112 |
113 | like(http_get('/stderr'), qr/SEE-THIS/, 'large stderr handled default_down=false');
114 |
115 | $t->stop();
116 | $t->stop_daemons();
117 |
118 | ###############################################################################
119 |
120 | $t->write_file_expand('nginx.conf', <<'EOF');
121 |
122 | %%TEST_GLOBALS%%
123 |
124 | daemon off;
125 |
126 | worker_processes auto;
127 |
128 | events {
129 | accept_mutex off;
130 | }
131 |
132 | http {
133 | %%TEST_GLOBALS_HTTP%%
134 |
135 | upstream fastcgi {
136 | server 127.0.0.1:8081;
137 | check interval=3000 rise=2 fall=3 timeout=1000 type=fastcgi;
138 | check_fastcgi_param "REQUEST_METHOD" "GET";
139 | check_fastcgi_param "REQUEST_URI" "/redir";
140 | check_http_expect_alive http_3xx;
141 | }
142 |
143 | server {
144 | listen 127.0.0.1:8080;
145 | server_name localhost;
146 |
147 | location / {
148 | fastcgi_pass fastcgi;
149 | fastcgi_param REQUEST_URI $request_uri;
150 | }
151 | }
152 | }
153 |
154 | EOF
155 |
156 | $t->run();
157 | $t->run_daemon(\&fastcgi_daemon);
158 |
159 | ###############################################################################
160 |
161 | like(http_get('/'), qr/502/m, 'fastcgi request default_down=true');
162 | like(http_get('/redir'), qr/502/m, 'fastcgi redirect default_down=true');
163 | like(http_get('/'), qr/502/m, 'fastcgi third request default_down=true');
164 | like(http_head('/'), qr/502/m, 'no data in HEAD default_down=true');
165 | like(http_get('/stderr'), qr/502/m, 'large stderr handled default_down=true');
166 |
167 | $t->stop();
168 | $t->stop_daemons();
169 |
170 | ###############################################################################
171 |
172 | $t->write_file_expand('nginx.conf', <<'EOF');
173 |
174 | %%TEST_GLOBALS%%
175 |
176 | daemon off;
177 |
178 | worker_processes auto;
179 |
180 | events {
181 | accept_mutex off;
182 | }
183 |
184 | http {
185 | %%TEST_GLOBALS_HTTP%%
186 |
187 | upstream fastcgi {
188 | server 127.0.0.1:8081;
189 | check interval=3000 rise=2 fall=3 timeout=1000 type=fastcgi;
190 | check_fastcgi_param "REQUEST_METHOD" "GET";
191 | check_fastcgi_param "REQUEST_URI" "/redir";
192 | check_http_expect_alive http_3xx;
193 | }
194 |
195 | server {
196 | listen 127.0.0.1:8080;
197 | server_name localhost;
198 |
199 | location / {
200 | fastcgi_pass fastcgi;
201 | fastcgi_param REQUEST_URI $request_uri;
202 | }
203 | }
204 | }
205 |
206 | EOF
207 |
208 | $t->run();
209 | $t->run_daemon(\&fastcgi_daemon);
210 |
211 | ###############################################################################
212 |
213 | sleep(5);
214 |
215 | like(http_get('/'), qr/SEE-THIS/, 'fastcgi request default_down=false check 302');
216 | like(http_get('/redir'), qr/302/, 'fastcgi redirect default_down=false check 302');
217 | like(http_get('/'), qr/^\d$/m, 'fastcgi third request default_down=false check 302');
218 |
219 | unlike(http_head('/'), qr/SEE-THIS/, 'no data in HEAD default_down=false check 302');
220 |
221 | like(http_get('/stderr'), qr/SEE-THIS/, 'large stderr handled default_down=false check 302');
222 |
223 | $t->stop();
224 | $t->stop_daemons();
225 |
226 |
227 | ###############################################################################
228 |
229 | $t->write_file_expand('nginx.conf', <<'EOF');
230 |
231 | %%TEST_GLOBALS%%
232 |
233 | daemon off;
234 |
235 | worker_processes auto;
236 |
237 | events {
238 | accept_mutex off;
239 | }
240 |
241 | http {
242 | %%TEST_GLOBALS_HTTP%%
243 |
244 | upstream fastcgi {
245 | server 127.0.0.1:8081;
246 | check interval=1000 rise=1 fall=1 timeout=1000 type=fastcgi;
247 | check_fastcgi_param "REQUEST_METHOD" "GET";
248 | check_fastcgi_param "REQUEST_URI" "/404";
249 | check_http_expect_alive http_2xx;
250 | }
251 |
252 | server {
253 | listen 127.0.0.1:8080;
254 | server_name localhost;
255 |
256 | location / {
257 | fastcgi_pass fastcgi;
258 | fastcgi_param REQUEST_URI $request_uri;
259 | }
260 | }
261 | }
262 |
263 | EOF
264 |
265 | $t->run();
266 | $t->run_daemon(\&fastcgi_daemon);
267 |
268 | ###############################################################################
269 |
270 | sleep(5);
271 |
272 | like(http_get('/'), qr/502/m, 'fastcgi request default_down=true check status heaer');
273 | like(http_get('/redir'), qr/502/m, 'fastcgi redirect default_down=true check status heaer');
274 | like(http_get('/'), qr/502/m, 'fastcgi third request default_down=true check status heaer');
275 | like(http_head('/'), qr/502/m, 'no data in HEAD default_down=true check status heaer');
276 | like(http_get('/stderr'), qr/502/m, 'large stderr handled default_down=true check status heaer');
277 |
278 | $t->stop();
279 | $t->stop_daemons();
280 |
281 |
282 | ###############################################################################
283 |
284 | $t->write_file_expand('nginx.conf', <<'EOF');
285 |
286 | %%TEST_GLOBALS%%
287 |
288 | daemon off;
289 |
290 | worker_processes auto;
291 |
292 | events {
293 | accept_mutex off;
294 | }
295 |
296 | http {
297 | %%TEST_GLOBALS_HTTP%%
298 |
299 | upstream fastcgi {
300 | server 127.0.0.1:8081;
301 | check interval=1000 rise=1 fall=1 timeout=1000 type=fastcgi;
302 | check_fastcgi_param "REQUEST_METHOD" "GET";
303 | check_fastcgi_param "REQUEST_URI" "/";
304 | check_http_expect_alive http_4xx;
305 | }
306 |
307 | server {
308 | listen 127.0.0.1:8080;
309 | server_name localhost;
310 |
311 | location / {
312 | fastcgi_pass fastcgi;
313 | fastcgi_param REQUEST_URI $request_uri;
314 | }
315 | }
316 | }
317 |
318 | EOF
319 |
320 | $t->run();
321 | $t->run_daemon(\&fastcgi_daemon);
322 |
323 | ###############################################################################
324 |
325 | sleep(5);
326 |
327 | like(http_get('/'), qr/SEE-THIS/, 'fastcgi request default_down=false without status header');
328 | like(http_get('/redir'), qr/302/, 'fastcgi redirect default_down=false without status header');
329 | like(http_get('/'), qr/^\d$/m, 'fastcgi third request default_down=false without status header');
330 |
331 | unlike(http_head('/'), qr/SEE-THIS/, 'no data in HEAD default_down=false without status header');
332 |
333 | like(http_get('/stderr'), qr/SEE-THIS/, 'large stderr handled default_down=false without status header');
334 |
335 | $t->stop();
336 | $t->stop_daemons();
337 |
338 |
339 | ###############################################################################
340 |
341 | sub fastcgi_daemon {
342 | my $socket = FCGI::OpenSocket('127.0.0.1:8081', 5);
343 | my $request = FCGI::Request(\*STDIN, \*STDOUT, \*STDERR, \%ENV,
344 | $socket);
345 |
346 | my $count;
347 | while ( $request->Accept() >= 0 ) {
348 | $count++;
349 |
350 | if ($ENV{REQUEST_URI} eq '/stderr') {
351 | warn "sample stderr text" x 512;
352 | }
353 |
354 | if ($ENV{REQUEST_URI} eq '/404') {
355 | print <
6 | #include
7 | #include
8 |
9 | ngx_uint_t ngx_http_upstream_check_add_peer(ngx_conf_t *cf,
10 | ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer);
11 |
12 | ngx_uint_t ngx_http_upstream_check_peer_down(ngx_uint_t index);
13 |
14 | void ngx_http_upstream_check_get_peer(ngx_uint_t index);
15 | void ngx_http_upstream_check_free_peer(ngx_uint_t index);
16 |
17 | ngx_uint_t ngx_http_upstream_check_add_dynamic_peer(ngx_pool_t *pool,
18 | ngx_http_upstream_srv_conf_t *us, ngx_addr_t *peer);
19 | void ngx_http_upstream_check_delete_dynamic_peer(ngx_str_t *name,
20 | ngx_addr_t *peer_addr);
21 |
22 |
23 | #endif //_NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_
24 |
--------------------------------------------------------------------------------
/ngx_http_upstream_jvm_route_module.patch:
--------------------------------------------------------------------------------
1 | diff --git a/ngx_http_upstream_jvm_route_module.c b/ngx_http_upstream_jvm_route_module.c
2 | index 770cfa5..e8e079b 100644
3 | --- a/ngx_http_upstream_jvm_route_module.c
4 | +++ b/ngx_http_upstream_jvm_route_module.c
5 | @@ -13,6 +13,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 |
14 | #define SHM_NAME_LEN 256
15 |
16 | @@ -73,6 +77,9 @@ typedef struct {
17 | time_t fail_timeout;
18 | ngx_uint_t down; /* unsigned down:1; */
19 | ngx_str_t srun_id;
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_uint_t check_index;
22 | +#endif
23 |
24 | #if (NGX_HTTP_SSL)
25 | ngx_ssl_session_t *ssl_session; /* local to a process */
26 | @@ -380,6 +387,15 @@ ngx_http_upstream_init_jvm_route_rr(ngx_conf_t *cf,
27 | peers->peer[n].fail_timeout = server[i].fail_timeout;
28 | peers->peer[n].down = server[i].down;
29 | peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
30 | +#if (NGX_HTTP_UPSTREAM_CHECK)
31 | + if (!server[i].down) {
32 | + peers->peer[n].check_index =
33 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
34 | + }
35 | + else {
36 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
37 | + }
38 | +#endif
39 |
40 | n++;
41 | }
42 | @@ -433,6 +449,15 @@ ngx_http_upstream_init_jvm_route_rr(ngx_conf_t *cf,
43 | backup->peer[n].max_busy = server[i].max_busy;
44 | backup->peer[n].fail_timeout = server[i].fail_timeout;
45 | backup->peer[n].down = server[i].down;
46 | +#if (NGX_HTTP_UPSTREAM_CHECK)
47 | + if (!server[i].down) {
48 | + peers->peer[n].check_index =
49 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
50 | + }
51 | + else {
52 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
53 | + }
54 | +#endif
55 |
56 | n++;
57 | }
58 | @@ -490,6 +515,9 @@ ngx_http_upstream_init_jvm_route_rr(ngx_conf_t *cf,
59 | peers->peer[i].max_fails = 1;
60 | peers->peer[i].max_busy = 0;
61 | peers->peer[i].fail_timeout = 10;
62 | +#if (NGX_HTTP_UPSTREAM_CHECK)
63 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
64 | +#endif
65 | }
66 |
67 | us->peer.data = peers;
68 | @@ -773,6 +801,12 @@ ngx_http_upstream_jvm_route_try_peer( ngx_http_upstream_jvm_route_peer_data_t *j
69 | return NGX_BUSY;
70 | }
71 |
72 | +#if (NGX_HTTP_UPSTREAM_CHECK)
73 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) {
74 | + return NGX_BUSY;
75 | + }
76 | +#endif
77 | +
78 | if (!peer->down) {
79 | if (peer->max_fails == 0 || peer->shared->fails < peer->max_fails) {
80 | return NGX_OK;
81 |
--------------------------------------------------------------------------------
/test/README:
--------------------------------------------------------------------------------
1 | NAME
2 | Test::Nginx - Testing modules for Nginx C module development
3 |
4 | DESCRIPTION
5 | This distribution provides two testing modules for Nginx C module
6 | development:
7 |
8 | * Test::Nginx::LWP
9 |
10 | * Test::Nginx::Socket
11 |
12 | All of them are based on Test::Base.
13 |
14 | Usually, Test::Nginx::Socket is preferred because it works on a much
15 | lower level and not that fault tolerant like Test::Nginx::LWP.
16 |
17 | Also, a lot of connection hang issues (like wrong "r->main->count" value
18 | in nginx 0.8.x) can only be captured by Test::Nginx::Socket because
19 | Perl's LWP::UserAgent client will close the connection itself which will
20 | conceal such issues from the testers.
21 |
22 | Test::Nginx automatically starts an nginx instance (from the "PATH" env)
23 | rooted at t/servroot/ and the default config template makes this nginx
24 | instance listen on the port 1984 by default. One can specify a different
25 | port number by setting his port number to the "TEST_NGINX_PORT"
26 | environment, as in
27 |
28 | export TEST_NGINX_PORT=1989
29 |
30 | etcproxy integration
31 | The default settings in etcproxy
32 | (https://github.com/chaoslawful/etcproxy) makes this small TCP proxy
33 | split the TCP packets into bytes and introduce 1 ms latency among them.
34 |
35 | There's usually various TCP chains that we can put etcproxy into, for
36 | example
37 |
38 | Test::Nginx <=> nginx
39 | $ ./etcproxy 1234 1984
40 |
41 | Here we tell etcproxy to listen on port 1234 and to delegate all the TCP
42 | traffic to the port 1984, the default port that Test::Nginx makes nginx
43 | listen to.
44 |
45 | And then we tell Test::Nginx to test against the port 1234, where
46 | etcproxy listens on, rather than the port 1984 that nginx directly
47 | listens on:
48 |
49 | $ TEST_NGINX_CLIENT_PORT=1234 prove -r t/
50 |
51 | Then the TCP chain now looks like this:
52 |
53 | Test::Nginx <=> etcproxy (1234) <=> nginx (1984)
54 |
55 | So etcproxy can effectively emulate extreme network conditions and
56 | exercise "unusual" code paths in your nginx server by your tests.
57 |
58 | In practice, *tons* of weird bugs can be captured by this setting. Even
59 | ourselves didn't expect that this simple approach is so effective.
60 |
61 | nginx <=> memcached
62 | We first start the memcached server daemon on port 11211:
63 |
64 | memcached -p 11211 -vv
65 |
66 | and then we another etcproxy instance to listen on port 11984 like this
67 |
68 | $ ./etcproxy 11984 11211
69 |
70 | Then we tell our t/foo.t test script to connect to 11984 rather than
71 | 11211:
72 |
73 | # foo.t
74 | use Test::Nginx::Socket;
75 | repeat_each(1);
76 | plan tests => 2 * repeat_each() * blocks();
77 | $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; # make this env take a default value
78 | run_tests();
79 |
80 | __DATA__
81 |
82 | === TEST 1: sanity
83 | --- config
84 | location /foo {
85 | set $memc_cmd set;
86 | set $memc_key foo;
87 | set $memc_value bar;
88 | memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT;
89 | }
90 | --- request
91 | GET /foo
92 | --- response_body_like: STORED
93 |
94 | The Test::Nginx library will automatically expand the special macro
95 | $TEST_NGINX_MEMCACHED_PORT to the environment with the same name. You
96 | can define your own $TEST_NGINX_BLAH_BLAH_PORT macros as long as its
97 | prefix is "TEST_NGINX_" and all in upper case letters.
98 |
99 | And now we can run your test script against the etcproxy port 11984:
100 |
101 | TEST_NGINX_MEMCACHED_PORT=11984 prove t/foo.t
102 |
103 | Then the TCP chains look like this:
104 |
105 | Test::Nginx <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211)
106 |
107 | If "TEST_NGINX_MEMCACHED_PORT" is not set, then it will take the default
108 | value 11211, which is what we want when there's no etcproxy configured:
109 |
110 | Test::Nginx <=> nginx (1984) <=> memcached (11211)
111 |
112 | This approach also works for proxied mysql and postgres traffic. Please
113 | see the live test suite of ngx_drizzle and ngx_postgres for more
114 | details.
115 |
116 | Usually we set both "TEST_NGINX_CLIENT_PORT" and
117 | "TEST_NGINX_MEMCACHED_PORT" (and etc) at the same time, effectively
118 | yielding the following chain:
119 |
120 | Test::Nginx <=> etcproxy (1234) <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211)
121 |
122 | as long as you run two separate etcproxy instances in two separate
123 | terminals.
124 |
125 | It's easy to verify if the traffic actually goes through your etcproxy
126 | server. Just check if the terminal running etcproxy emits outputs. By
127 | default, etcproxy always dump out the incoming and outgoing data to
128 | stdout/stderr.
129 |
130 | valgrind integration
131 | Test::Nginx has integrated support for valgrind ()
132 | even though by default it does not bother running it with the tests
133 | because valgrind will significantly slow down the test sutie.
134 |
135 | First ensure that your valgrind executable visible in your PATH env. And
136 | then run your test suite with the "TEST_NGINX_USE_VALGRIND" env set to
137 | true:
138 |
139 | TEST_NGINX_USE_VALGRIND=1 prove -r t
140 |
141 | If you see false alarms, you do have a chance to skip them by defining a
142 | ./valgrind.suppress file at the root of your module source tree, as in
143 |
144 |
146 |
147 | This is the suppression file for ngx_drizzle. Test::Nginx will
148 | automatically use it to start nginx with valgrind memcheck if this file
149 | does exist at the expected location.
150 |
151 | If you do see a lot of "Connection refused" errors while running the
152 | tests this way, then you probably have a slow machine (or a very busy
153 | one) that the default waiting time is not sufficient for valgrind to
154 | start. You can define the sleep time to a larger value by setting the
155 | "TEST_NGINX_SLEEP" env:
156 |
157 | TEST_NGINX_SLEEP=1 prove -r t
158 |
159 | The time unit used here is "second". The default sleep setting just fits
160 | my ThinkPad ("Core2Duo T9600").
161 |
162 | Applying the no-pool patch to your nginx core is recommended while
163 | running nginx with valgrind:
164 |
165 |
166 |
167 | The nginx memory pool can prevent valgrind from spotting lots of invalid
168 | memory reads/writes as well as certain double-free errors. We did find a
169 | lot more memory issues in many of our modules when we first introduced
170 | the no-pool patch in practice ;)
171 |
172 | There's also more advanced features in Test::Nginx that have never
173 | documented. I'd like to write more about them in the near future ;)
174 |
175 | Nginx C modules that use Test::Nginx to drive their test suites
176 | ngx_echo
177 |
178 |
179 | ngx_headers_more
180 |
181 |
182 | ngx_chunkin
183 |
184 |
185 | ngx_memc
186 |
187 |
188 | ngx_drizzle
189 |
190 |
191 | ngx_rds_json
192 |
193 |
194 | ngx_rds_csv
195 |
196 |
197 | ngx_xss
198 |
199 |
200 | ngx_srcache
201 |
202 |
203 | ngx_lua
204 |
205 |
206 | ngx_set_misc
207 |
208 |
209 | ngx_array_var
210 |
211 |
212 | ngx_form_input
213 |
214 |
215 | ngx_iconv
216 |
217 |
218 | ngx_set_cconv
219 |
220 |
221 | ngx_postgres
222 |
223 |
224 | ngx_coolkit
225 |
226 |
227 | Naxsi
228 |
229 |
230 | SOURCE REPOSITORY
231 | This module has a Git repository on Github, which has access for all.
232 |
233 | http://github.com/agentzh/test-nginx
234 |
235 | If you want a commit bit, feel free to drop me a line.
236 |
237 | AUTHORS
238 | agentzh (章亦春) ""
239 |
240 | Antoine BONAVITA ""
241 |
242 | COPYRIGHT & LICENSE
243 | Copyright (c) 2009-2012, agentzh "".
244 |
245 | Copyright (c) 2011-2012, Antoine Bonavita
246 | "".
247 |
248 | This module is licensed under the terms of the BSD license.
249 |
250 | Redistribution and use in source and binary forms, with or without
251 | modification, are permitted provided that the following conditions are
252 | met:
253 |
254 | * Redistributions of source code must retain the above copyright
255 | notice, this list of conditions and the following disclaimer.
256 |
257 | * Redistributions in binary form must reproduce the above copyright
258 | notice, this list of conditions and the following disclaimer in the
259 | documentation and/or other materials provided with the distribution.
260 |
261 | * Neither the name of the authors nor the names of its contributors
262 | may be used to endorse or promote products derived from this
263 | software without specific prior written permission.
264 |
265 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
266 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
267 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
268 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
269 | HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
270 | SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
271 | TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
272 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
273 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
274 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
275 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
276 |
277 | SEE ALSO
278 | Test::Nginx::LWP, Test::Nginx::Socket, Test::Base.
279 |
280 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/AutoInstall.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::AutoInstall;
3 |
4 | use strict;
5 | use Module::Install::Base ();
6 |
7 | use vars qw{$VERSION @ISA $ISCORE};
8 | BEGIN {
9 | $VERSION = '1.04';
10 | @ISA = 'Module::Install::Base';
11 | $ISCORE = 1;
12 | }
13 |
14 | sub AutoInstall { $_[0] }
15 |
16 | sub run {
17 | my $self = shift;
18 | $self->auto_install_now(@_);
19 | }
20 |
21 | sub write {
22 | my $self = shift;
23 | $self->auto_install(@_);
24 | }
25 |
26 | sub auto_install {
27 | my $self = shift;
28 | return if $self->{done}++;
29 |
30 | # Flatten array of arrays into a single array
31 | my @core = map @$_, map @$_, grep ref,
32 | $self->build_requires, $self->requires;
33 |
34 | my @config = @_;
35 |
36 | # We'll need Module::AutoInstall
37 | $self->include('Module::AutoInstall');
38 | require Module::AutoInstall;
39 |
40 | my @features_require = Module::AutoInstall->import(
41 | (@config ? (-config => \@config) : ()),
42 | (@core ? (-core => \@core) : ()),
43 | $self->features,
44 | );
45 |
46 | my %seen;
47 | my @requires = map @$_, map @$_, grep ref, $self->requires;
48 | while (my ($mod, $ver) = splice(@requires, 0, 2)) {
49 | $seen{$mod}{$ver}++;
50 | }
51 | my @build_requires = map @$_, map @$_, grep ref, $self->build_requires;
52 | while (my ($mod, $ver) = splice(@build_requires, 0, 2)) {
53 | $seen{$mod}{$ver}++;
54 | }
55 | my @configure_requires = map @$_, map @$_, grep ref, $self->configure_requires;
56 | while (my ($mod, $ver) = splice(@configure_requires, 0, 2)) {
57 | $seen{$mod}{$ver}++;
58 | }
59 |
60 | my @deduped;
61 | while (my ($mod, $ver) = splice(@features_require, 0, 2)) {
62 | push @deduped, $mod => $ver unless $seen{$mod}{$ver}++;
63 | }
64 |
65 | $self->requires(@deduped);
66 |
67 | $self->makemaker_args( Module::AutoInstall::_make_args() );
68 |
69 | my $class = ref($self);
70 | $self->postamble(
71 | "# --- $class section:\n" .
72 | Module::AutoInstall::postamble()
73 | );
74 | }
75 |
76 | sub installdeps_target {
77 | my ($self, @args) = @_;
78 |
79 | $self->include('Module::AutoInstall');
80 | require Module::AutoInstall;
81 |
82 | Module::AutoInstall::_installdeps_target(1);
83 |
84 | $self->auto_install(@args);
85 | }
86 |
87 | sub auto_install_now {
88 | my $self = shift;
89 | $self->auto_install(@_);
90 | Module::AutoInstall::do_install();
91 | }
92 |
93 | 1;
94 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/Base.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::Base;
3 |
4 | use strict 'vars';
5 | use vars qw{$VERSION};
6 | BEGIN {
7 | $VERSION = '1.04';
8 | }
9 |
10 | # Suspend handler for "redefined" warnings
11 | BEGIN {
12 | my $w = $SIG{__WARN__};
13 | $SIG{__WARN__} = sub { $w };
14 | }
15 |
16 | #line 42
17 |
18 | sub new {
19 | my $class = shift;
20 | unless ( defined &{"${class}::call"} ) {
21 | *{"${class}::call"} = sub { shift->_top->call(@_) };
22 | }
23 | unless ( defined &{"${class}::load"} ) {
24 | *{"${class}::load"} = sub { shift->_top->load(@_) };
25 | }
26 | bless { @_ }, $class;
27 | }
28 |
29 | #line 61
30 |
31 | sub AUTOLOAD {
32 | local $@;
33 | my $func = eval { shift->_top->autoload } or return;
34 | goto &$func;
35 | }
36 |
37 | #line 75
38 |
39 | sub _top {
40 | $_[0]->{_top};
41 | }
42 |
43 | #line 90
44 |
45 | sub admin {
46 | $_[0]->_top->{admin}
47 | or
48 | Module::Install::Base::FakeAdmin->new;
49 | }
50 |
51 | #line 106
52 |
53 | sub is_admin {
54 | ! $_[0]->admin->isa('Module::Install::Base::FakeAdmin');
55 | }
56 |
57 | sub DESTROY {}
58 |
59 | package Module::Install::Base::FakeAdmin;
60 |
61 | use vars qw{$VERSION};
62 | BEGIN {
63 | $VERSION = $Module::Install::Base::VERSION;
64 | }
65 |
66 | my $fake;
67 |
68 | sub new {
69 | $fake ||= bless(\@_, $_[0]);
70 | }
71 |
72 | sub AUTOLOAD {}
73 |
74 | sub DESTROY {}
75 |
76 | # Restore warning handler
77 | BEGIN {
78 | $SIG{__WARN__} = $SIG{__WARN__}->();
79 | }
80 |
81 | 1;
82 |
83 | #line 159
84 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/Can.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::Can;
3 |
4 | use strict;
5 | use Config ();
6 | use File::Spec ();
7 | use ExtUtils::MakeMaker ();
8 | use Module::Install::Base ();
9 |
10 | use vars qw{$VERSION @ISA $ISCORE};
11 | BEGIN {
12 | $VERSION = '1.04';
13 | @ISA = 'Module::Install::Base';
14 | $ISCORE = 1;
15 | }
16 |
17 | # check if we can load some module
18 | ### Upgrade this to not have to load the module if possible
19 | sub can_use {
20 | my ($self, $mod, $ver) = @_;
21 | $mod =~ s{::|\\}{/}g;
22 | $mod .= '.pm' unless $mod =~ /\.pm$/i;
23 |
24 | my $pkg = $mod;
25 | $pkg =~ s{/}{::}g;
26 | $pkg =~ s{\.pm$}{}i;
27 |
28 | local $@;
29 | eval { require $mod; $pkg->VERSION($ver || 0); 1 };
30 | }
31 |
32 | # check if we can run some command
33 | sub can_run {
34 | my ($self, $cmd) = @_;
35 |
36 | my $_cmd = $cmd;
37 | return $_cmd if (-x $_cmd or $_cmd = MM->maybe_command($_cmd));
38 |
39 | for my $dir ((split /$Config::Config{path_sep}/, $ENV{PATH}), '.') {
40 | next if $dir eq '';
41 | my $abs = File::Spec->catfile($dir, $_[1]);
42 | return $abs if (-x $abs or $abs = MM->maybe_command($abs));
43 | }
44 |
45 | return;
46 | }
47 |
48 | # can we locate a (the) C compiler
49 | sub can_cc {
50 | my $self = shift;
51 | my @chunks = split(/ /, $Config::Config{cc}) or return;
52 |
53 | # $Config{cc} may contain args; try to find out the program part
54 | while (@chunks) {
55 | return $self->can_run("@chunks") || (pop(@chunks), next);
56 | }
57 |
58 | return;
59 | }
60 |
61 | # Fix Cygwin bug on maybe_command();
62 | if ( $^O eq 'cygwin' ) {
63 | require ExtUtils::MM_Cygwin;
64 | require ExtUtils::MM_Win32;
65 | if ( ! defined(&ExtUtils::MM_Cygwin::maybe_command) ) {
66 | *ExtUtils::MM_Cygwin::maybe_command = sub {
67 | my ($self, $file) = @_;
68 | if ($file =~ m{^/cygdrive/}i and ExtUtils::MM_Win32->can('maybe_command')) {
69 | ExtUtils::MM_Win32->maybe_command($file);
70 | } else {
71 | ExtUtils::MM_Unix->maybe_command($file);
72 | }
73 | }
74 | }
75 | }
76 |
77 | 1;
78 |
79 | __END__
80 |
81 | #line 156
82 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/Fetch.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::Fetch;
3 |
4 | use strict;
5 | use Module::Install::Base ();
6 |
7 | use vars qw{$VERSION @ISA $ISCORE};
8 | BEGIN {
9 | $VERSION = '1.04';
10 | @ISA = 'Module::Install::Base';
11 | $ISCORE = 1;
12 | }
13 |
14 | sub get_file {
15 | my ($self, %args) = @_;
16 | my ($scheme, $host, $path, $file) =
17 | $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return;
18 |
19 | if ( $scheme eq 'http' and ! eval { require LWP::Simple; 1 } ) {
20 | $args{url} = $args{ftp_url}
21 | or (warn("LWP support unavailable!\n"), return);
22 | ($scheme, $host, $path, $file) =
23 | $args{url} =~ m|^(\w+)://([^/]+)(.+)/(.+)| or return;
24 | }
25 |
26 | $|++;
27 | print "Fetching '$file' from $host... ";
28 |
29 | unless (eval { require Socket; Socket::inet_aton($host) }) {
30 | warn "'$host' resolve failed!\n";
31 | return;
32 | }
33 |
34 | return unless $scheme eq 'ftp' or $scheme eq 'http';
35 |
36 | require Cwd;
37 | my $dir = Cwd::getcwd();
38 | chdir $args{local_dir} or return if exists $args{local_dir};
39 |
40 | if (eval { require LWP::Simple; 1 }) {
41 | LWP::Simple::mirror($args{url}, $file);
42 | }
43 | elsif (eval { require Net::FTP; 1 }) { eval {
44 | # use Net::FTP to get past firewall
45 | my $ftp = Net::FTP->new($host, Passive => 1, Timeout => 600);
46 | $ftp->login("anonymous", 'anonymous@example.com');
47 | $ftp->cwd($path);
48 | $ftp->binary;
49 | $ftp->get($file) or (warn("$!\n"), return);
50 | $ftp->quit;
51 | } }
52 | elsif (my $ftp = $self->can_run('ftp')) { eval {
53 | # no Net::FTP, fallback to ftp.exe
54 | require FileHandle;
55 | my $fh = FileHandle->new;
56 |
57 | local $SIG{CHLD} = 'IGNORE';
58 | unless ($fh->open("|$ftp -n")) {
59 | warn "Couldn't open ftp: $!\n";
60 | chdir $dir; return;
61 | }
62 |
63 | my @dialog = split(/\n/, <<"END_FTP");
64 | open $host
65 | user anonymous anonymous\@example.com
66 | cd $path
67 | binary
68 | get $file $file
69 | quit
70 | END_FTP
71 | foreach (@dialog) { $fh->print("$_\n") }
72 | $fh->close;
73 | } }
74 | else {
75 | warn "No working 'ftp' program available!\n";
76 | chdir $dir; return;
77 | }
78 |
79 | unless (-f $file) {
80 | warn "Fetching failed: $@\n";
81 | chdir $dir; return;
82 | }
83 |
84 | return if exists $args{size} and -s $file != $args{size};
85 | system($args{run}) if exists $args{run};
86 | unlink($file) if $args{remove};
87 |
88 | print(((!exists $args{check_for} or -e $args{check_for})
89 | ? "done!" : "failed! ($!)"), "\n");
90 | chdir $dir; return !$?;
91 | }
92 |
93 | 1;
94 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/Include.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::Include;
3 |
4 | use strict;
5 | use Module::Install::Base ();
6 |
7 | use vars qw{$VERSION @ISA $ISCORE};
8 | BEGIN {
9 | $VERSION = '1.04';
10 | @ISA = 'Module::Install::Base';
11 | $ISCORE = 1;
12 | }
13 |
14 | sub include {
15 | shift()->admin->include(@_);
16 | }
17 |
18 | sub include_deps {
19 | shift()->admin->include_deps(@_);
20 | }
21 |
22 | sub auto_include {
23 | shift()->admin->auto_include(@_);
24 | }
25 |
26 | sub auto_include_deps {
27 | shift()->admin->auto_include_deps(@_);
28 | }
29 |
30 | sub auto_include_dependent_dists {
31 | shift()->admin->auto_include_dependent_dists(@_);
32 | }
33 |
34 | 1;
35 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/TestBase.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::TestBase;
3 | use strict;
4 | use warnings;
5 |
6 | use Module::Install::Base;
7 |
8 | use vars qw($VERSION @ISA);
9 | BEGIN {
10 | $VERSION = '0.60';
11 | @ISA = 'Module::Install::Base';
12 | }
13 |
14 | sub use_test_base {
15 | my $self = shift;
16 | $self->include('Test::Base');
17 | $self->include('Test::Base::Filter');
18 | $self->include('Spiffy');
19 | $self->include('Test::More');
20 | $self->include('Test::Builder');
21 | $self->include('Test::Builder::Module');
22 | $self->requires('Filter::Util::Call');
23 | }
24 |
25 | 1;
26 |
27 | =encoding utf8
28 |
29 | #line 70
30 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/Win32.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::Win32;
3 |
4 | use strict;
5 | use Module::Install::Base ();
6 |
7 | use vars qw{$VERSION @ISA $ISCORE};
8 | BEGIN {
9 | $VERSION = '1.04';
10 | @ISA = 'Module::Install::Base';
11 | $ISCORE = 1;
12 | }
13 |
14 | # determine if the user needs nmake, and download it if needed
15 | sub check_nmake {
16 | my $self = shift;
17 | $self->load('can_run');
18 | $self->load('get_file');
19 |
20 | require Config;
21 | return unless (
22 | $^O eq 'MSWin32' and
23 | $Config::Config{make} and
24 | $Config::Config{make} =~ /^nmake\b/i and
25 | ! $self->can_run('nmake')
26 | );
27 |
28 | print "The required 'nmake' executable not found, fetching it...\n";
29 |
30 | require File::Basename;
31 | my $rv = $self->get_file(
32 | url => 'http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe',
33 | ftp_url => 'ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe',
34 | local_dir => File::Basename::dirname($^X),
35 | size => 51928,
36 | run => 'Nmake15.exe /o > nul',
37 | check_for => 'Nmake.exe',
38 | remove => 1,
39 | );
40 |
41 | die <<'END_MESSAGE' unless $rv;
42 |
43 | -------------------------------------------------------------------------------
44 |
45 | Since you are using Microsoft Windows, you will need the 'nmake' utility
46 | before installation. It's available at:
47 |
48 | http://download.microsoft.com/download/vc15/Patch/1.52/W95/EN-US/Nmake15.exe
49 | or
50 | ftp://ftp.microsoft.com/Softlib/MSLFILES/Nmake15.exe
51 |
52 | Please download the file manually, save it to a directory in %PATH% (e.g.
53 | C:\WINDOWS\COMMAND\), then launch the MS-DOS command line shell, "cd" to
54 | that directory, and run "Nmake15.exe" from there; that will create the
55 | 'nmake.exe' file needed by this module.
56 |
57 | You may then resume the installation process described in README.
58 |
59 | -------------------------------------------------------------------------------
60 | END_MESSAGE
61 |
62 | }
63 |
64 | 1;
65 |
--------------------------------------------------------------------------------
/test/inc/Module/Install/WriteAll.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Module::Install::WriteAll;
3 |
4 | use strict;
5 | use Module::Install::Base ();
6 |
7 | use vars qw{$VERSION @ISA $ISCORE};
8 | BEGIN {
9 | $VERSION = '1.04';
10 | @ISA = qw{Module::Install::Base};
11 | $ISCORE = 1;
12 | }
13 |
14 | sub WriteAll {
15 | my $self = shift;
16 | my %args = (
17 | meta => 1,
18 | sign => 0,
19 | inline => 0,
20 | check_nmake => 1,
21 | @_,
22 | );
23 |
24 | $self->sign(1) if $args{sign};
25 | $self->admin->WriteAll(%args) if $self->is_admin;
26 |
27 | $self->check_nmake if $args{check_nmake};
28 | unless ( $self->makemaker_args->{PL_FILES} ) {
29 | # XXX: This still may be a bit over-defensive...
30 | unless ($self->makemaker(6.25)) {
31 | $self->makemaker_args( PL_FILES => {} ) if -f 'Build.PL';
32 | }
33 | }
34 |
35 | # Until ExtUtils::MakeMaker support MYMETA.yml, make sure
36 | # we clean it up properly ourself.
37 | $self->realclean_files('MYMETA.yml');
38 |
39 | if ( $args{inline} ) {
40 | $self->Inline->write;
41 | } else {
42 | $self->Makefile->write;
43 | }
44 |
45 | # The Makefile write process adds a couple of dependencies,
46 | # so write the META.yml files after the Makefile.
47 | if ( $args{meta} ) {
48 | $self->Meta->write;
49 | }
50 |
51 | # Experimental support for MYMETA
52 | if ( $ENV{X_MYMETA} ) {
53 | if ( $ENV{X_MYMETA} eq 'JSON' ) {
54 | $self->Meta->write_mymeta_json;
55 | } else {
56 | $self->Meta->write_mymeta_yaml;
57 | }
58 | }
59 |
60 | return 1;
61 | }
62 |
63 | 1;
64 |
--------------------------------------------------------------------------------
/test/inc/Test/Base/Filter.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | #===============================================================================
3 | # This is the default class for handling Test::Base data filtering.
4 | #===============================================================================
5 | package Test::Base::Filter;
6 | use Spiffy -Base;
7 | use Spiffy ':XXX';
8 |
9 | field 'current_block';
10 |
11 | our $arguments;
12 | sub current_arguments {
13 | return undef unless defined $arguments;
14 | my $args = $arguments;
15 | $args =~ s/(\\s)/ /g;
16 | $args =~ s/(\\[a-z])/'"' . $1 . '"'/gee;
17 | return $args;
18 | }
19 |
20 | sub assert_scalar {
21 | return if @_ == 1;
22 | require Carp;
23 | my $filter = (caller(1))[3];
24 | $filter =~ s/.*:://;
25 | Carp::croak "Input to the '$filter' filter must be a scalar, not a list";
26 | }
27 |
28 | sub _apply_deepest {
29 | my $method = shift;
30 | return () unless @_;
31 | if (ref $_[0] eq 'ARRAY') {
32 | for my $aref (@_) {
33 | @$aref = $self->_apply_deepest($method, @$aref);
34 | }
35 | return @_;
36 | }
37 | $self->$method(@_);
38 | }
39 |
40 | sub _split_array {
41 | map {
42 | [$self->split($_)];
43 | } @_;
44 | }
45 |
46 | sub _peel_deepest {
47 | return () unless @_;
48 | if (ref $_[0] eq 'ARRAY') {
49 | if (ref $_[0]->[0] eq 'ARRAY') {
50 | for my $aref (@_) {
51 | @$aref = $self->_peel_deepest(@$aref);
52 | }
53 | return @_;
54 | }
55 | return map { $_->[0] } @_;
56 | }
57 | return @_;
58 | }
59 |
60 | #===============================================================================
61 | # these filters work on the leaves of nested arrays
62 | #===============================================================================
63 | sub Join { $self->_peel_deepest($self->_apply_deepest(join => @_)) }
64 | sub Reverse { $self->_apply_deepest(reverse => @_) }
65 | sub Split { $self->_apply_deepest(_split_array => @_) }
66 | sub Sort { $self->_apply_deepest(sort => @_) }
67 |
68 |
69 | sub append {
70 | my $suffix = $self->current_arguments;
71 | map { $_ . $suffix } @_;
72 | }
73 |
74 | sub array {
75 | return [@_];
76 | }
77 |
78 | sub base64_decode {
79 | $self->assert_scalar(@_);
80 | require MIME::Base64;
81 | MIME::Base64::decode_base64(shift);
82 | }
83 |
84 | sub base64_encode {
85 | $self->assert_scalar(@_);
86 | require MIME::Base64;
87 | MIME::Base64::encode_base64(shift);
88 | }
89 |
90 | sub chomp {
91 | map { CORE::chomp; $_ } @_;
92 | }
93 |
94 | sub chop {
95 | map { CORE::chop; $_ } @_;
96 | }
97 |
98 | sub dumper {
99 | no warnings 'once';
100 | require Data::Dumper;
101 | local $Data::Dumper::Sortkeys = 1;
102 | local $Data::Dumper::Indent = 1;
103 | local $Data::Dumper::Terse = 1;
104 | Data::Dumper::Dumper(@_);
105 | }
106 |
107 | sub escape {
108 | $self->assert_scalar(@_);
109 | my $text = shift;
110 | $text =~ s/(\\.)/eval "qq{$1}"/ge;
111 | return $text;
112 | }
113 |
114 | sub eval {
115 | $self->assert_scalar(@_);
116 | my @return = CORE::eval(shift);
117 | return $@ if $@;
118 | return @return;
119 | }
120 |
121 | sub eval_all {
122 | $self->assert_scalar(@_);
123 | my $out = '';
124 | my $err = '';
125 | Test::Base::tie_output(*STDOUT, $out);
126 | Test::Base::tie_output(*STDERR, $err);
127 | my $return = CORE::eval(shift);
128 | no warnings;
129 | untie *STDOUT;
130 | untie *STDERR;
131 | return $return, $@, $out, $err;
132 | }
133 |
134 | sub eval_stderr {
135 | $self->assert_scalar(@_);
136 | my $output = '';
137 | Test::Base::tie_output(*STDERR, $output);
138 | CORE::eval(shift);
139 | no warnings;
140 | untie *STDERR;
141 | return $output;
142 | }
143 |
144 | sub eval_stdout {
145 | $self->assert_scalar(@_);
146 | my $output = '';
147 | Test::Base::tie_output(*STDOUT, $output);
148 | CORE::eval(shift);
149 | no warnings;
150 | untie *STDOUT;
151 | return $output;
152 | }
153 |
154 | sub exec_perl_stdout {
155 | my $tmpfile = "/tmp/test-blocks-$$";
156 | $self->_write_to($tmpfile, @_);
157 | open my $execution, "$^X $tmpfile 2>&1 |"
158 | or die "Couldn't open subprocess: $!\n";
159 | local $/;
160 | my $output = <$execution>;
161 | close $execution;
162 | unlink($tmpfile)
163 | or die "Couldn't unlink $tmpfile: $!\n";
164 | return $output;
165 | }
166 |
167 | sub flatten {
168 | $self->assert_scalar(@_);
169 | my $ref = shift;
170 | if (ref($ref) eq 'HASH') {
171 | return map {
172 | ($_, $ref->{$_});
173 | } sort keys %$ref;
174 | }
175 | if (ref($ref) eq 'ARRAY') {
176 | return @$ref;
177 | }
178 | die "Can only flatten a hash or array ref";
179 | }
180 |
181 | sub get_url {
182 | $self->assert_scalar(@_);
183 | my $url = shift;
184 | CORE::chomp($url);
185 | require LWP::Simple;
186 | LWP::Simple::get($url);
187 | }
188 |
189 | sub hash {
190 | return +{ @_ };
191 | }
192 |
193 | sub head {
194 | my $size = $self->current_arguments || 1;
195 | return splice(@_, 0, $size);
196 | }
197 |
198 | sub join {
199 | my $string = $self->current_arguments;
200 | $string = '' unless defined $string;
201 | CORE::join $string, @_;
202 | }
203 |
204 | sub lines {
205 | $self->assert_scalar(@_);
206 | my $text = shift;
207 | return () unless length $text;
208 | my @lines = ($text =~ /^(.*\n?)/gm);
209 | return @lines;
210 | }
211 |
212 | sub norm {
213 | $self->assert_scalar(@_);
214 | my $text = shift;
215 | $text = '' unless defined $text;
216 | $text =~ s/\015\012/\n/g;
217 | $text =~ s/\r/\n/g;
218 | return $text;
219 | }
220 |
221 | sub prepend {
222 | my $prefix = $self->current_arguments;
223 | map { $prefix . $_ } @_;
224 | }
225 |
226 | sub read_file {
227 | $self->assert_scalar(@_);
228 | my $file = shift;
229 | CORE::chomp $file;
230 | open my $fh, $file
231 | or die "Can't open '$file' for input:\n$!";
232 | CORE::join '', <$fh>;
233 | }
234 |
235 | sub regexp {
236 | $self->assert_scalar(@_);
237 | my $text = shift;
238 | my $flags = $self->current_arguments;
239 | if ($text =~ /\n.*?\n/s) {
240 | $flags = 'xism'
241 | unless defined $flags;
242 | }
243 | else {
244 | CORE::chomp($text);
245 | }
246 | $flags ||= '';
247 | my $regexp = eval "qr{$text}$flags";
248 | die $@ if $@;
249 | return $regexp;
250 | }
251 |
252 | sub reverse {
253 | CORE::reverse(@_);
254 | }
255 |
256 | sub slice {
257 | die "Invalid args for slice"
258 | unless $self->current_arguments =~ /^(\d+)(?:,(\d))?$/;
259 | my ($x, $y) = ($1, $2);
260 | $y = $x if not defined $y;
261 | die "Invalid args for slice"
262 | if $x > $y;
263 | return splice(@_, $x, 1 + $y - $x);
264 | }
265 |
266 | sub sort {
267 | CORE::sort(@_);
268 | }
269 |
270 | sub split {
271 | $self->assert_scalar(@_);
272 | my $separator = $self->current_arguments;
273 | if (defined $separator and $separator =~ s{^/(.*)/$}{$1}) {
274 | my $regexp = $1;
275 | $separator = qr{$regexp};
276 | }
277 | $separator = qr/\s+/ unless $separator;
278 | CORE::split $separator, shift;
279 | }
280 |
281 | sub strict {
282 | $self->assert_scalar(@_);
283 | <<'...' . shift;
284 | use strict;
285 | use warnings;
286 | ...
287 | }
288 |
289 | sub tail {
290 | my $size = $self->current_arguments || 1;
291 | return splice(@_, @_ - $size, $size);
292 | }
293 |
294 | sub trim {
295 | map {
296 | s/\A([ \t]*\n)+//;
297 | s/(?<=\n)\s*\z//g;
298 | $_;
299 | } @_;
300 | }
301 |
302 | sub unchomp {
303 | map { $_ . "\n" } @_;
304 | }
305 |
306 | sub write_file {
307 | my $file = $self->current_arguments
308 | or die "No file specified for write_file filter";
309 | if ($file =~ /(.*)[\\\/]/) {
310 | my $dir = $1;
311 | if (not -e $dir) {
312 | require File::Path;
313 | File::Path::mkpath($dir)
314 | or die "Can't create $dir";
315 | }
316 | }
317 | open my $fh, ">$file"
318 | or die "Can't open '$file' for output\n:$!";
319 | print $fh @_;
320 | close $fh;
321 | return $file;
322 | }
323 |
324 | sub yaml {
325 | $self->assert_scalar(@_);
326 | require YAML;
327 | return YAML::Load(shift);
328 | }
329 |
330 | sub _write_to {
331 | my $filename = shift;
332 | open my $script, ">$filename"
333 | or die "Couldn't open $filename: $!\n";
334 | print $script @_;
335 | close $script
336 | or die "Couldn't close $filename: $!\n";
337 | }
338 |
339 | __DATA__
340 |
341 | #line 636
342 |
--------------------------------------------------------------------------------
/test/inc/Test/Builder/Module.pm:
--------------------------------------------------------------------------------
1 | #line 1
2 | package Test::Builder::Module;
3 |
4 | use strict;
5 |
6 | use Test::Builder;
7 |
8 | require Exporter;
9 | our @ISA = qw(Exporter);
10 |
11 | our $VERSION = '0.92';
12 | $VERSION = eval $VERSION; ## no critic (BuiltinFunctions::ProhibitStringyEval)
13 |
14 | # 5.004's Exporter doesn't have export_to_level.
15 | my $_export_to_level = sub {
16 | my $pkg = shift;
17 | my $level = shift;
18 | (undef) = shift; # redundant arg
19 | my $callpkg = caller($level);
20 | $pkg->export( $callpkg, @_ );
21 | };
22 |
23 | #line 82
24 |
25 | sub import {
26 | my($class) = shift;
27 |
28 | # Don't run all this when loading ourself.
29 | return 1 if $class eq 'Test::Builder::Module';
30 |
31 | my $test = $class->builder;
32 |
33 | my $caller = caller;
34 |
35 | $test->exported_to($caller);
36 |
37 | $class->import_extra( \@_ );
38 | my(@imports) = $class->_strip_imports( \@_ );
39 |
40 | $test->plan(@_);
41 |
42 | $class->$_export_to_level( 1, $class, @imports );
43 | }
44 |
45 | sub _strip_imports {
46 | my $class = shift;
47 | my $list = shift;
48 |
49 | my @imports = ();
50 | my @other = ();
51 | my $idx = 0;
52 | while( $idx <= $#{$list} ) {
53 | my $item = $list->[$idx];
54 |
55 | if( defined $item and $item eq 'import' ) {
56 | push @imports, @{ $list->[ $idx + 1 ] };
57 | $idx++;
58 | }
59 | else {
60 | push @other, $item;
61 | }
62 |
63 | $idx++;
64 | }
65 |
66 | @$list = @other;
67 |
68 | return @imports;
69 | }
70 |
71 | #line 145
72 |
73 | sub import_extra { }
74 |
75 | #line 175
76 |
77 | sub builder {
78 | return Test::Builder->new;
79 | }
80 |
81 | 1;
82 |
--------------------------------------------------------------------------------
/test/lib/Test/Nginx.pm:
--------------------------------------------------------------------------------
1 | package Test::Nginx;
2 |
3 | use strict;
4 | use warnings;
5 |
6 | our $VERSION = '0.18';
7 |
8 | __END__
9 |
10 | =encoding utf-8
11 |
12 | =head1 NAME
13 |
14 | Test::Nginx - Testing modules for Nginx C module development
15 |
16 | =head1 DESCRIPTION
17 |
18 | This distribution provides two testing modules for Nginx C module development:
19 |
20 | =over
21 |
22 | =item *
23 |
24 | L
25 |
26 | =item *
27 |
28 | L
29 |
30 | =back
31 |
32 | All of them are based on L.
33 |
34 | Usually, L is preferred because it works on a much lower
35 | level and not that fault tolerant like L.
36 |
37 | Also, a lot of connection hang issues (like wrong C<< r->main->count >> value in nginx
38 | 0.8.x) can only be captured by L because Perl's L client
39 | will close the connection itself which will conceal such issues from
40 | the testers.
41 |
42 | Test::Nginx automatically starts an nginx instance (from the C env)
43 | rooted at t/servroot/ and the default config template makes this nginx
44 | instance listen on the port C<1984> by default. One can specify a different
45 | port number by setting his port number to the C environment,
46 | as in
47 |
48 | export TEST_NGINX_PORT=1989
49 |
50 | =head2 etcproxy integration
51 |
52 | The default settings in etcproxy (https://github.com/chaoslawful/etcproxy)
53 | makes this small TCP proxy split the TCP packets into bytes and introduce 1 ms latency among them.
54 |
55 | There's usually various TCP chains that we can put etcproxy into, for example
56 |
57 | =head3 Test::Nginx <=> nginx
58 |
59 | $ ./etcproxy 1234 1984
60 |
61 | Here we tell etcproxy to listen on port 1234 and to delegate all the
62 | TCP traffic to the port 1984, the default port that Test::Nginx makes
63 | nginx listen to.
64 |
65 | And then we tell Test::Nginx to test against the port 1234, where
66 | etcproxy listens on, rather than the port 1984 that nginx directly
67 | listens on:
68 |
69 | $ TEST_NGINX_CLIENT_PORT=1234 prove -r t/
70 |
71 | Then the TCP chain now looks like this:
72 |
73 | Test::Nginx <=> etcproxy (1234) <=> nginx (1984)
74 |
75 | So etcproxy can effectively emulate extreme network conditions and
76 | exercise "unusual" code paths in your nginx server by your tests.
77 |
78 | In practice, *tons* of weird bugs can be captured by this setting.
79 | Even ourselves didn't expect that this simple approach is so
80 | effective.
81 |
82 | =head3 nginx <=> memcached
83 |
84 | We first start the memcached server daemon on port 11211:
85 |
86 | memcached -p 11211 -vv
87 |
88 | and then we another etcproxy instance to listen on port 11984 like this
89 |
90 | $ ./etcproxy 11984 11211
91 |
92 | Then we tell our t/foo.t test script to connect to 11984 rather than 11211:
93 |
94 | # foo.t
95 | use Test::Nginx::Socket;
96 | repeat_each(1);
97 | plan tests => 2 * repeat_each() * blocks();
98 | $ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211; # make this env take a default value
99 | run_tests();
100 |
101 | __DATA__
102 |
103 | === TEST 1: sanity
104 | --- config
105 | location /foo {
106 | set $memc_cmd set;
107 | set $memc_key foo;
108 | set $memc_value bar;
109 | memc_pass 127.0.0.1:$TEST_NGINX_MEMCACHED_PORT;
110 | }
111 | --- request
112 | GET /foo
113 | --- response_body_like: STORED
114 |
115 | The Test::Nginx library will automatically expand the special macro
116 | C<$TEST_NGINX_MEMCACHED_PORT> to the environment with the same name.
117 | You can define your own C<$TEST_NGINX_BLAH_BLAH_PORT> macros as long as
118 | its prefix is C and all in upper case letters.
119 |
120 | And now we can run your test script against the etcproxy port 11984:
121 |
122 | TEST_NGINX_MEMCACHED_PORT=11984 prove t/foo.t
123 |
124 | Then the TCP chains look like this:
125 |
126 | Test::Nginx <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211)
127 |
128 | If C is not set, then it will take the default
129 | value 11211, which is what we want when there's no etcproxy
130 | configured:
131 |
132 | Test::Nginx <=> nginx (1984) <=> memcached (11211)
133 |
134 | This approach also works for proxied mysql and postgres traffic.
135 | Please see the live test suite of ngx_drizzle and ngx_postgres for
136 | more details.
137 |
138 | Usually we set both C and
139 | C (and etc) at the same time, effectively
140 | yielding the following chain:
141 |
142 | Test::Nginx <=> etcproxy (1234) <=> nginx (1984) <=> etcproxy (11984) <=> memcached (11211)
143 |
144 | as long as you run two separate etcproxy instances in two separate terminals.
145 |
146 | It's easy to verify if the traffic actually goes through your etcproxy
147 | server. Just check if the terminal running etcproxy emits outputs. By
148 | default, etcproxy always dump out the incoming and outgoing data to
149 | stdout/stderr.
150 |
151 | =head2 valgrind integration
152 |
153 | Test::Nginx has integrated support for valgrind (L) even though by
154 | default it does not bother running it with the tests because valgrind
155 | will significantly slow down the test sutie.
156 |
157 | First ensure that your valgrind executable visible in your PATH env.
158 | And then run your test suite with the C env set
159 | to true:
160 |
161 | TEST_NGINX_USE_VALGRIND=1 prove -r t
162 |
163 | If you see false alarms, you do have a chance to skip them by defining
164 | a ./valgrind.suppress file at the root of your module source tree, as
165 | in
166 |
167 | L
168 |
169 | This is the suppression file for ngx_drizzle. Test::Nginx will
170 | automatically use it to start nginx with valgrind memcheck if this
171 | file does exist at the expected location.
172 |
173 | If you do see a lot of "Connection refused" errors while running the
174 | tests this way, then you probably have a slow machine (or a very busy
175 | one) that the default waiting time is not sufficient for valgrind to
176 | start. You can define the sleep time to a larger value by setting the
177 | C env:
178 |
179 | TEST_NGINX_SLEEP=1 prove -r t
180 |
181 | The time unit used here is "second". The default sleep setting just
182 | fits my ThinkPad (C).
183 |
184 | Applying the no-pool patch to your nginx core is recommended while
185 | running nginx with valgrind:
186 |
187 | L
188 |
189 | The nginx memory pool can prevent valgrind from spotting lots of
190 | invalid memory reads/writes as well as certain double-free errors. We
191 | did find a lot more memory issues in many of our modules when we first
192 | introduced the no-pool patch in practice ;)
193 |
194 | There's also more advanced features in Test::Nginx that have never
195 | documented. I'd like to write more about them in the near future ;)
196 |
197 |
198 | =head1 Nginx C modules that use Test::Nginx to drive their test suites
199 |
200 | =over
201 |
202 | =item ngx_echo
203 |
204 | L
205 |
206 | =item ngx_headers_more
207 |
208 | L
209 |
210 | =item ngx_chunkin
211 |
212 | L
213 |
214 | =item ngx_memc
215 |
216 | L
217 |
218 | =item ngx_drizzle
219 |
220 | L
221 |
222 | =item ngx_rds_json
223 |
224 | L
225 |
226 | =item ngx_rds_csv
227 |
228 | L
229 |
230 | =item ngx_xss
231 |
232 | L
233 |
234 | =item ngx_srcache
235 |
236 | L
237 |
238 | =item ngx_lua
239 |
240 | L
241 |
242 | =item ngx_set_misc
243 |
244 | L
245 |
246 | =item ngx_array_var
247 |
248 | L
249 |
250 | =item ngx_form_input
251 |
252 | L
253 |
254 | =item ngx_iconv
255 |
256 | L
257 |
258 | =item ngx_set_cconv
259 |
260 | L
261 |
262 | =item ngx_postgres
263 |
264 | L
265 |
266 | =item ngx_coolkit
267 |
268 | L
269 |
270 | =item Naxsi
271 |
272 | L
273 |
274 | =back
275 |
276 | =head1 SOURCE REPOSITORY
277 |
278 | This module has a Git repository on Github, which has access for all.
279 |
280 | http://github.com/agentzh/test-nginx
281 |
282 | If you want a commit bit, feel free to drop me a line.
283 |
284 | =head1 AUTHORS
285 |
286 | agentzh (章亦春) C<< >>
287 |
288 | Antoine BONAVITA C<< >>
289 |
290 | =head1 COPYRIGHT & LICENSE
291 |
292 | Copyright (c) 2009-2012, agentzh C<< >>.
293 |
294 | Copyright (c) 2011-2012, Antoine Bonavita C<< >>.
295 |
296 | This module is licensed under the terms of the BSD license.
297 |
298 | Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
299 |
300 | =over
301 |
302 | =item *
303 |
304 | Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
305 |
306 | =item *
307 |
308 | Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
309 |
310 | =item *
311 |
312 | Neither the name of the authors nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
313 |
314 | =back
315 |
316 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
317 |
318 | =head1 SEE ALSO
319 |
320 | L, L, L.
321 |
322 |
--------------------------------------------------------------------------------
/test/ragel/Makefile:
--------------------------------------------------------------------------------
1 | default: server client
2 |
3 | server: http11_parser.rl ragel_http_server.c
4 | ragel -G2 http11_parser.rl
5 | gcc -g -Wall ragel_http_server.c http11_parser.c -o server
6 |
7 |
8 | client: http11_response.rl ragel_http_client.c
9 | ragel -G2 http11_response.rl
10 | gcc -g -Wall ragel_http_client.c http11_response.c -o client
11 |
12 | clean:
13 | rm client server
14 |
--------------------------------------------------------------------------------
/test/ragel/http11_parser.h:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2005 Zed A. Shaw
3 | * You can redistribute it and/or modify it under the same terms as Ruby.
4 | */
5 |
6 | #ifndef http11_parser_h
7 | #define http11_parser_h
8 |
9 | #include
10 |
11 | #if defined(_WIN32)
12 | #include
13 | #endif
14 |
15 | typedef void (*element_cb)(void *data, const char *at, size_t length);
16 | typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
17 |
18 | typedef struct http_parser {
19 | int cs;
20 | size_t body_start;
21 | int content_len;
22 | size_t nread;
23 | size_t mark;
24 | size_t field_start;
25 | size_t field_len;
26 | size_t query_start;
27 |
28 | void *data;
29 |
30 | field_cb http_field;
31 | element_cb request_method;
32 | element_cb request_uri;
33 | element_cb fragment;
34 | element_cb request_path;
35 | element_cb query_string;
36 | element_cb http_version;
37 | element_cb header_done;
38 |
39 | } http_parser;
40 |
41 | int http_parser_init(http_parser *parser);
42 | int http_parser_finish(http_parser *parser);
43 | size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
44 | int http_parser_has_error(http_parser *parser);
45 | int http_parser_is_finished(http_parser *parser);
46 |
47 | #define http_parser_nread(parser) (parser)->nread
48 |
49 | #endif
50 |
--------------------------------------------------------------------------------
/test/ragel/http11_parser.rl:
--------------------------------------------------------------------------------
1 | /**
2 | * Copyright (c) 2005 Zed A. Shaw
3 | * You can redistribute it and/or modify it under the same terms as Ruby.
4 | */
5 | #include "http11_parser.h"
6 | #include
7 | #include
8 | #include
9 | #include
10 | #include
11 |
12 |
13 | #define LEN(AT, FPC) (FPC - buffer - parser->AT)
14 | #define MARK(M,FPC) (parser->M = (FPC) - buffer)
15 | #define PTR_TO(F) (buffer + parser->F)
16 |
17 | /** Machine **/
18 |
19 | %%{
20 |
21 | machine http_parser;
22 |
23 | action mark {MARK(mark, fpc); }
24 |
25 |
26 | action start_field { MARK(field_start, fpc); }
27 | action write_field {
28 | parser->field_len = LEN(field_start, fpc);
29 | }
30 |
31 | action start_value { MARK(mark, fpc); }
32 | action write_value {
33 | if(parser->http_field != NULL) {
34 | parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
35 | }
36 | }
37 | action request_method {
38 | if(parser->request_method != NULL)
39 | parser->request_method(parser->data, PTR_TO(mark), LEN(mark, fpc));
40 | }
41 | action request_uri {
42 | if(parser->request_uri != NULL)
43 | parser->request_uri(parser->data, PTR_TO(mark), LEN(mark, fpc));
44 | }
45 | action fragment {
46 | if(parser->fragment != NULL)
47 | parser->fragment(parser->data, PTR_TO(mark), LEN(mark, fpc));
48 | }
49 |
50 | action start_query {MARK(query_start, fpc); }
51 | action query_string {
52 | if(parser->query_string != NULL)
53 | parser->query_string(parser->data, PTR_TO(query_start), LEN(query_start, fpc));
54 | }
55 |
56 | action http_version {
57 | if(parser->http_version != NULL)
58 | parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
59 | }
60 |
61 | action request_path {
62 | if(parser->request_path != NULL)
63 | parser->request_path(parser->data, PTR_TO(mark), LEN(mark,fpc));
64 | }
65 |
66 | action done {
67 | parser->body_start = fpc - buffer + 1;
68 | if(parser->header_done != NULL)
69 | parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
70 | fbreak;
71 | }
72 |
73 | include http_parser_common "http11_parser_common.rl";
74 |
75 | }%%
76 |
77 | /** Data **/
78 | %% write data;
79 |
80 | int http_parser_init(http_parser *parser) {
81 | int cs = 0;
82 | %% write init;
83 | parser->cs = cs;
84 | parser->body_start = 0;
85 | parser->content_len = 0;
86 | parser->mark = 0;
87 | parser->nread = 0;
88 | parser->field_len = 0;
89 | parser->field_start = 0;
90 |
91 | return(1);
92 | }
93 |
94 |
95 | /** exec **/
96 | size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
97 | const char *p, *pe;
98 | int cs = parser->cs;
99 |
100 | assert(off <= len && "offset past end of buffer");
101 |
102 | p = buffer+off;
103 | pe = buffer+len;
104 |
105 | /* assert(*pe == '\0' && "pointer does not end on NUL"); */
106 | assert(pe - p == len - off && "pointers aren't same distance");
107 |
108 | %% write exec;
109 |
110 | if (!http_parser_has_error(parser))
111 | parser->cs = cs;
112 | parser->nread += p - (buffer + off);
113 |
114 | assert(p <= pe && "buffer overflow after parsing execute");
115 | assert(parser->nread <= len && "nread longer than length");
116 | assert(parser->body_start <= len && "body starts after buffer end");
117 | assert(parser->mark < len && "mark is after buffer end");
118 | assert(parser->field_len <= len && "field has length longer than whole buffer");
119 | assert(parser->field_start < len && "field starts after buffer end");
120 |
121 | return(parser->nread);
122 | }
123 |
124 | int http_parser_finish(http_parser *parser)
125 | {
126 | if (http_parser_has_error(parser) ) {
127 | return -1;
128 | } else if (http_parser_is_finished(parser) ) {
129 | return 1;
130 | } else {
131 | return 0;
132 | }
133 | }
134 |
135 | int http_parser_has_error(http_parser *parser) {
136 | return parser->cs == http_parser_error;
137 | }
138 |
139 | int http_parser_is_finished(http_parser *parser) {
140 | return parser->cs >= http_parser_first_final;
141 | }
142 |
--------------------------------------------------------------------------------
/test/ragel/http11_parser_common.rl:
--------------------------------------------------------------------------------
1 | %%{
2 |
3 | machine http_parser_common;
4 |
5 | #### HTTP PROTOCOL GRAMMAR
6 | # line endings
7 | CRLF = "\r\n";
8 |
9 | # character types
10 | CTL = (cntrl | 127);
11 | safe = ("$" | "-" | "_" | ".");
12 | extra = ("!" | "*" | "'" | "(" | ")" | ",");
13 | reserved = (";" | "/" | "?" | ":" | "@" | "&" | "=" | "+");
14 | unsafe = (CTL | " " | "\"" | "#" | "%" | "<" | ">");
15 | national = any -- (alpha | digit | reserved | extra | safe | unsafe);
16 | unreserved = (alpha | digit | safe | extra | national);
17 | escape = ("%" xdigit xdigit);
18 | uchar = (unreserved | escape);
19 | pchar = (uchar | ":" | "@" | "&" | "=" | "+");
20 | tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
21 |
22 | # elements
23 | token = (ascii -- (CTL | tspecials));
24 |
25 | # URI schemes and absolute paths
26 | scheme = ( alpha | digit | "+" | "-" | "." )* ;
27 | absolute_uri = (scheme ":" (uchar | reserved )*);
28 |
29 | path = ( pchar+ ( "/" pchar* )* ) ;
30 | query = ( uchar | reserved )* %query_string ;
31 | param = ( pchar | "/" )* ;
32 | params = ( param ( ";" param )* ) ;
33 | rel_path = ( path? %request_path (";" params)? ) ("?" %start_query query)?;
34 | absolute_path = ( "/"+ rel_path );
35 |
36 | Request_URI = ( "*" | absolute_uri | absolute_path ) >mark %request_uri;
37 | Fragment = ( uchar | reserved )* >mark %fragment;
38 | Method = ( upper | digit | safe ){1,20} >mark %request_method;
39 |
40 | http_number = ( digit+ "." digit+ ) ;
41 | HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
42 | Request_Line = ( Method " " Request_URI ("#" Fragment){0,1} " " HTTP_Version CRLF ) ;
43 |
44 | #field_name = ( token -- ":" )+ >start_field $snake_upcase_field %write_field;
45 | field_name = ( token -- ":" )+ >start_field %write_field;
46 |
47 | field_value = any* >start_value %write_value;
48 |
49 | message_header = field_name ":" " "* field_value :> CRLF;
50 |
51 | Request = Request_Line ( message_header )* ( CRLF @done );
52 |
53 | main := Request;
54 |
55 | }%%
56 |
--------------------------------------------------------------------------------
/test/ragel/http11_response.c:
--------------------------------------------------------------------------------
1 |
2 | #line 1 "http11_response.rl"
3 |
4 | #include "http11_response.h"
5 | #include
6 | #include
7 | #include
8 | #include
9 | #include
10 |
11 |
12 | #define LEN(AT, FPC) (FPC - buffer - parser->AT)
13 | #define MARK(M,FPC) (parser->M = (FPC) - buffer)
14 | #define PTR_TO(F) (buffer + parser->F)
15 |
16 | /** Machine **/
17 |
18 |
19 | #line 59 "http11_response.rl"
20 |
21 |
22 | /** Data **/
23 |
24 | #line 25 "http11_response.c"
25 | static const int http_parser_start = 1;
26 | static const int http_parser_first_final = 20;
27 | static const int http_parser_error = 0;
28 |
29 | static const int http_parser_en_main = 1;
30 |
31 |
32 | #line 63 "http11_response.rl"
33 |
34 | int http_parser_init(http_parser *parser) {
35 | int cs = 0;
36 |
37 | #line 38 "http11_response.c"
38 | {
39 | cs = http_parser_start;
40 | }
41 |
42 | #line 67 "http11_response.rl"
43 | parser->cs = cs;
44 | parser->body_start = 0;
45 | parser->content_len = 0;
46 | parser->mark = 0;
47 | parser->nread = 0;
48 | parser->field_len = 0;
49 | parser->field_start = 0;
50 |
51 | return(1);
52 | }
53 |
54 |
55 | /** exec **/
56 | size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
57 | const char *p, *pe;
58 | int cs = parser->cs;
59 |
60 | assert(off <= len && "offset past end of buffer");
61 |
62 | p = buffer+off;
63 | pe = buffer+len;
64 |
65 | assert(pe - p == len - off && "pointers aren't same distance");
66 |
67 |
68 | #line 69 "http11_response.c"
69 | {
70 | if ( p == pe )
71 | goto _test_eof;
72 | switch ( cs )
73 | {
74 | case 1:
75 | if ( (*p) == 72 )
76 | goto tr0;
77 | goto st0;
78 | st0:
79 | cs = 0;
80 | goto _out;
81 | tr0:
82 | #line 20 "http11_response.rl"
83 | {MARK(mark, p); }
84 | goto st2;
85 | st2:
86 | if ( ++p == pe )
87 | goto _test_eof2;
88 | case 2:
89 | #line 90 "http11_response.c"
90 | if ( (*p) == 84 )
91 | goto st3;
92 | goto st0;
93 | st3:
94 | if ( ++p == pe )
95 | goto _test_eof3;
96 | case 3:
97 | if ( (*p) == 84 )
98 | goto st4;
99 | goto st0;
100 | st4:
101 | if ( ++p == pe )
102 | goto _test_eof4;
103 | case 4:
104 | if ( (*p) == 80 )
105 | goto st5;
106 | goto st0;
107 | st5:
108 | if ( ++p == pe )
109 | goto _test_eof5;
110 | case 5:
111 | if ( (*p) == 47 )
112 | goto st6;
113 | goto st0;
114 | st6:
115 | if ( ++p == pe )
116 | goto _test_eof6;
117 | case 6:
118 | if ( 48 <= (*p) && (*p) <= 57 )
119 | goto st7;
120 | goto st0;
121 | st7:
122 | if ( ++p == pe )
123 | goto _test_eof7;
124 | case 7:
125 | if ( (*p) == 46 )
126 | goto st8;
127 | if ( 48 <= (*p) && (*p) <= 57 )
128 | goto st7;
129 | goto st0;
130 | st8:
131 | if ( ++p == pe )
132 | goto _test_eof8;
133 | case 8:
134 | if ( 48 <= (*p) && (*p) <= 57 )
135 | goto st9;
136 | goto st0;
137 | st9:
138 | if ( ++p == pe )
139 | goto _test_eof9;
140 | case 9:
141 | if ( (*p) == 32 )
142 | goto tr9;
143 | if ( 48 <= (*p) && (*p) <= 57 )
144 | goto st9;
145 | goto st0;
146 | tr9:
147 | #line 35 "http11_response.rl"
148 | {
149 | if(parser->http_version != NULL)
150 | parser->http_version(parser->data, PTR_TO(mark), LEN(mark, p));
151 | }
152 | goto st10;
153 | st10:
154 | if ( ++p == pe )
155 | goto _test_eof10;
156 | case 10:
157 | #line 158 "http11_response.c"
158 | if ( 48 <= (*p) && (*p) <= 57 )
159 | goto tr10;
160 | goto st0;
161 | tr10:
162 | #line 20 "http11_response.rl"
163 | {MARK(mark, p); }
164 | goto st11;
165 | st11:
166 | if ( ++p == pe )
167 | goto _test_eof11;
168 | case 11:
169 | #line 170 "http11_response.c"
170 | if ( (*p) == 32 )
171 | goto tr11;
172 | if ( 48 <= (*p) && (*p) <= 57 )
173 | goto st11;
174 | goto st0;
175 | tr11:
176 | #line 40 "http11_response.rl"
177 | {
178 | if(parser->status_code != NULL)
179 | parser->status_code(parser->data, PTR_TO(mark), LEN(mark,p));
180 | }
181 | goto st12;
182 | st12:
183 | if ( ++p == pe )
184 | goto _test_eof12;
185 | case 12:
186 | #line 187 "http11_response.c"
187 | if ( (*p) < 11 ) {
188 | if ( 0 <= (*p) && (*p) <= 9 )
189 | goto tr13;
190 | } else if ( (*p) > 12 ) {
191 | if ( 14 <= (*p) )
192 | goto tr13;
193 | } else
194 | goto tr13;
195 | goto st0;
196 | tr13:
197 | #line 20 "http11_response.rl"
198 | {MARK(mark, p); }
199 | goto st13;
200 | st13:
201 | if ( ++p == pe )
202 | goto _test_eof13;
203 | case 13:
204 | #line 205 "http11_response.c"
205 | if ( (*p) == 13 )
206 | goto tr15;
207 | if ( (*p) > 9 ) {
208 | if ( 11 <= (*p) )
209 | goto st13;
210 | } else if ( (*p) >= 0 )
211 | goto st13;
212 | goto st0;
213 | tr15:
214 | #line 45 "http11_response.rl"
215 | {
216 | if(parser->reason_phrase != NULL)
217 | parser->reason_phrase(parser->data, PTR_TO(mark), LEN(mark,p));
218 | }
219 | goto st14;
220 | tr23:
221 | #line 27 "http11_response.rl"
222 | { MARK(mark, p); }
223 | #line 29 "http11_response.rl"
224 | {
225 | if(parser->http_field != NULL) {
226 | parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
227 | }
228 | }
229 | goto st14;
230 | tr26:
231 | #line 29 "http11_response.rl"
232 | {
233 | if(parser->http_field != NULL) {
234 | parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, p));
235 | }
236 | }
237 | goto st14;
238 | st14:
239 | if ( ++p == pe )
240 | goto _test_eof14;
241 | case 14:
242 | #line 243 "http11_response.c"
243 | if ( (*p) == 10 )
244 | goto st15;
245 | goto st0;
246 | st15:
247 | if ( ++p == pe )
248 | goto _test_eof15;
249 | case 15:
250 | switch( (*p) ) {
251 | case 13: goto st16;
252 | case 33: goto tr18;
253 | case 124: goto tr18;
254 | case 126: goto tr18;
255 | }
256 | if ( (*p) < 45 ) {
257 | if ( (*p) > 39 ) {
258 | if ( 42 <= (*p) && (*p) <= 43 )
259 | goto tr18;
260 | } else if ( (*p) >= 35 )
261 | goto tr18;
262 | } else if ( (*p) > 46 ) {
263 | if ( (*p) < 65 ) {
264 | if ( 48 <= (*p) && (*p) <= 57 )
265 | goto tr18;
266 | } else if ( (*p) > 90 ) {
267 | if ( 94 <= (*p) && (*p) <= 122 )
268 | goto tr18;
269 | } else
270 | goto tr18;
271 | } else
272 | goto tr18;
273 | goto st0;
274 | st16:
275 | if ( ++p == pe )
276 | goto _test_eof16;
277 | case 16:
278 | if ( (*p) == 10 )
279 | goto tr19;
280 | goto st0;
281 | tr19:
282 | #line 50 "http11_response.rl"
283 | {
284 | parser->body_start = p - buffer + 1;
285 | if(parser->header_done != NULL)
286 | parser->header_done(parser->data, p + 1, pe - p - 1);
287 | {p++; cs = 20; goto _out;}
288 | }
289 | goto st20;
290 | st20:
291 | if ( ++p == pe )
292 | goto _test_eof20;
293 | case 20:
294 | #line 295 "http11_response.c"
295 | goto st0;
296 | tr18:
297 | #line 22 "http11_response.rl"
298 | { MARK(field_start, p); }
299 | goto st17;
300 | st17:
301 | if ( ++p == pe )
302 | goto _test_eof17;
303 | case 17:
304 | #line 305 "http11_response.c"
305 | switch( (*p) ) {
306 | case 33: goto st17;
307 | case 58: goto tr21;
308 | case 124: goto st17;
309 | case 126: goto st17;
310 | }
311 | if ( (*p) < 45 ) {
312 | if ( (*p) > 39 ) {
313 | if ( 42 <= (*p) && (*p) <= 43 )
314 | goto st17;
315 | } else if ( (*p) >= 35 )
316 | goto st17;
317 | } else if ( (*p) > 46 ) {
318 | if ( (*p) < 65 ) {
319 | if ( 48 <= (*p) && (*p) <= 57 )
320 | goto st17;
321 | } else if ( (*p) > 90 ) {
322 | if ( 94 <= (*p) && (*p) <= 122 )
323 | goto st17;
324 | } else
325 | goto st17;
326 | } else
327 | goto st17;
328 | goto st0;
329 | tr21:
330 | #line 23 "http11_response.rl"
331 | {
332 | parser->field_len = LEN(field_start, p);
333 | }
334 | goto st18;
335 | tr24:
336 | #line 27 "http11_response.rl"
337 | { MARK(mark, p); }
338 | goto st18;
339 | st18:
340 | if ( ++p == pe )
341 | goto _test_eof18;
342 | case 18:
343 | #line 344 "http11_response.c"
344 | switch( (*p) ) {
345 | case 13: goto tr23;
346 | case 32: goto tr24;
347 | }
348 | goto tr22;
349 | tr22:
350 | #line 27 "http11_response.rl"
351 | { MARK(mark, p); }
352 | goto st19;
353 | st19:
354 | if ( ++p == pe )
355 | goto _test_eof19;
356 | case 19:
357 | #line 358 "http11_response.c"
358 | if ( (*p) == 13 )
359 | goto tr26;
360 | goto st19;
361 | }
362 | _test_eof2: cs = 2; goto _test_eof;
363 | _test_eof3: cs = 3; goto _test_eof;
364 | _test_eof4: cs = 4; goto _test_eof;
365 | _test_eof5: cs = 5; goto _test_eof;
366 | _test_eof6: cs = 6; goto _test_eof;
367 | _test_eof7: cs = 7; goto _test_eof;
368 | _test_eof8: cs = 8; goto _test_eof;
369 | _test_eof9: cs = 9; goto _test_eof;
370 | _test_eof10: cs = 10; goto _test_eof;
371 | _test_eof11: cs = 11; goto _test_eof;
372 | _test_eof12: cs = 12; goto _test_eof;
373 | _test_eof13: cs = 13; goto _test_eof;
374 | _test_eof14: cs = 14; goto _test_eof;
375 | _test_eof15: cs = 15; goto _test_eof;
376 | _test_eof16: cs = 16; goto _test_eof;
377 | _test_eof20: cs = 20; goto _test_eof;
378 | _test_eof17: cs = 17; goto _test_eof;
379 | _test_eof18: cs = 18; goto _test_eof;
380 | _test_eof19: cs = 19; goto _test_eof;
381 |
382 | _test_eof: {}
383 | _out: {}
384 | }
385 |
386 | #line 92 "http11_response.rl"
387 |
388 | if (!http_parser_has_error(parser))
389 | parser->cs = cs;
390 | parser->nread += p - (buffer + off);
391 |
392 | assert(p <= pe && "buffer overflow after parsing execute");
393 | assert(parser->nread <= len && "nread longer than length");
394 | assert(parser->body_start <= len && "body starts after buffer end");
395 | assert(parser->mark < len && "mark is after buffer end");
396 | assert(parser->field_len <= len && "field has length longer than whole buffer");
397 | assert(parser->field_start < len && "field starts after buffer end");
398 |
399 | return(parser->nread);
400 | }
401 |
402 | int http_parser_finish(http_parser *parser)
403 | {
404 | if (http_parser_has_error(parser) ) {
405 | return -1;
406 | } else if (http_parser_is_finished(parser) ) {
407 | return 1;
408 | } else {
409 | return 0;
410 | }
411 | }
412 |
413 | int http_parser_has_error(http_parser *parser) {
414 | return parser->cs == http_parser_error;
415 | }
416 |
417 | int http_parser_is_finished(http_parser *parser) {
418 | return parser->cs >= http_parser_first_final;
419 | }
420 |
--------------------------------------------------------------------------------
/test/ragel/http11_response.h:
--------------------------------------------------------------------------------
1 |
2 | #ifndef http11_parser_h
3 | #define http11_parser_h
4 |
5 | #include
6 |
7 | #if defined(_WIN32)
8 | #include
9 | #endif
10 |
11 | typedef void (*element_cb)(void *data, const char *at, size_t length);
12 | typedef void (*field_cb)(void *data, const char *field, size_t flen, const char *value, size_t vlen);
13 |
14 | typedef struct http_parser {
15 | int cs;
16 | size_t body_start;
17 | int content_len;
18 | size_t nread;
19 | size_t mark;
20 | size_t field_start;
21 | size_t field_len;
22 | size_t query_start;
23 |
24 | void *data;
25 |
26 | field_cb http_field;
27 |
28 | element_cb http_version;
29 | element_cb status_code;
30 | element_cb reason_phrase;
31 | element_cb header_done;
32 |
33 | } http_parser;
34 |
35 | int http_parser_init(http_parser *parser);
36 | int http_parser_finish(http_parser *parser);
37 | size_t http_parser_execute(http_parser *parser, const char *data, size_t len, size_t off);
38 | int http_parser_has_error(http_parser *parser);
39 | int http_parser_is_finished(http_parser *parser);
40 |
41 | #define http_parser_nread(parser) (parser)->nread
42 |
43 | #endif
44 |
--------------------------------------------------------------------------------
/test/ragel/http11_response.rl:
--------------------------------------------------------------------------------
1 |
2 | #include "http11_response.h"
3 | #include
4 | #include
5 | #include
6 | #include
7 | #include
8 |
9 |
10 | #define LEN(AT, FPC) (FPC - buffer - parser->AT)
11 | #define MARK(M,FPC) (parser->M = (FPC) - buffer)
12 | #define PTR_TO(F) (buffer + parser->F)
13 |
14 | /** Machine **/
15 |
16 | %%{
17 |
18 | machine http_parser;
19 |
20 | action mark {MARK(mark, fpc); }
21 |
22 | action start_field { MARK(field_start, fpc); }
23 | action write_field {
24 | parser->field_len = LEN(field_start, fpc);
25 | }
26 |
27 | action start_value { MARK(mark, fpc); }
28 |
29 | action write_value {
30 | if(parser->http_field != NULL) {
31 | parser->http_field(parser->data, PTR_TO(field_start), parser->field_len, PTR_TO(mark), LEN(mark, fpc));
32 | }
33 | }
34 |
35 | action http_version {
36 | if(parser->http_version != NULL)
37 | parser->http_version(parser->data, PTR_TO(mark), LEN(mark, fpc));
38 | }
39 |
40 | action status_code {
41 | if(parser->status_code != NULL)
42 | parser->status_code(parser->data, PTR_TO(mark), LEN(mark,fpc));
43 | }
44 |
45 | action reason_phrase {
46 | if(parser->reason_phrase != NULL)
47 | parser->reason_phrase(parser->data, PTR_TO(mark), LEN(mark,fpc));
48 | }
49 |
50 | action done {
51 | parser->body_start = fpc - buffer + 1;
52 | if(parser->header_done != NULL)
53 | parser->header_done(parser->data, fpc + 1, pe - fpc - 1);
54 | fbreak;
55 | }
56 |
57 | include http_response_common "http11_response_common.rl";
58 |
59 | }%%
60 |
61 | /** Data **/
62 | %% write data;
63 |
64 | int http_parser_init(http_parser *parser) {
65 | int cs = 0;
66 | %% write init;
67 | parser->cs = cs;
68 | parser->body_start = 0;
69 | parser->content_len = 0;
70 | parser->mark = 0;
71 | parser->nread = 0;
72 | parser->field_len = 0;
73 | parser->field_start = 0;
74 |
75 | return(1);
76 | }
77 |
78 |
79 | /** exec **/
80 | size_t http_parser_execute(http_parser *parser, const char *buffer, size_t len, size_t off) {
81 | const char *p, *pe;
82 | int cs = parser->cs;
83 |
84 | assert(off <= len && "offset past end of buffer");
85 |
86 | p = buffer+off;
87 | pe = buffer+len;
88 |
89 | assert(pe - p == len - off && "pointers aren't same distance");
90 |
91 | %% write exec;
92 |
93 | if (!http_parser_has_error(parser))
94 | parser->cs = cs;
95 | parser->nread += p - (buffer + off);
96 |
97 | assert(p <= pe && "buffer overflow after parsing execute");
98 | assert(parser->nread <= len && "nread longer than length");
99 | assert(parser->body_start <= len && "body starts after buffer end");
100 | assert(parser->mark < len && "mark is after buffer end");
101 | assert(parser->field_len <= len && "field has length longer than whole buffer");
102 | assert(parser->field_start < len && "field starts after buffer end");
103 |
104 | return(parser->nread);
105 | }
106 |
107 | int http_parser_finish(http_parser *parser)
108 | {
109 | if (http_parser_has_error(parser) ) {
110 | return -1;
111 | } else if (http_parser_is_finished(parser) ) {
112 | return 1;
113 | } else {
114 | return 0;
115 | }
116 | }
117 |
118 | int http_parser_has_error(http_parser *parser) {
119 | return parser->cs == http_parser_error;
120 | }
121 |
122 | int http_parser_is_finished(http_parser *parser) {
123 | return parser->cs >= http_parser_first_final;
124 | }
125 |
--------------------------------------------------------------------------------
/test/ragel/http11_response_common.rl:
--------------------------------------------------------------------------------
1 | %%{
2 |
3 | machine http_response_common;
4 |
5 | #### HTTP PROTOCOL GRAMMAR
6 | # line endings
7 | CRLF = "\r\n";
8 |
9 | # character types
10 | CTL = (cntrl | 127);
11 | tspecials = ("(" | ")" | "<" | ">" | "@" | "," | ";" | ":" | "\\" | "\"" | "/" | "[" | "]" | "?" | "=" | "{" | "}" | " " | "\t");
12 |
13 | # elements
14 | token = (ascii -- (CTL | tspecials));
15 |
16 | Reason_Phrase = ( ascii -- ("\r" | "\n") )+ >mark %reason_phrase;
17 |
18 | Status_Code = ( digit+ ) >mark %status_code ;
19 |
20 | http_number = ( digit+ "." digit+ ) ;
21 | HTTP_Version = ( "HTTP/" http_number ) >mark %http_version ;
22 |
23 | Response_Line = ( HTTP_Version " " Status_Code " " Reason_Phrase CRLF ) ;
24 |
25 | field_name = ( token -- ":" )+ >start_field %write_field;
26 |
27 | field_value = any* >start_value %write_value;
28 |
29 | message_header = field_name ":" " "* field_value :> CRLF;
30 |
31 | Response = Response_Line ( message_header )* ( CRLF @done );
32 |
33 | main := Response;
34 |
35 | }%%
36 |
--------------------------------------------------------------------------------
/test/ragel/ragel_http_client.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include "http11_response.h"
6 | #include
7 |
8 | #define BUFF_LEN 4096
9 |
10 | void http_field(void *data, const char *field,
11 | size_t flen, const char *value, size_t vlen)
12 | {
13 | char buff[BUFF_LEN] = {0};
14 |
15 | strncpy(buff, field, flen);
16 | strcat(buff, ": ");
17 | strncat(buff, value, vlen);
18 |
19 | printf("HEADER: \"%s\"\n", buff);
20 | }
21 |
22 | void http_version(void *data, const char *at, size_t length)
23 | {
24 | printf("VERSION: \"%.*s\"\n", length, at);
25 | }
26 |
27 | void status_code(void *data, const char *at, size_t length)
28 | {
29 | printf("STATUS_CODE: \"%.*s\"\n", length, at);
30 | }
31 |
32 | void reason_phrase(void *data, const char *at, size_t length)
33 | {
34 | printf("REASON_PHRASE: \"%.*s\"\n", length, at);
35 | }
36 |
37 | void header_done(void *data, const char *at, size_t length)
38 | {
39 | printf("HEADER_DONE.\n");
40 | }
41 |
42 | void parser_init(http_parser *hp)
43 | {
44 | hp->http_field = http_field;
45 | hp->http_version = http_version;
46 | hp->status_code = status_code;
47 | hp->reason_phrase = reason_phrase;
48 | hp->header_done = header_done;
49 | http_parser_init(hp);
50 | }
51 |
52 | int main1 ()
53 | {
54 | char *data = "HTTP/1.0 200 OK\r\n"
55 | "Server: nginx\r\n"
56 | "Date: Fri, 26 Mar 2010 03:39:03 GMT\r\n"
57 | "Content-Type: text/html; charset=GBK\r\n"
58 | "Vary: Accept-Encoding\r\n"
59 | "Expires: Fri, 26 Mar 2010 03:40:23 GMT\r\n"
60 | "Cache-Control: max-age=80\r\n"
61 | "Vary: User-Agent\r\n"
62 | "Vary: Accept\r\n"
63 | "X-Cache: MISS from cache.163.com\r\n"
64 | "Connection: close\r\n"
65 | "\r\n"
66 | "I am the body"
67 | ;
68 | size_t dlen;
69 | http_parser parser, *hp;
70 |
71 | hp = &parser;
72 | dlen = strlen(data);
73 |
74 | parser_init(hp);
75 |
76 | http_parser_execute(hp, data, dlen, 0);
77 |
78 | return 0;
79 | }
80 |
81 | int main ()
82 | {
83 | char *data = "HTTP/1.0 200 OK\r\n"
84 | "Server: nginx\r\n"
85 | "Date: Fri, 26 Mar 2010 03:39:03 GMT\r\n"
86 | "Content-Type: text/html; charset=GBK\r\n"
87 | "Vary: Accept-Encoding\r\n"
88 | "Expires: Fri, 26 Mar 2010 03:40:23 GMT\r\n"
89 | "Cache-Control: max-age=80\r\n"
90 | "Vary: User-Agent\r\n"
91 | "Vary: Accept\r\n"
92 | "X-Cache: MISS from cache.163.com\r\n"
93 | "Connection: close\r\n"
94 | "\r\n"
95 | "I am the body"
96 | ;
97 |
98 |
99 | size_t dlen, dlen1;
100 | http_parser parser, *hp;
101 | int i;
102 |
103 | hp = &parser;
104 | dlen = strlen(data);
105 |
106 | for (i = 1;i < dlen;i++) {
107 | printf("\n\nblock point: %d\n", i);
108 | parser_init(hp);
109 | dlen1 = http_parser_execute(hp, data, i, 0);
110 | dlen1 = http_parser_execute(hp, data, dlen, dlen1);
111 | printf("BODY: \"%s\"\n", data + hp->body_start);
112 | }
113 |
114 | return 0;
115 | }
116 |
--------------------------------------------------------------------------------
/test/ragel/ragel_http_server.c:
--------------------------------------------------------------------------------
1 |
2 | #include
3 | #include
4 | #include
5 | #include "http11_parser.h"
6 | #include
7 |
8 | #define BUFF_LEN 4096
9 |
10 | void http_field(void *data, const char *field,
11 | size_t flen, const char *value, size_t vlen)
12 | {
13 | char buff[BUFF_LEN] = {0};
14 |
15 | strncpy(buff, field, flen);
16 | strcat(buff, ": ");
17 | strncat(buff, value, vlen);
18 |
19 | printf("HEADER: \"%s\"\n", buff);
20 | }
21 |
22 | void request_method(void *data, const char *at, size_t length)
23 | {
24 | char buff[BUFF_LEN] = {0};
25 |
26 | strncpy(buff, at, length);
27 |
28 | printf("METHOD: \"%s\"\n", buff);
29 | }
30 |
31 | void request_uri(void *data, const char *at, size_t length)
32 | {
33 | char buff[BUFF_LEN] = {0};
34 |
35 | strncpy(buff, at, length);
36 |
37 | printf("URI: \"%s\"\n", buff);
38 | }
39 |
40 | void fragment(void *data, const char *at, size_t length)
41 | {
42 | char buff[BUFF_LEN] = {0};
43 |
44 | strncpy(buff, at, length);
45 |
46 | printf("FRAGMENT: \"%s\"\n", buff);
47 | }
48 |
49 | void request_path(void *data, const char *at, size_t length)
50 | {
51 | char buff[BUFF_LEN] = {0};
52 |
53 | strncpy(buff, at, length);
54 |
55 | printf("PATH: \"%s\"\n", buff);
56 | }
57 |
58 | void query_string(void *data, const char *at, size_t length)
59 | {
60 | char buff[BUFF_LEN] = {0};
61 |
62 | strncpy(buff, at, length);
63 |
64 | printf("QUERY: \"%s\"\n", buff);
65 | }
66 |
67 | void http_version(void *data, const char *at, size_t length)
68 | {
69 | char buff[BUFF_LEN] = {0};
70 |
71 | strncpy(buff, at, length);
72 |
73 | printf("VERSION: \"%s\"\n", buff);
74 | }
75 |
76 | void header_done(void *data, const char *at, size_t length)
77 | {
78 | printf("done.\n");
79 | }
80 |
81 | void parser_init(http_parser *hp)
82 | {
83 | hp->http_field = http_field;
84 | hp->request_method = request_method;
85 | hp->request_uri = request_uri;
86 | hp->fragment = fragment;
87 | hp->request_path = request_path;
88 | hp->query_string = query_string;
89 | hp->http_version = http_version;
90 | hp->header_done = header_done;
91 | http_parser_init(hp);
92 | }
93 |
94 | int main1 ()
95 | {
96 | char *data = "GET / HTTP/1.0\r\n"
97 | "User-Agent: Wget/1.11.4\r\n"
98 | "Accept: */*\r\n"
99 | "Host: www.163.com\r\n"
100 | "Connection: Keep-Alive\r\n"
101 | "\r\n";
102 | size_t dlen;
103 | http_parser parser, *hp;
104 |
105 | hp = &parser;
106 | dlen = strlen(data);
107 |
108 | parser_init(hp);
109 |
110 | http_parser_execute(hp, data, dlen, 0);
111 |
112 | return 0;
113 | }
114 |
115 | int main ()
116 | {
117 | char *data = "GET / HTTP/1.0\r\n"
118 | "User-Agent: Wget/1.11.4\r\n"
119 | "Accept: */*\r\n"
120 | "Host: www.163.com\r\n"
121 | "Connection: Keep-Alive\r\n"
122 | "\r\n";
123 |
124 |
125 | size_t dlen, dlen1;
126 | http_parser parser, *hp;
127 | int i;
128 |
129 | hp = &parser;
130 | dlen = strlen(data);
131 |
132 | for (i = 1;i < dlen;i++) {
133 | parser_init(hp);
134 | dlen1 = http_parser_execute(hp, data, i, 0);
135 | dlen1 = http_parser_execute(hp, data, dlen, dlen1);
136 | }
137 |
138 | return 0;
139 | }
140 |
--------------------------------------------------------------------------------
/test/t/ssl_hello_check.t:
--------------------------------------------------------------------------------
1 | # vi:filetype=perl
2 |
3 | use lib 'lib';
4 | use Test::Nginx::LWP;
5 |
6 | plan tests => repeat_each(2) * 2 * blocks();
7 |
8 | no_root_location();
9 | #no_diff;
10 |
11 | run_tests();
12 |
13 | __DATA__
14 |
15 | === TEST 1: the ssl_hello_check test
16 | --- http_config
17 | upstream test{
18 | server www.alipay.com:443;
19 | server www.alipay.com:444;
20 | server www.alipay.com:445;
21 |
22 | check interval=4000 rise=1 fall=1 timeout=2000 type=ssl_hello;
23 | }
24 |
25 | --- config
26 | location / {
27 | proxy_ssl_session_reuse off;
28 | proxy_pass https://test;
29 | }
30 |
31 | --- request
32 | GET /
33 | --- response_body_like: ^<(.*)>[\r\n\s\t]*$
34 |
35 | === TEST 2: the ssl_hello_check test with ip_hash
36 | --- http_config
37 | upstream test{
38 | server www.alipay.com:443;
39 | server www.alipay.com:444;
40 | server www.alipay.com:445;
41 | ip_hash;
42 |
43 | check interval=4000 rise=1 fall=1 timeout=2000 type=ssl_hello;
44 | }
45 |
46 | --- config
47 | location / {
48 | proxy_ssl_session_reuse off;
49 | proxy_pass https://test;
50 | }
51 |
52 | --- request
53 | GET /
54 | --- response_body_like: ^<(.*)>[\r\n\s\t]*$
55 |
56 | === TEST 3: the ssl_hello_check test with bad ip
57 | --- http_config
58 | upstream test{
59 | server www.alipay.com:80;
60 | server www.alipay.com:443;
61 | server www.alipay.com:444;
62 | server www.alipay.com:445;
63 |
64 | check interval=4000 rise=1 fall=1 timeout=2000 type=ssl_hello;
65 | }
66 |
67 | --- config
68 | location / {
69 | proxy_ssl_session_reuse off;
70 | proxy_pass https://test;
71 | }
72 |
73 | --- request
74 | GET /
75 | --- response_body_like: ^<(.*)>[\r\n\s\t]*$
76 |
77 | === TEST 4: the ssl_hello_check test with least_conn
78 | --- http_config
79 | upstream test{
80 | server www.alipay.com:443;
81 | server www.alipay.com:444;
82 | server www.alipay.com:445;
83 | least_conn;
84 |
85 | check interval=4000 rise=1 fall=1 timeout=2000 type=ssl_hello;
86 | }
87 |
88 | --- config
89 | location / {
90 | proxy_ssl_session_reuse off;
91 | proxy_pass https://test;
92 | }
93 |
94 | --- request
95 | GET /
96 | --- response_body_like: ^<(.*)>[\r\n\s\t]*$
97 |
98 | === TEST 5: the ssl_hello_check test with port 80
99 | --- http_config
100 | upstream test{
101 | server www.alipay.com:443;
102 |
103 | check interval=4000 rise=1 fall=1 timeout=2000 type=http port=80;
104 | check_http_send "GET / HTTP/1.0\r\n\r\n";
105 | check_http_expect_alive http_2xx http_3xx;
106 | }
107 |
108 | --- config
109 | location / {
110 | proxy_ssl_session_reuse off;
111 | proxy_pass https://test;
112 | }
113 |
114 | --- request
115 | GET /
116 | --- response_body_like: ^<(.*)>[\r\n\s\t]*$
117 |
118 | === TEST 6: the ssl_hello_check test with port 443
119 | --- http_config
120 | upstream test{
121 | server www.alipay.com:443;
122 |
123 | check interval=4000 rise=1 fall=1 timeout=2000 type=ssl_hello port=443;
124 | }
125 |
126 | --- config
127 | location / {
128 | proxy_ssl_session_reuse off;
129 | proxy_pass https://test;
130 | }
131 |
132 | --- request
133 | GET /
134 | --- response_body_like: ^<(.*)>[\r\n\s\t]*$
135 |
136 | === TEST 7: the ssl_hello_check test with port 444
137 | --- http_config
138 | upstream test{
139 | server www.alipay.com:443;
140 |
141 | check interval=4000 rise=1 fall=1 timeout=2000 type=ssl_hello port=444;
142 | }
143 |
144 | --- config
145 | location / {
146 | proxy_ssl_session_reuse off;
147 | proxy_pass https://test;
148 | }
149 |
150 | --- request
151 | GET /
152 | --- error_code: 502
153 | --- response_body_like: ^.*$
154 |
155 |
--------------------------------------------------------------------------------
/test/t/tcp_check.t:
--------------------------------------------------------------------------------
1 | # vi:filetype=perl
2 |
3 | use lib 'lib';
4 | use Test::Nginx::LWP;
5 |
6 | plan tests => repeat_each(2) * 2 * blocks();
7 |
8 | no_root_location();
9 | #no_diff;
10 |
11 | run_tests();
12 |
13 | __DATA__
14 |
15 | === TEST 1: the tcp_check test
16 | --- http_config
17 | upstream test{
18 | server 127.0.0.1:1970;
19 | server 127.0.0.1:1971;
20 | server 127.0.0.1:1972;
21 |
22 | check interval=3000 rise=1 fall=1 timeout=1000;
23 | }
24 |
25 | server {
26 | listen 1970;
27 |
28 | location / {
29 | root html;
30 | index index.html index.htm;
31 | }
32 | }
33 |
34 | --- config
35 | location / {
36 | proxy_pass http://test;
37 | }
38 |
39 | --- request
40 | GET /
41 | --- response_body_like: ^<(.*)>$
42 |
43 | === TEST 2: the tcp_check test with ip_hash
44 | --- http_config
45 | upstream test{
46 | server 127.0.0.1:1970;
47 | server 127.0.0.1:1971;
48 | server 127.0.0.1:1972;
49 | ip_hash;
50 |
51 | check interval=3000 rise=1 fall=1 timeout=1000 type=tcp;
52 | }
53 |
54 | server {
55 | listen 1970;
56 |
57 | location / {
58 | root html;
59 | index index.html index.htm;
60 | }
61 | }
62 |
63 | --- config
64 | location / {
65 | proxy_pass http://test;
66 | }
67 |
68 | --- request
69 | GET /
70 | --- response_body_like: ^<(.*)>$
71 |
72 | === TEST 3: the tcp_check test which don't use the checked upstream
73 | --- http_config
74 | upstream test{
75 | server 127.0.0.1:1970;
76 | server 127.0.0.1:1971;
77 | server 127.0.0.1:1972;
78 |
79 | check interval=3000 rise=1 fall=1 timeout=1000;
80 | }
81 |
82 | server {
83 | listen 1970;
84 |
85 | location / {
86 | root html;
87 | index index.html index.htm;
88 | }
89 | }
90 |
91 | --- config
92 | location / {
93 | proxy_pass http://127.0.0.1:1970;
94 | }
95 |
96 | --- request
97 | GET /
98 | --- response_body_like: ^<(.*)>$
99 |
100 | === TEST 3: the tcp_check test with least_conn;
101 | --- http_config
102 | upstream test{
103 | server 127.0.0.1:1970;
104 | server 127.0.0.1:1971;
105 | server 127.0.0.1:1972;
106 | least_conn;
107 |
108 | check interval=3000 rise=1 fall=5 timeout=1000 type=tcp;
109 | }
110 |
111 | server {
112 | listen 1970;
113 |
114 | location / {
115 | root html;
116 | index index.html index.htm;
117 | }
118 | }
119 |
120 | --- config
121 | location / {
122 | proxy_pass http://test;
123 | }
124 |
125 | --- request
126 | GET /
127 | --- response_body_like: ^<(.*)>$
128 |
129 | === TEST 4: the tcp_check test with port
130 | --- http_config
131 | upstream test{
132 | server 127.0.0.1:1971;
133 |
134 | check interval=3000 rise=1 fall=1 timeout=1000 type=tcp port=1970;
135 | }
136 |
137 | server {
138 | listen 1970;
139 |
140 | location / {
141 | root html;
142 | index index.html index.htm;
143 | }
144 | }
145 |
146 | --- config
147 | location / {
148 | proxy_pass http://test;
149 | }
150 |
151 | --- request
152 | GET /
153 | --- error_code: 502
154 | --- response_body_like: ^.*$
155 |
156 | === TEST 5: the tcp_check test with port
157 | --- http_config
158 | upstream test{
159 | server 127.0.0.1:1970;
160 |
161 | check interval=2000 rise=1 fall=1 timeout=1000 type=tcp port=1971;
162 | }
163 |
164 | server {
165 | listen 1970;
166 |
167 | location / {
168 | root html;
169 | index index.html index.htm;
170 | }
171 | }
172 |
173 | --- config
174 | location / {
175 | proxy_pass http://test;
176 | }
177 |
178 | --- request
179 | GET /
180 | --- error_code: 502
181 | --- response_body_like: ^.*$
182 |
183 | === TEST 5: the tcp_check test with check_keepalive_requests configured
184 | --- http_config
185 | upstream test{
186 | server 127.0.0.1:1970;
187 |
188 | check_keepalive_requests 10;
189 | check interval=2000 rise=1 fall=1 timeout=1000 type=tcp;
190 | }
191 |
192 | server {
193 | listen 1970;
194 |
195 | location / {
196 | root html;
197 | index index.html index.htm;
198 | }
199 | }
200 |
201 | --- config
202 | location / {
203 | proxy_pass http://test;
204 | }
205 |
206 | --- request
207 | GET /
208 | --- response_body_like: ^<(.*)>$
209 |
--------------------------------------------------------------------------------
/test/test.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | TEST_NGINX_USE_HUP=1 PATH=/home/yaoweibin/nginx/sbin:$PATH prove -r t
4 |
--------------------------------------------------------------------------------
/upstream_fair.patch:
--------------------------------------------------------------------------------
1 | diff --git a/ngx_http_upstream_fair_module.c b/ngx_http_upstream_fair_module.c
2 | index a4419ca..af80bba 100644
3 | --- a/ngx_http_upstream_fair_module.c
4 | +++ b/ngx_http_upstream_fair_module.c
5 | @@ -9,6 +9,10 @@
6 | #include
7 | #include
8 |
9 | +#if (NGX_HTTP_UPSTREAM_CHECK)
10 | +#include "ngx_http_upstream_check_module.h"
11 | +#endif
12 | +
13 | typedef struct {
14 | ngx_uint_t nreq;
15 | ngx_uint_t total_req;
16 | @@ -42,6 +42,10 @@ typedef struct {
17 | ngx_uint_t max_fails;
18 | time_t fail_timeout;
19 |
20 | +#if (NGX_HTTP_UPSTREAM_CHECK)
21 | + ngx_uint_t check_index;
22 | +#endif
23 | +
24 | time_t accessed;
25 | ngx_uint_t down:1;
26 |
27 | @@ -474,6 +478,15 @@ ngx_http_upstream_init_fair_rr(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
28 | peers->peer[n].fail_timeout = server[i].fail_timeout;
29 | peers->peer[n].down = server[i].down;
30 | peers->peer[n].weight = server[i].down ? 0 : server[i].weight;
31 | +#if (NGX_HTTP_UPSTREAM_CHECK)
32 | + if (!server[i].down) {
33 | + peers->peer[n].check_index =
34 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
35 | + }
36 | + else {
37 | + peers->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
38 | + }
39 | +#endif
40 | n++;
41 | }
42 | }
43 | @@ -524,6 +537,15 @@ ngx_http_upstream_init_fair_rr(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
44 | backup->peer[n].max_fails = server[i].max_fails;
45 | backup->peer[n].fail_timeout = server[i].fail_timeout;
46 | backup->peer[n].down = server[i].down;
47 | +#if (NGX_HTTP_UPSTREAM_CHECK)
48 | + if (!server[i].down) {
49 | + backup->peer[n].check_index =
50 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]);
51 | + }
52 | + else {
53 | + backup->peer[n].check_index = (ngx_uint_t) NGX_ERROR;
54 | + }
55 | +#endif
56 | n++;
57 | }
58 | }
59 | @@ -580,6 +602,9 @@ ngx_http_upstream_init_fair_rr(ngx_conf_t *cf, ngx_http_upstream_srv_conf_t *us)
60 | peers->peer[i].weight = 1;
61 | peers->peer[i].max_fails = 1;
62 | peers->peer[i].fail_timeout = 10;
63 | +#if (NGX_HTTP_UPSTREAM_CHECK)
64 | + peers->peer[i].check_index = (ngx_uint_t) NGX_ERROR;
65 | +#endif
66 | }
67 |
68 | us->peer.data = peers;
69 | @@ -723,6 +748,12 @@ ngx_http_upstream_fair_try_peer(ngx_peer_connection_t *pc,
70 | peer = &fp->peers->peer[peer_id];
71 |
72 | if (!peer->down) {
73 | +#if (NGX_HTTP_UPSTREAM_CHECK)
74 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0,
75 | + "[upstream_fair] get fair peer, check_index: %ui",
76 | + peer->check_index);
77 | + if (!ngx_http_upstream_check_peer_down(peer->check_index)) {
78 | +#endif
79 | if (peer->max_fails == 0 || peer->shared->fails < peer->max_fails) {
80 | return NGX_OK;
81 | }
82 | @@ -733,6 +764,9 @@ ngx_http_upstream_fair_try_peer(ngx_peer_connection_t *pc,
83 | peer->shared->fails = 0;
84 | return NGX_OK;
85 | }
86 | +#if (NGX_HTTP_UPSTREAM_CHECK)
87 | + }
88 | +#endif
89 | }
90 |
91 | return NGX_BUSY;
92 |
--------------------------------------------------------------------------------
/util/chomp.rb:
--------------------------------------------------------------------------------
1 | STDIN.each do |line|
2 | next unless line
3 | res = line.gsub(/\s+$/, "")
4 | puts "#{res}"
5 | end
6 |
--------------------------------------------------------------------------------
/util/chomp.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | for file in *
4 | do
5 | if [ -d "$file" ]
6 | then
7 | continue
8 | fi
9 |
10 | ruby util/chomp.rb < $file > /tmp/tt
11 | mv /tmp/tt $file
12 | done
13 |
14 | rm -f /tmp/tt
15 |
--------------------------------------------------------------------------------
/util/update-readme.sh:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | perl util/wiki2pod.pl doc/README.wiki > /tmp/a.pod && pod2text /tmp/a.pod > doc/README.txt
4 |
5 | cp doc/README.txt README
6 |
--------------------------------------------------------------------------------
/util/wiki2pod.pl:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env perl
2 |
3 | use strict;
4 | use warnings;
5 | use bytes;
6 |
7 | my @nl_counts;
8 | my $last_nl_count_level;
9 |
10 | my @bl_counts;
11 | my $last_bl_count_level;
12 |
13 | sub fmt_pos ($) {
14 | (my $s = $_[0]) =~ s{\#(.*)}{/"$1"};
15 | $s;
16 | }
17 |
18 | sub fmt_mark ($$) {
19 | my ($tag, $s) = @_;
20 | my $max_level = 0;
21 | while ($s =~ /([<>])\1*/g) {
22 | my $level = length $&;
23 | if ($level > $max_level) {
24 | $max_level = $level;
25 | }
26 | }
27 |
28 | my $times = $max_level + 1;
29 | if ($times > 1) {
30 | $s = " $s ";
31 | }
32 | return $tag . ('<' x $times) . $s . ('>' x $times);
33 | }
34 |
35 | print "=encoding utf-8\n\n";
36 |
37 | while (<>) {
38 | if ($. == 1) {
39 | # strip the leading U+FEFF byte in MS-DOS text files
40 | my $first = ord(substr($_, 0, 1));
41 | #printf STDERR "0x%x", $first;
42 | #my $second = ord(substr($_, 2, 1));
43 | #printf STDERR "0x%x", $second;
44 | if ($first == 0xEF) {
45 | substr($_, 0, 1, '');
46 | #warn "Hit!";
47 | }
48 | }
49 | s{\[(http[^ \]]+) ([^\]]*)\]}{$2 (L<$1>)}gi;
50 | s{ \[\[ ( [^\]\|]+ ) \| ([^\]]*) \]\] }{"L<$2|" . fmt_pos($1) . ">"}gixe;
51 | s{(.*?)
}{fmt_mark('C', $1)}gie;
52 | s{'''(.*?)'''}{fmt_mark('B', $1)}ge;
53 | s{''(.*?)''}{fmt_mark('I', $1)}ge;
54 | if (s{^\s*<[^>]+>\s*$}{}) {
55 | next;
56 | }
57 |
58 | if (/^\s*$/) {
59 | print "\n";
60 | next;
61 | }
62 |
63 | =begin cmt
64 |
65 | if ($. == 1) {
66 | warn $_;
67 | for my $i (0..length($_) - 1) {
68 | my $chr = substr($_, $i, 1);
69 | warn "chr ord($i): ".ord($chr)." \"$chr\"\n";
70 | }
71 | }
72 |
73 | =end cmt
74 | =cut
75 |
76 | if (/(=+) (.*) \1$/) {
77 | #warn "HERE! $_" if $. == 1;
78 | my ($level, $title) = (length $1, $2);
79 | collapse_lists();
80 |
81 | print "\n=head$level $title\n\n";
82 | } elsif (/^(\#+) (.*)/) {
83 | my ($level, $txt) = (length($1) - 1, $2);
84 | if (defined $last_nl_count_level && $level != $last_nl_count_level) {
85 | print "\n=back\n\n";
86 | }
87 | $last_nl_count_level = $level;
88 | $nl_counts[$level] ||= 0;
89 | if ($nl_counts[$level] == 0) {
90 | print "\n=over\n\n";
91 | }
92 | $nl_counts[$level]++;
93 | print "\n=item $nl_counts[$level].\n\n";
94 | print "$txt\n";
95 | } elsif (/^(\*+) (.*)/) {
96 | my ($level, $txt) = (length($1) - 1, $2);
97 | if (defined $last_bl_count_level && $level != $last_bl_count_level) {
98 | print "\n=back\n\n";
99 | }
100 | $last_bl_count_level = $level;
101 | $bl_counts[$level] ||= 0;
102 | if ($bl_counts[$level] == 0) {
103 | print "\n=over\n\n";
104 | }
105 | $bl_counts[$level]++;
106 | print "\n=item *\n\n";
107 | print "$txt\n";
108 | } else {
109 | collapse_lists();
110 | print;
111 | }
112 | }
113 |
114 | collapse_lists();
115 |
116 | sub collapse_lists {
117 | while (defined $last_nl_count_level && $last_nl_count_level >= 0) {
118 | print "\n=back\n\n";
119 | $last_nl_count_level--;
120 | }
121 | undef $last_nl_count_level;
122 | undef @nl_counts;
123 |
124 | while (defined $last_bl_count_level && $last_bl_count_level >= 0) {
125 | print "\n=back\n\n";
126 | $last_bl_count_level--;
127 | }
128 | undef $last_bl_count_level;
129 | undef @bl_counts;
130 | }
131 |
132 |
--------------------------------------------------------------------------------