├── .astylerc ├── .format.sh ├── CHANGELOG.md ├── README.md ├── check.patch ├── check_1.11.1+.patch ├── check_1.11.5+.patch ├── check_1.12.1+.patch ├── check_1.14.0+.patch ├── check_1.16.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 ├── 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 └── y ├── CHANGELOG.tpl.md └── config.yml /.astylerc: -------------------------------------------------------------------------------- 1 | # astylerc 2 | align-pointer=name 3 | align-reference=name 4 | break-after-logical 5 | #indent=spaces=2 6 | max-code-length=120 7 | style=google 8 | suffix=none 9 | 10 | # Indent 11 | indent-preproc-block 12 | 13 | # Padding 14 | pad-header 15 | unpad-paren 16 | 17 | # Formatting: 18 | add-brackets 19 | #convert-tabs 20 | 21 | # Output: 22 | formatted 23 | -------------------------------------------------------------------------------- /.format.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Search in the script folder 4 | pushd "$(dirname $0)" >/dev/null 5 | CWD="$(pwd -P)" 6 | popd >/dev/null 7 | FILES='ngx_http_upstream_check_module.c ngx_http_upstream_check_module.h' 8 | 9 | # The file format in accordance with the style defined in .astylerc 10 | astyle -v --options='.astylerc' ${FILES} || (echo 'astyle failed'; exit 1); 11 | 12 | # To correct this, the issuance dos2unix on each file 13 | # sometimes adds in Windows as a string-endins (\r\n). 14 | dos2unix --quiet ${FILES} || (echo 'dos2unix failed'; exit 2); 15 | 16 | -------------------------------------------------------------------------------- /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.14.0+.patch: -------------------------------------------------------------------------------- 1 | diff -burN nginx-1.14.0.orig/src/http/modules/ngx_http_upstream_hash_module.c nginx-1.14.0/src/http/modules/ngx_http_upstream_hash_module.c 2 | --- nginx-1.14.0.orig/src/http/modules/ngx_http_upstream_hash_module.c 2018-06-28 21:30:48.891580738 +0000 3 | +++ nginx-1.14.0/src/http/modules/ngx_http_upstream_hash_module.c 2018-06-28 21:40:41.801180483 +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 | @@ -554,6 +565,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.14.0.orig/src/http/modules/ngx_http_upstream_ip_hash_module.c nginx-1.14.0/src/http/modules/ngx_http_upstream_ip_hash_module.c 46 | --- nginx-1.14.0.orig/src/http/modules/ngx_http_upstream_ip_hash_module.c 2018-06-28 21:30:48.891580738 +0000 47 | +++ nginx-1.14.0/src/http/modules/ngx_http_upstream_ip_hash_module.c 2018-06-28 21:49:12.608780187 +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.14.0.orig/src/http/modules/ngx_http_upstream_least_conn_module.c nginx-1.14.0/src/http/modules/ngx_http_upstream_least_conn_module.c 75 | --- nginx-1.14.0.orig/src/http/modules/ngx_http_upstream_least_conn_module.c 2018-06-28 21:30:48.895580638 +0000 76 | +++ nginx-1.14.0/src/http/modules/ngx_http_upstream_least_conn_module.c 2018-06-28 21:50:48.542450442 +0000 77 | @@ -9,6 +9,9 @@ 78 | #include 79 | #include 80 | 81 | +#if (NGX_HTTP_UPSTREAM_CHECK) 82 | +#include "ngx_http_upstream_check_module.h" 83 | +#endif 84 | 85 | static ngx_int_t ngx_http_upstream_init_least_conn_peer(ngx_http_request_t *r, 86 | ngx_http_upstream_srv_conf_t *us); 87 | @@ -147,6 +150,16 @@ 88 | continue; 89 | } 90 | 91 | +#if (NGX_HTTP_UPSTREAM_CHECK) 92 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 93 | + "get least_conn peer, check_index: %ui", 94 | + peer->check_index); 95 | + 96 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 97 | + continue; 98 | + } 99 | +#endif 100 | + 101 | if (peer->max_fails 102 | && peer->fails >= peer->max_fails 103 | && now - peer->checked <= peer->fail_timeout) 104 | @@ -202,6 +215,16 @@ 105 | continue; 106 | } 107 | 108 | +#if (NGX_HTTP_UPSTREAM_CHECK) 109 | + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, pc->log, 0, 110 | + "get least_conn peer, check_index: %ui", 111 | + peer->check_index); 112 | + 113 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 114 | + continue; 115 | + } 116 | +#endif 117 | + 118 | if (peer->conns * best->weight != best->conns * peer->weight) { 119 | continue; 120 | } 121 | diff -burN nginx-1.14.0.orig/src/http/ngx_http_upstream_round_robin.c nginx-1.14.0/src/http/ngx_http_upstream_round_robin.c 122 | --- nginx-1.14.0.orig/src/http/ngx_http_upstream_round_robin.c 2018-06-28 21:30:48.887580840 +0000 123 | +++ nginx-1.14.0/src/http/ngx_http_upstream_round_robin.c 2018-06-28 21:54:36.492914512 +0000 124 | @@ -9,6 +9,9 @@ 125 | #include 126 | #include 127 | 128 | +#if (NGX_HTTP_UPSTREAM_CHECK) 129 | +#include "ngx_http_upstream_check_module.h" 130 | +#endif 131 | 132 | #define ngx_http_upstream_tries(p) ((p)->number \ 133 | + ((p)->next ? (p)->next->number : 0)) 134 | @@ -98,6 +101,15 @@ 135 | peer[n].down = server[i].down; 136 | peer[n].server = server[i].name; 137 | 138 | +#if (NGX_HTTP_UPSTREAM_CHECK) 139 | + if (!server[i].down) { 140 | + peer[n].check_index = 141 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 142 | + } else { 143 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 144 | + } 145 | +#endif 146 | + 147 | *peerp = &peer[n]; 148 | peerp = &peer[n].next; 149 | n++; 150 | @@ -162,6 +174,16 @@ 151 | peer[n].down = server[i].down; 152 | peer[n].server = server[i].name; 153 | 154 | +#if (NGX_HTTP_UPSTREAM_CHECK) 155 | + if (!server[i].down) { 156 | + peer[n].check_index = 157 | + ngx_http_upstream_check_add_peer(cf, us, &server[i].addrs[j]); 158 | + } 159 | + else { 160 | + peer[n].check_index = (ngx_uint_t) NGX_ERROR; 161 | + } 162 | +#endif 163 | + 164 | *peerp = &peer[n]; 165 | peerp = &peer[n].next; 166 | n++; 167 | @@ -228,6 +250,9 @@ 168 | peer[i].max_conns = 0; 169 | peer[i].max_fails = 1; 170 | peer[i].fail_timeout = 10; 171 | +#if (NGX_HTTP_UPSTREAM_CHECK) 172 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 173 | +#endif 174 | *peerp = &peer[i]; 175 | peerp = &peer[i].next; 176 | } 177 | @@ -344,6 +369,9 @@ 178 | peer[0].max_conns = 0; 179 | peer[0].max_fails = 1; 180 | peer[0].fail_timeout = 10; 181 | +#if (NGX_HTTP_UPSTREAM_CHECK) 182 | + peer[0].check_index = (ngx_uint_t) NGX_ERROR; 183 | +#endif 184 | peers->peer = peer; 185 | 186 | } else { 187 | @@ -378,6 +406,9 @@ 188 | peer[i].max_conns = 0; 189 | peer[i].max_fails = 1; 190 | peer[i].fail_timeout = 10; 191 | +#if (NGX_HTTP_UPSTREAM_CHECK) 192 | + peer[i].check_index = (ngx_uint_t) NGX_ERROR; 193 | +#endif 194 | *peerp = &peer[i]; 195 | peerp = &peer[i].next; 196 | } 197 | @@ -443,6 +474,12 @@ 198 | goto failed; 199 | } 200 | 201 | +#if (NGX_HTTP_UPSTREAM_CHECK) 202 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 203 | + goto failed; 204 | + } 205 | +#endif 206 | + 207 | rrp->current = peer; 208 | 209 | } else { 210 | @@ -537,6 +574,12 @@ 211 | continue; 212 | } 213 | 214 | +#if (NGX_HTTP_UPSTREAM_CHECK) 215 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 216 | + continue; 217 | + } 218 | +#endif 219 | + 220 | if (peer->max_fails 221 | && peer->fails >= peer->max_fails 222 | && now - peer->checked <= peer->fail_timeout) 223 | diff -burN nginx-1.14.0.orig/src/http/ngx_http_upstream_round_robin.h nginx-1.14.0/src/http/ngx_http_upstream_round_robin.h 224 | --- nginx-1.14.0.orig/src/http/ngx_http_upstream_round_robin.h 2018-06-28 21:30:48.895580638 +0000 225 | +++ nginx-1.14.0/src/http/ngx_http_upstream_round_robin.h 2018-06-28 21:55:13.036027376 +0000 226 | @@ -38,6 +38,10 @@ 227 | ngx_msec_t slow_start; 228 | ngx_msec_t start_time; 229 | 230 | +#if (NGX_HTTP_UPSTREAM_CHECK) 231 | + ngx_uint_t check_index; 232 | +#endif 233 | + 234 | ngx_uint_t down; 235 | 236 | #if (NGX_HTTP_SSL || NGX_COMPAT) 237 | -------------------------------------------------------------------------------- /check_1.16.1+.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 6c247b5..1ae9cce 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 | @@ -238,6 +241,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", peer->check_index); 22 | + if (ngx_http_upstream_check_peer_down(peer->check_index)) { 23 | + goto next; 24 | + } 25 | +#endif 26 | + 27 | if (peer->max_fails 28 | && peer->fails >= peer->max_fails 29 | && now - peer->checked <= peer->fail_timeout) 30 | @@ -560,6 +571,15 @@ 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 | + 43 | if (peer->server.len != server->len 44 | || ngx_strncmp(peer->server.data, server->data, server->len) 45 | != 0) 46 | diff --git a/src/http/modules/ngx_http_upstream_ip_hash_module.c b/src/http/modules/ngx_http_upstream_ip_hash_module.c 47 | index 1fa01d9..366aca9 100644 48 | --- a/src/http/modules/ngx_http_upstream_ip_hash_module.c 49 | +++ b/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 | @@ -208,6 +211,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 a/src/http/modules/ngx_http_upstream_least_conn_module.c b/src/http/modules/ngx_http_upstream_least_conn_module.c 77 | index ebe0627..3525035 100644 78 | --- a/src/http/modules/ngx_http_upstream_least_conn_module.c 79 | +++ b/src/http/modules/ngx_http_upstream_least_conn_module.c 80 | @@ -9,6 +9,9 @@ 81 | #include 82 | #include 83 | 84 | +#if (NGX_HTTP_UPSTREAM_CHECK) 85 | +#include "ngx_http_upstream_check_module.h" 86 | +#endif 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 +150,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 +215,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 a/src/http/ngx_http_upstream_round_robin.c b/src/http/ngx_http_upstream_round_robin.c 125 | index f72de3e..78b3342 100644 126 | --- a/src/http/ngx_http_upstream_round_robin.c 127 | +++ b/src/http/ngx_http_upstream_round_robin.c 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 | @@ -98,6 +101,15 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 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 | + 151 | *peerp = &peer[n]; 152 | peerp = &peer[n].next; 153 | n++; 154 | @@ -162,6 +174,16 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 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 | + 168 | *peerp = &peer[n]; 169 | peerp = &peer[n].next; 170 | n++; 171 | @@ -228,6 +250,9 @@ ngx_http_upstream_init_round_robin(ngx_conf_t *cf, 172 | peer[i].max_conns = 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 | @@ -344,6 +369,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 182 | peer[0].max_conns = 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 | @@ -378,6 +406,9 @@ ngx_http_upstream_create_round_robin_peer(ngx_http_request_t *r, 192 | peer[i].max_conns = 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 | @@ -443,6 +474,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 | rrp->current = peer; 212 | 213 | } else { 214 | @@ -537,6 +574,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 45f258d..dee91d0 100644 229 | --- a/src/http/ngx_http_upstream_round_robin.h 230 | +++ b/src/http/ngx_http_upstream_round_robin.h 231 | @@ -38,6 +38,10 @@ struct ngx_http_upstream_rr_peer_s { 232 | ngx_msec_t slow_start; 233 | ngx_msec_t start_time; 234 | 235 | +#if (NGX_HTTP_UPSTREAM_CHECK) 236 | + ngx_uint_t check_index; 237 | +#endif 238 | + 239 | ngx_uint_t down; 240 | 241 | #if (NGX_HTTP_SSL || NGX_COMPAT) 242 | -------------------------------------------------------------------------------- /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="#include " 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=0; printf("%d", 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 | -------------------------------------------------------------------------------- /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 | ngx_uint_t ngx_http_upstream_check_upstream_down(ngx_str_t *upstream); 14 | 15 | void ngx_http_upstream_check_get_peer(ngx_uint_t index); 16 | void ngx_http_upstream_check_free_peer(ngx_uint_t index); 17 | 18 | 19 | #endif //_NGX_HTTP_UPSTREAM_CHECK_MODELE_H_INCLUDED_ 20 | 21 | -------------------------------------------------------------------------------- /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 | -------------------------------------------------------------------------------- /y/CHANGELOG.tpl.md: -------------------------------------------------------------------------------- 1 | {{ range .Versions }} 2 | 3 | ## {{ if .Tag.Previous }}[{{ .Tag.Name }}]({{ $.Info.RepositoryURL }}/compare/{{ .Tag.Previous.Name }}...{{ .Tag.Name }}){{ else }}{{ .Tag.Name }}{{ end }} 4 | 5 | > {{ datetime "2006-01-02" .Tag.Date }} 6 | 7 | {{ range .CommitGroups -}} 8 | ### {{ .Title }} 9 | 10 | {{ range .Commits -}} 11 | * {{ if .Scope }}**{{ .Scope }}:** {{ end }}{{ .Subject }} 12 | {{ end }} 13 | {{ end -}} 14 | 15 | {{- if .RevertCommits -}} 16 | ### Reverts 17 | 18 | {{ range .RevertCommits -}} 19 | * {{ .Revert.Header }} 20 | {{ end }} 21 | {{ end -}} 22 | 23 | {{- if .MergeCommits -}} 24 | ### Pull Requests 25 | 26 | {{ range .MergeCommits -}} 27 | * {{ .Header }} 28 | {{ end }} 29 | {{ end -}} 30 | 31 | {{- if .NoteGroups -}} 32 | {{ range .NoteGroups -}} 33 | ### {{ .Title }} 34 | 35 | {{ range .Notes }} 36 | {{ .Body }} 37 | {{ end }} 38 | {{ end -}} 39 | {{ end -}} 40 | {{ end -}} -------------------------------------------------------------------------------- /y/config.yml: -------------------------------------------------------------------------------- 1 | style: github 2 | template: CHANGELOG.tpl.md 3 | info: 4 | title: CHANGELOG 5 | repository_url: https://github.com/nginx-modules/nginx_upstream_check_module 6 | options: 7 | commits: 8 | # filters: 9 | # Type: 10 | # - feat 11 | # - fix 12 | # - perf 13 | # - refactor 14 | commit_groups: 15 | # title_maps: 16 | # feat: Features 17 | # fix: Bug Fixes 18 | # perf: Performance Improvements 19 | # refactor: Code Refactoring 20 | header: 21 | pattern: "^(\\w*)(?:\\(([\\w\\$\\.\\-\\*\\s]*)\\))?\\:\\s(.*)$" 22 | pattern_maps: 23 | - Type 24 | - Scope 25 | - Subject 26 | notes: 27 | keywords: 28 | - BREAKING CHANGE --------------------------------------------------------------------------------