From a79d5dcbdaf5ecf3feef91696ea4943bb66807e0 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Thu, 24 Nov 2022 19:55:48 +0800 Subject: [PATCH 1/9] fixed http_proxy_connect_resolve_variables.t: return 200 instead of root/index.html --- t/http_proxy_connect_resolve_variables.t | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/t/http_proxy_connect_resolve_variables.t b/t/http_proxy_connect_resolve_variables.t index e9a1c65..b19d2f4 100644 --- a/t/http_proxy_connect_resolve_variables.t +++ b/t/http_proxy_connect_resolve_variables.t @@ -126,6 +126,16 @@ http { set $proxy_connect_send_timeout "2ms"; } + if ($request ~ "127.0.0.1:8082") { + # must be larger than 1s (server 8082 lua sleep(1s)) + set $proxy_connect_read_timeout "1200ms"; + } + + if ($request ~ "127.0.0.1:8083") { + # must be larger than 0.5s (server 8082 lua sleep(0.5s)) + set $proxy_connect_read_timeout "700ms"; + } + location / { proxy_pass http://127.0.0.01:8081; } @@ -157,6 +167,7 @@ http { rewrite_by_lua ' ngx.sleep(1) ngx.say("8082 server fbt") + ngx.exit(ngx.HTTP_OK) '; } @@ -166,6 +177,7 @@ http { rewrite_by_lua ' ngx.sleep(0.5) ngx.say("8083 server fbt") + ngx.exit(ngx.HTTP_OK) '; } @@ -230,11 +242,16 @@ like($errlog, qr/proxy_connect: non-existent-domain.com could not be resolved .+ # test first byte time # fbt:~1s -http_connect_request('127.0.0.1', '8082', '/'); +my $r; +$r = http_connect_request('127.0.0.1', '8082', '/'); +like($r, qr/8082 server fbt/, "test first byte time: 1s, receive response from backend server"); $log = http_get('/connect.log'); like($log, qr/"CONNECT 127.0.0.1:8082 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:1\....,/, 'test first byte time: 1s'); + # fbt:~0.5s -http_connect_request('127.0.0.1', '8083', '/'); +$r = http_connect_request('127.0.0.1', '8083', '/'); +like($r, qr/8083 server fbt/, "test first byte time: 0.5s, receive response from backend server"); + $log = http_get('/connect.log'); like($log, qr/"CONNECT 127.0.0.1:8083 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:0\.5..,/, 'test first byte time: 0.5s'); From 834a1c7a0d8358456e83d45310112df10c5bbe36 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Thu, 24 Nov 2022 20:10:14 +0800 Subject: [PATCH 2/9] test cases: use t->read_file instead of getting log from http request --- t/http_proxy_connect_resolve_variables.t | 51 +++++++++-------------- t/http_proxy_connect_timeout.t | 52 +++++++----------------- 2 files changed, 33 insertions(+), 70 deletions(-) diff --git a/t/http_proxy_connect_resolve_variables.t b/t/http_proxy_connect_resolve_variables.t index b19d2f4..9a98bd5 100644 --- a/t/http_proxy_connect_resolve_variables.t +++ b/t/http_proxy_connect_resolve_variables.t @@ -139,19 +139,6 @@ http { location / { proxy_pass http://127.0.0.01:8081; } - - # used to output connect.log - location = /connect.log { - access_log off; - root %%TESTDIR%%/; - } - - # used to output error.log - location = /connect_error.log { - access_log off; - root %%TESTDIR%%/; - } - } server { @@ -204,56 +191,56 @@ if ($@) { # exit #} -my $log; -my $errlog; - TODO: { # $proxy_connect_connect_time has value, $proxy_connect_connect_time is "-" local $TODO = '# This case will pass, if connecting 8.8.8.8 timed out.'; http_connect_request('test-connect-timeout.com', '8888', '/'); - $log = http_get('/connect.log'); - like($log, qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" 504 .+ resolve:\d+\.\d+,connect:-/, + like($t->read_file('connect.log'), + qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" 504 .+ resolve:\d+\.\d+,connect:-/, 'connect timed out log: get $var & status=504'); - $errlog = http_get('/connect_error.log'); - like($errlog, qr/proxy_connect: upstream connect timed out \(peer:8\.8\.8\.8:8888\) while connecting to upstream/, + like($t->read_file('connect_error.log'), + qr/proxy_connect: upstream connect timed out \(peer:8\.8\.8\.8:8888\) while connecting to upstream/, 'connect timed out error log'); } # Both $proxy_connect_resolve_time & $proxy_connect_connect_time are empty string. http_get('/200'); -$log = http_get('/connect.log'); -like($log, qr/GET \/200.*resolve:,connect:,/, +like($t->read_file('connect.log'), + qr/GET \/200.*resolve:,connect:,/, 'For GET request, both $proxy_connect_resolve_time & $proxy_connect_connect_time are empty string'); # Both $proxy_connect_resolve_time & $proxy_connect_connect_time have value. http_connect_request('127.0.0.1', '8081', '/'); -$log = http_get('/connect.log'); -like($log, qr/"CONNECT 127.0.0.1:8081 HTTP\/1.1" 200 .+ resolve:0\.\d+,connect:0\.\d+,/, +like($t->read_file('connect.log'), + qr/"CONNECT 127.0.0.1:8081 HTTP\/1.1" 200 .+ resolve:0\.\d+,connect:0\.\d+,/, 'For CONNECT request, test both $proxy_connect_resolve_time & $proxy_connect_connect_time'); # DNS resolving fails. Both $proxy_connect_resolve_time & $proxy_connect_connect_time are "-". http_connect_request('non-existent-domain.com', '8081', '/'); -$log = http_get('/connect.log'); -like($log, qr/"CONNECT non-existent-domain.com:8081 HTTP\/1.1" 502 .+ resolve:-,connect:-,/, +like($t->read_file('connect.log'), + qr/"CONNECT non-existent-domain.com:8081 HTTP\/1.1" 502 .+ resolve:-,connect:-,/, 'For CONNECT request, test both $proxy_connect_resolve_time & $proxy_connect_connect_time'); -$errlog = http_get('/connect_error.log'); -like($errlog, qr/proxy_connect: non-existent-domain.com could not be resolved .+Host not found/, 'test error.log for 502 respsone'); +like($t->read_file('connect_error.log'), + qr/proxy_connect: non-existent-domain.com could not be resolved .+Host not found/, + 'test error.log for 502 respsone'); # test first byte time # fbt:~1s my $r; $r = http_connect_request('127.0.0.1', '8082', '/'); like($r, qr/8082 server fbt/, "test first byte time: 1s, receive response from backend server"); -$log = http_get('/connect.log'); -like($log, qr/"CONNECT 127.0.0.1:8082 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:1\....,/, 'test first byte time: 1s'); +like($t->read_file('connect.log'), + qr/"CONNECT 127.0.0.1:8082 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:1\....,/, + 'test first byte time: 1s'); # fbt:~0.5s $r = http_connect_request('127.0.0.1', '8083', '/'); like($r, qr/8083 server fbt/, "test first byte time: 0.5s, receive response from backend server"); -$log = http_get('/connect.log'); -like($log, qr/"CONNECT 127.0.0.1:8083 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:0\.5..,/, 'test first byte time: 0.5s'); +like($t->read_file('connect.log'), + qr/"CONNECT 127.0.0.1:8083 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:0\.5..,/, + 'test first byte time: 0.5s'); $t->stop(); diff --git a/t/http_proxy_connect_timeout.t b/t/http_proxy_connect_timeout.t index d1e6201..5e9001c 100644 --- a/t/http_proxy_connect_timeout.t +++ b/t/http_proxy_connect_timeout.t @@ -53,12 +53,6 @@ my %aroute_map = ( # AAAA record (ipv6) my %aaaaroute_map; -# my %aaaaroute_map = ( -# 'www.test-a.com' => [[300, "[::1]"]], -# 'www.test-b.com' => [[300, "[::1]"]], -# #'www.test-a.com' => [[300, "127.0.0.1"]], -# #'www.test-b.com' => [[300, "127.0.0.1"]], -# ); start_bind(); @@ -67,20 +61,16 @@ start_bind(); ############################################################################### my $nginx_conf = <<'EOF'; - %%TEST_GLOBALS%% - daemon off; - -events { -} +events { } http { %%TEST_GLOBALS_HTTP%% #LUA_PACKAGE_PATH - # If you build nginx with lua-nginx-module, please enable - # directive "lua_package_path". For more details, see: + # If you build nginx with lua-nginx-module, please enable + # directive "lua_package_path". For more details, see: # https://github.com/openresty/lua-nginx-module#installation #lua_package_path "/path/to/lib/lua/?.lua;;"; @@ -103,7 +93,6 @@ http { proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; proxy_connect_send_timeout 10s; - proxy_connect_send_lowat 0; set $proxy_connect_connect_timeout "101ms"; set $proxy_connect_send_timeout "102ms"; @@ -121,19 +110,6 @@ http { location / { proxy_pass http://127.0.0.01:8081; } - - # used to output connect.log - location = /connect.log { - access_log off; - root %%TESTDIR%%/; - } - - # used to output error.log - location = /connect_error.log { - access_log off; - root %%TESTDIR%%/; - } - } } @@ -157,26 +133,26 @@ if ($@) { # exit #} -my $log; -my $errlog; - TODO: { local $TODO = '# This case will pass, if connecting 8.8.8.8 timed out.'; like(http_connect_request('test-connect-timeout.com', '8888', '/'), qr/504/, 'connect timed out: set $var'); - $log = http_get('/connect.log'); - like($log, qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" 504 .+ c:1,s:102,r:103/, + like($t->read_file('connect.log'), + qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" 504 .+ c:1,s:102,r:103/, 'connect timed out log: get $var & status=504'); - $errlog = http_get('/connect_error.log'); - like($errlog, qr/proxy_connect: upstream connect timed out \(peer:8\.8\.8\.8:8888\) while connecting to upstream/, + like($t->read_file('connect_error.log'), + qr/proxy_connect: upstream connect timed out \(peer:8\.8\.8\.8:8888\) while connecting to upstream/, 'connect timed out error log'); } http_connect_request('test-read-timeout.com', '8888', '/'); -# test $proxy_connect_*_timeout -$log = http_get('/connect.log'); -like($log, qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" ... .+ c:1,s:102,r:103/, 'connect timed out log: get $var'); -like($log, qr/"CONNECT test-read-timeout.com:8888 HTTP\/1.1" ... .+ c:3,s:2,r:1/, 'connect/send/read timed out log: get $var'); +# test reading variables of $proxy_connect_*_timeout +like($t->read_file('connect.log'), + qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" ... .+ c:1,s:102,r:103/, + 'connect timed out log: get $var'); +like($t->read_file('connect.log'), + qr/"CONNECT test-read-timeout.com:8888 HTTP\/1.1" ... .+ c:3,s:2,r:1/, + 'connect/send/read timed out log: get $var'); $t->stop(); From bed2a0872de6f1c5dbcdd80c33039efc98301bf3 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Thu, 24 Nov 2022 21:05:36 +0800 Subject: [PATCH 3/9] refactor logic of handling proxy timer 1. Refactor timer logic in ngx_http_proxy_connect_tunnel(), refer to ngx_stream_proxy_process() in ngx_stream_proxy_module. It only adds one timer after it processes r/w operations on client or proxied server connections. 2. With the new timer logic, it will fix connection break that it continues to upload data to backend 3. The directive `proxy_connect_read_timeout` has been changed to: Sets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed. 4. The directive `proxy_connect_send_timeout` has been deprecated. 5. Added new test cases and documentation for new timer logic --- README.md | 11 +-- ngx_http_proxy_connect_module.c | 112 ++++++++++------------- t/http_proxy_connect_resolve_variables.t | 28 +++++- 3 files changed, 79 insertions(+), 72 deletions(-) diff --git a/README.md b/README.md index a543843..2ec668e 100644 --- a/README.md +++ b/README.md @@ -337,9 +337,7 @@ Syntax: **proxy_connect_read_timeout `time`** Default: `60s` Context: `server` -Defines a timeout for reading a response from the proxied server. -The timeout is set only between two successive read operations, not for the transmission of the whole response. -If the proxied server does not transmit anything within this time, the connection is closed. +Sets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed. proxy_connect_send_timeout -------------------------- @@ -348,9 +346,8 @@ Syntax: **proxy_connect_send_timeout `time`** Default: `60s` Context: `server` -Sets a timeout for transmitting a request to the proxied server. -The timeout is set only between two successive write operations, not for the transmission of the whole request. -If the proxied server does not receive anything within this time, the connection is closed. +Deprecated, it has no function. +Use the directive `proxy_connect_read_timeout` instead for both read and write operations. proxy_connect_address --------------------- @@ -473,7 +470,7 @@ Get or set a timeout of [`proxy_connect_read_timeout` directive](#proxy_connect_ $proxy_connect_send_timeout --------------------------- -Get or set a timeout of [`proxy_connect_send_timeout` directive](#proxy_connect_send_timeout). +Deprecated. $proxy_connect_resolve_time --------------------------- diff --git a/ngx_http_proxy_connect_module.c b/ngx_http_proxy_connect_module.c index cb760c1..63bcfd1 100644 --- a/ngx_http_proxy_connect_module.c +++ b/ngx_http_proxy_connect_module.c @@ -617,9 +617,10 @@ ngx_http_proxy_connect_send_connection_established(ngx_http_request_t *r) } /* n == NGX_AGAIN */ + r->write_event_handler = ngx_http_proxy_connect_send_handler; - ngx_add_timer(c->write, ctx->send_timeout); + ngx_add_timer(c->write, ctx->read_timeout); if (ngx_handle_write_event(c->write, clcf->send_lowat) != NGX_OK) { ngx_http_proxy_connect_finalize_request(r, u, @@ -635,11 +636,12 @@ static void ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, ngx_uint_t from_upstream, ngx_uint_t do_write) { + char *recv_action, *send_action; size_t size; ssize_t n; ngx_buf_t *b; - ngx_connection_t *c, *downstream, *upstream, *dst, *src; - ngx_http_core_loc_conf_t *clcf; + ngx_uint_t flags; + ngx_connection_t *c, *pc, *dst, *src; ngx_http_proxy_connect_ctx_t *ctx; ngx_http_proxy_connect_upstream_t *u; @@ -652,17 +654,19 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, "proxy_connect: tunnel fu:%ui write:%ui", from_upstream, do_write); - downstream = c; - upstream = u->peer.connection; + c = c; + pc = u->peer.connection; if (from_upstream) { - src = upstream; - dst = downstream; + src = pc; + dst = c; b = &u->buffer; + recv_action = "proxying and reading from upstream"; + send_action = "proxying and sending to client"; } else { - src = downstream; - dst = upstream; + src = c; + dst = pc; b = &u->from_client; if (r->header_in->last > r->header_in->pos) { @@ -683,6 +687,8 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, b->end = b->start + u->conf->buffer_size; b->temporary = 1; } + recv_action = "proxying and reading from client"; + send_action = "proxying and sending to upstream"; } for ( ;; ) { @@ -692,6 +698,7 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, size = b->last - b->pos; if (size && dst->write->ready) { + c->log->action = send_action; n = dst->send(dst, b->pos, size); @@ -719,6 +726,8 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, if (size && src->read->ready) { + c->log->action = recv_action; + n = src->recv(src, b->last, size); if (n == NGX_AGAIN || n == 0) { @@ -747,9 +756,13 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, break; } - if ((upstream->read->eof && u->buffer.pos == u->buffer.last) - || (downstream->read->eof && u->from_client.pos == u->from_client.last) - || (downstream->read->eof && upstream->read->eof)) + c->log->action = "proxying connection"; + + /* test finalize */ + + if ((pc->read->eof && u->buffer.pos == u->buffer.last) + || (c->read->eof && u->from_client.pos == u->from_client.last) + || (c->read->eof && pc->read->eof)) { ngx_log_debug0(NGX_LOG_DEBUG_HTTP, c->log, 0, "proxy_connect: tunnel done"); @@ -757,62 +770,25 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, return; } - clcf = ngx_http_get_module_loc_conf(r, ngx_http_core_module); + flags = src->read->eof ? NGX_CLOSE_EVENT : 0; - if (ngx_handle_write_event(upstream->write, u->conf->send_lowat) - != NGX_OK) - { + if (ngx_handle_read_event(src->read, flags) != NGX_OK) { ngx_http_proxy_connect_finalize_request(r, u, NGX_ERROR); return; } - if (upstream->write->active && !upstream->write->ready) { - ngx_add_timer(upstream->write, ctx->send_timeout); - - } else if (upstream->write->timer_set) { - ngx_del_timer(upstream->write); - } - - if (ngx_handle_read_event(upstream->read, 0) != NGX_OK) { - ngx_http_proxy_connect_finalize_request(r, u, NGX_ERROR); - return; - } - - if (upstream->read->active && !upstream->read->ready) { - if (from_upstream) { - ngx_add_timer(upstream->read, ctx->read_timeout); + if (dst) { + if (ngx_handle_write_event(dst->write, 0) != NGX_OK) { + ngx_http_proxy_connect_finalize_request(r, u, NGX_ERROR); + return; } - } else if (upstream->read->timer_set) { - ngx_del_timer(upstream->read); - } + if (!c->read->delayed && !pc->read->delayed) { + ngx_add_timer(c->write, ctx->read_timeout); - if (ngx_handle_write_event(downstream->write, clcf->send_lowat) - != NGX_OK) - { - ngx_http_proxy_connect_finalize_request(r, u, NGX_ERROR); - return; - } - - if (ngx_handle_read_event(downstream->read, 0) != NGX_OK) { - ngx_http_proxy_connect_finalize_request(r, u, NGX_ERROR); - return; - } - - if (downstream->write->active && !downstream->write->ready) { - ngx_add_timer(downstream->write, clcf->send_timeout); - - } else if (downstream->write->timer_set) { - ngx_del_timer(downstream->write); - } - - if (downstream->read->active && !downstream->read->ready) { - if (!from_upstream) { - ngx_add_timer(downstream->read, clcf->client_body_timeout); + } else if (c->write->timer_set) { + ngx_del_timer(c->write); } - - } else if (downstream->read->timer_set) { - ngx_del_timer(downstream->read); } } @@ -822,6 +798,10 @@ ngx_http_proxy_connect_read_downstream(ngx_http_request_t *r) { ngx_http_proxy_connect_ctx_t *ctx; + + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "proxy connect read downstream"); + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_connect_module); if (r->connection->read->timedout) { @@ -842,12 +822,15 @@ ngx_http_proxy_connect_write_downstream(ngx_http_request_t *r) { ngx_http_proxy_connect_ctx_t *ctx; + ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "proxy connect write downstream"); + ctx = ngx_http_get_module_ctx(r, ngx_http_proxy_connect_module); if (r->connection->write->timedout) { r->connection->timedout = 1; - ngx_log_error(NGX_LOG_ERR, r->connection->log, 0, - "proxy_connect: client write timed out"); + ngx_connection_error(r->connection, NGX_ETIMEDOUT, + "proxy_connect: connection timed out"); ngx_http_proxy_connect_finalize_request(r, ctx->u, NGX_HTTP_REQUEST_TIME_OUT); return; @@ -923,8 +906,9 @@ ngx_http_proxy_connect_write_upstream(ngx_http_request_t *r, c = u->peer.connection; - ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, - "proxy_connect: upstream write handler"); + ngx_log_debug1(NGX_LOG_DEBUG_HTTP, r->connection->log, 0, + "proxy_connect: upstream write handler %s", + u->connected ? "" : "(connect)"); if (c->write->timedout) { ngx_log_error(NGX_LOG_ERR, c->log, 0, @@ -1390,7 +1374,7 @@ ngx_http_proxy_connect_check_broken_connection(ngx_http_request_t *r, err = ngx_socket_errno; ngx_log_debug1(NGX_LOG_DEBUG_HTTP, ev->log, err, - "proxy_connect: upstream recv(): %d", n); + "proxy_connect: client recv(): %d", n); if (ev->write && (n >= 0 || err == NGX_EAGAIN)) { return; diff --git a/t/http_proxy_connect_resolve_variables.t b/t/http_proxy_connect_resolve_variables.t index 9a98bd5..e79c0ce 100644 --- a/t/http_proxy_connect_resolve_variables.t +++ b/t/http_proxy_connect_resolve_variables.t @@ -93,7 +93,7 @@ http { 'fbt:$proxy_connect_first_byte_time,'; access_log %%TESTDIR%%/connect.log connect; - error_log %%TESTDIR%%/connect_error.log error; + error_log %%TESTDIR%%/connect_error.log info; resolver 127.0.0.1:18085 ipv6=off; # NOTE: cannot connect ipv6 address ::1 in mac os x. @@ -136,6 +136,16 @@ http { set $proxy_connect_read_timeout "700ms"; } + if ($request ~ "127.0.0.01:8082") { + # must be less than 1s (server 8082 lua sleep(1s)) + set $proxy_connect_read_timeout "800ms"; + } + + if ($request ~ "127.0.0.01:8083") { + # must be less than 0.5s (server 8082 lua sleep(1s)) + set $proxy_connect_read_timeout "300ms"; + } + location / { proxy_pass http://127.0.0.01:8081; } @@ -242,6 +252,22 @@ like($t->read_file('connect.log'), qr/"CONNECT 127.0.0.1:8083 HTTP\/1.1" 200 .+ resolve:0\....,connect:0\....,fbt:0\.5..,/, 'test first byte time: 0.5s'); +# test timeout +$t->write_file('connect_error.log', ""); +$r = http_connect_request('127.0.0.01', '8082', '/'); +is($r, "", "test first byte time: 1s, timeout"); +#'2022/11/24 20:51:13 [info] 15239#0: *15 proxy_connect: connection timed out (110: Connection timed out) while proxying connection, client: 127.0.0.1, server: localhost, request: "CONNECT 127.0.0.01:8082 HTTP/1.1", host: "127.0.0.01" +like($t->read_file('connect_error.log'), + qr/\[info\].* proxy_connect: connection timed out.+ request: "CONNECT 127\.0\.0\.01:8082 HTTP\/..."/, + 'test first byte time: 1s, check timeout in error log'); + +$t->write_file('connect_error.log', ""); +$r = http_connect_request('127.0.0.01', '8083', '/'); +is($r, "", "test first byte time: 0.5s, timeout"); +like($t->read_file('connect_error.log'), + qr/\[info\].* proxy_connect: connection timed out.+ request: "CONNECT 127\.0\.0\.01:8083 HTTP\/..."/, + 'test first byte time: 1s, check timeout in error log'); + $t->stop(); From fa933fae33f9450c7f252a534862d8b8a69b86f6 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Tue, 29 Nov 2022 12:12:19 +0800 Subject: [PATCH 4/9] test cases: remove anything about send_timeout --- t/http_proxy_connect.t | 1 - t/http_proxy_connect_resolve_variables.t | 3 --- t/http_proxy_connect_timeout.t | 11 ++++------- 3 files changed, 4 insertions(+), 11 deletions(-) diff --git a/t/http_proxy_connect.t b/t/http_proxy_connect.t index 3529ef4..918e515 100644 --- a/t/http_proxy_connect.t +++ b/t/http_proxy_connect.t @@ -112,7 +112,6 @@ http { proxy_connect_allow 443 80 8081; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; - proxy_connect_send_timeout 10s; proxy_connect_send_lowat 0; proxy_connect_address $proxy_remote_address; proxy_connect_bind $proxy_local_address; diff --git a/t/http_proxy_connect_resolve_variables.t b/t/http_proxy_connect_resolve_variables.t index e79c0ce..d8093e3 100644 --- a/t/http_proxy_connect_resolve_variables.t +++ b/t/http_proxy_connect_resolve_variables.t @@ -106,11 +106,9 @@ http { proxy_connect_allow all; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; - proxy_connect_send_timeout 10s; proxy_connect_send_lowat 0; set $proxy_connect_connect_timeout "101ms"; - set $proxy_connect_send_timeout "102ms"; set $proxy_connect_read_timeout "103ms"; if ($uri = "/200") { @@ -123,7 +121,6 @@ http { if ($host = "test-read-timeout.com") { set $proxy_connect_connect_timeout "3ms"; set $proxy_connect_read_timeout "1ms"; - set $proxy_connect_send_timeout "2ms"; } if ($request ~ "127.0.0.1:8082") { diff --git a/t/http_proxy_connect_timeout.t b/t/http_proxy_connect_timeout.t index 5e9001c..55e67ee 100644 --- a/t/http_proxy_connect_timeout.t +++ b/t/http_proxy_connect_timeout.t @@ -76,7 +76,7 @@ http { log_format connect '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent var:$connect_host-$connect_port-$connect_addr ' - ' c:$proxy_connect_connect_timeout,s:$proxy_connect_send_timeout,r:$proxy_connect_read_timeout'; + ' c:$proxy_connect_connect_timeout,r:$proxy_connect_read_timeout'; access_log %%TESTDIR%%/connect.log connect; error_log %%TESTDIR%%/connect_error.log error; @@ -92,10 +92,8 @@ http { proxy_connect_allow all; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; - proxy_connect_send_timeout 10s; set $proxy_connect_connect_timeout "101ms"; - set $proxy_connect_send_timeout "102ms"; set $proxy_connect_read_timeout "103ms"; if ($host = "test-connect-timeout.com") { @@ -104,7 +102,6 @@ http { if ($host = "test-read-timeout.com") { set $proxy_connect_connect_timeout "3ms"; set $proxy_connect_read_timeout "1ms"; - set $proxy_connect_send_timeout "2ms"; } location / { @@ -137,7 +134,7 @@ TODO: { local $TODO = '# This case will pass, if connecting 8.8.8.8 timed out.'; like(http_connect_request('test-connect-timeout.com', '8888', '/'), qr/504/, 'connect timed out: set $var'); like($t->read_file('connect.log'), - qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" 504 .+ c:1,s:102,r:103/, + qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" 504 .+ c:1,r:103/, 'connect timed out log: get $var & status=504'); like($t->read_file('connect_error.log'), qr/proxy_connect: upstream connect timed out \(peer:8\.8\.8\.8:8888\) while connecting to upstream/, @@ -148,10 +145,10 @@ http_connect_request('test-read-timeout.com', '8888', '/'); # test reading variables of $proxy_connect_*_timeout like($t->read_file('connect.log'), - qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" ... .+ c:1,s:102,r:103/, + qr/"CONNECT test-connect-timeout.com:8888 HTTP\/1.1" ... .+ c:1,r:103/, 'connect timed out log: get $var'); like($t->read_file('connect.log'), - qr/"CONNECT test-read-timeout.com:8888 HTTP\/1.1" ... .+ c:3,s:2,r:1/, + qr/"CONNECT test-read-timeout.com:8888 HTTP\/1.1" ... .+ c:3,r:1/, 'connect/send/read timed out log: get $var'); $t->stop(); From 0fb26c7a3fce673757629a028297a7f1d8db24d8 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Tue, 29 Nov 2022 14:35:15 +0800 Subject: [PATCH 5/9] http_proxy_connect_timeout.t: added test case for data timeout 1. asdded test case data timeout 2. simplify code of dns daemon (from nginx-tests/http_resolver_aaaa.t) --- t/http_proxy_connect_timeout.t | 374 ++++++++++++++++++++++----------- 1 file changed, 249 insertions(+), 125 deletions(-) diff --git a/t/http_proxy_connect_timeout.t b/t/http_proxy_connect_timeout.t index 55e67ee..084c31f 100644 --- a/t/http_proxy_connect_timeout.t +++ b/t/http_proxy_connect_timeout.t @@ -10,7 +10,9 @@ use warnings; use strict; use Test::More; +use Time::HiRes; # use Test::Simple 'no_plan'; +use Test::Nginx::Stream qw/ stream /; BEGIN { use FindBin; chdir($FindBin::Bin); } @@ -23,40 +25,7 @@ use Net::DNS::Nameserver; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy/); #->plan(12); - -############################################################################### - -my $test_enable_rewrite_phase = 1; - -if (defined $ENV{TEST_DISABLE_REWRITE_PHASE}) { - $test_enable_rewrite_phase = 0; -} - -print("+ test_enable_rewrite_phase: $test_enable_rewrite_phase\n"); - -plan(skip_all => 'No rewrite phase enabled') if ($test_enable_rewrite_phase == 0); - -# --- init DNS server --- - -my $bind_pid; -my $bind_server_port = 18085; - -# SRV record, not used -my %route_map; - -# A record -my %aroute_map = ( - 'test-connect-timeout.com' => [[300, "8.8.8.8"]], - 'test-read-timeout.com' => [[300, "8.8.8.8"]], -); - -# AAAA record (ipv6) -my %aaaaroute_map; - -start_bind(); - -# --- end --- +my $t = Test::Nginx->new()->has(qw/http proxy proxy_connect/)->plan(16); ############################################################################### @@ -81,7 +50,7 @@ http { access_log %%TESTDIR%%/connect.log connect; error_log %%TESTDIR%%/connect_error.log error; - resolver 127.0.0.1:18085 ipv6=off; # NOTE: cannot connect ipv6 address ::1 in mac os x. + resolver 127.0.0.1:%%PORT_8981_UDP%% ipv6=off; # NOTE: cannot connect ipv6 address ::1 in mac os x. server { listen 127.0.0.1:8080; @@ -126,9 +95,9 @@ if ($@) { $t->run(); } -#if (not $test_enable_rewrite_phase) { -# exit -#} +$t->run_daemon(\&dns_daemon, port(8981), $t); +$t->waitforfile($t->testdir . '/' . port(8981)); + TODO: { local $TODO = '# This case will pass, if connecting 8.8.8.8 timed out.'; @@ -149,16 +118,117 @@ like($t->read_file('connect.log'), 'connect timed out log: get $var'); like($t->read_file('connect.log'), qr/"CONNECT test-read-timeout.com:8888 HTTP\/1.1" ... .+ c:3,r:1/, - 'connect/send/read timed out log: get $var'); + 'connect/read timed out log: get $var'); $t->stop(); +############################################################################### + +$nginx_conf = <<'EOF'; +%%TEST_GLOBALS%% +daemon off; +events { } + +http { + %%TEST_GLOBALS_HTTP%% + + #LUA_PACKAGE_PATH + # If you build nginx with lua-nginx-module, please enable + # directive "lua_package_path". For more details, see: + # https://github.com/openresty/lua-nginx-module#installation + #lua_package_path "/path/to/lib/lua/?.lua;;"; + + log_format connect '$remote_addr - $remote_user [$time_local] "$request" ' + '$status $body_bytes_sent var:$connect_host-$connect_port-$connect_addr ' + ' c:$proxy_connect_connect_timeout,r:$proxy_connect_read_timeout'; + + access_log %%TESTDIR%%/connect.log connect; + error_log %%TESTDIR%%/connect_timeout_error.log debug; + + resolver 127.0.0.1:18085 ipv6=off; # NOTE: cannot connect ipv6 address ::1 in mac os x. + + server { + listen 127.0.0.1:8080; + server_name localhost; + + # forward proxy for CONNECT method + proxy_connect; + proxy_connect_allow all; + + proxy_connect_read_timeout 10s; + + proxy_connect_address "127.0.0.1:8081"; + + if ($http_x_timeout) { + set $proxy_connect_read_timeout $http_x_timeout; + } + + location / { + proxy_pass http://127.0.0.1:8081; + } + } +} + +EOF + +$t->write_file_expand('nginx.conf', $nginx_conf); + +$t->run_daemon(\&stream_daemon); + +eval { + $t->run(); +}; + +if ($@) { + print("+ Retry new nginx conf: remove \"ipv6=off\"\n"); + + $nginx_conf =~ s/ ipv6=off;/;/g; # remove ipv6=off in resolver directive. + $t->write_file_expand('nginx.conf', $nginx_conf); + $t->run(); +} + +print("+ try to waitforsocket...\n"); +$t->waitforsocket('127.0.0.1:' . port(8081)) + or die "Can't start stream backend server"; +print("+ try to waitforsocket...done\n"); + +# test time out of data proxying ( proxy_connect_read_timeout) +my $str = '1234567890' x 10 . 'F'; +my $length = length($str); +my $sport = port(8081); +my $s; -# --- stop DNS server --- +# test: timeout expired or not -stop_bind(); +$s = stream('127.0.0.1:' . port(8080)); -done_testing(); +like($s->io(< 0.5), qr/200 Connection Established/, "establish CONNECT tunnel"); +CONNECT 127.0.0.1:$sport HTTP/1.1 +Host: stream +X-Timeout: 1000ms + +EOF + +my $i; +for ($i = 0; $i < 8; $i++) { + my $ms = $i/10; + Time::HiRes::sleep($ms); # < timeout + is($s->io($str, length => $length), $str, + "timeout not expired, then sleep $ms s"); +} + +# check log +#2022/11/29 13:49:28 [info] 1746#0: *3 proxy_connect: connection timed out (110: Connection timed out) while proxying connection, client: 127.0.0.1, server: localhost, request: "CONNECT 127.0.0.1:8081 HTTP/1.1", host: "stream" +unlike($t->read_file('connect_timeout_error.log'), + qr/proxy_connect: connection timed out .* "CONNECT .*", host: "stream"/, + 'get log: not timed out'); + +Time::HiRes::sleep(1.2); # > timeout +like($t->read_file('connect_timeout_error.log'), + qr/proxy_connect: connection timed out .* "CONNECT .*", host: "stream"/, + 'get log: timed out'); + +$t->stop(); ############################################################################### @@ -217,108 +287,162 @@ EOF # --- DNS Server --- sub reply_handler { - my ($qname, $qclass, $qtype, $peerhost, $query, $conn) = @_; - my ($rcode, @ans, @auth, @add); - # print("DNS reply: receive query=$qname, $qclass, $qtype, $peerhost, $query, $conn\n"); - - if ($qtype eq "SRV" && exists($route_map{$qname})) { - my @records = @{$route_map{$qname}}; - for (my $i = 0; $i < scalar(@records); $i++) { - my ($ttl, $weight, $priority, $port, $origin_addr) = @{$records[$i]}; - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $priority $weight $port $origin_addr"); - push @ans, $rr; - # print("DNS reply: $qname $ttl $qclass $qtype $origin_addr\n"); - } + my ($recv_data, $port, $state) = @_; - $rcode = "NOERROR"; - } elsif (($qtype eq "A") && exists($aroute_map{$qname})) { - my @records = @{$aroute_map{$qname}}; - for (my $i = 0; $i < scalar(@records); $i++) { - my ($ttl, $origin_addr) = @{$records[$i]}; - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $origin_addr"); - push @ans, $rr; - # print("DNS reply: $qname $ttl $qclass $qtype $origin_addr\n"); - } + my (@name, @rdata); - $rcode = "NOERROR"; - } elsif (($qtype eq "AAAA") && exists($aaaaroute_map{$qname})) { - my @records = @{$aaaaroute_map{$qname}}; - for (my $i = 0; $i < scalar(@records); $i++) { - my ($ttl, $origin_addr) = @{$records[$i]}; - my $rr = new Net::DNS::RR("$qname $ttl $qclass $qtype $origin_addr"); - push @ans, $rr; - # print("DNS reply: $qname $ttl $qclass $qtype $origin_addr\n"); - } + use constant NOERROR => 0; + use constant SERVFAIL => 2; + use constant NXDOMAIN => 3; - $rcode = "NOERROR"; - } else { - $rcode = "NXDOMAIN"; - } + use constant A => 1; + use constant CNAME => 5; + use constant AAAA => 28; + use constant DNAME => 39; + + use constant IN => 1; + + # default values + + my ($hdr, $rcode, $ttl) = (0x8180, NOERROR, 3600); - # mark the answer as authoritative (by setting the 'aa' flag) - my $headermask = { ra => 1 }; + # decode name - # specify EDNS options { option => value } - my $optionmask = { }; + my ($len, $offset) = (undef, 12); + while (1) { + $len = unpack("\@$offset C", $recv_data); + last if $len == 0; + $offset++; + push @name, unpack("\@$offset A$len", $recv_data); + $offset += $len; + } - return ($rcode, \@ans, \@auth, \@add, $headermask, $optionmask); + $offset -= 1; + my ($id, $type, $class) = unpack("n x$offset n2", $recv_data); + + my $name = join('.', @name); + + if (($name eq 'test-connect-timeout.com') || + ($name eq 'test-read-timeout.com')) + { + if ($type == A) { + push @rdata, rd_addr($ttl, '8.8.8.8'); + } + } + + $len = @name; + pack("n6 (C/a*)$len x n2", $id, $hdr | $rcode, 1, scalar @rdata, + 0, 0, @name, $type, $class) . join('', @rdata); } -sub bind_daemon { - my $ns = new Net::DNS::Nameserver( - LocalAddr => ['127.0.0.1'], - LocalPort => $bind_server_port, - ReplyHandler => \&reply_handler, - Verbose => 0, # Verbose = 1 to print debug info - Truncate => 0 - ) || die "[D] DNS server: couldn't create nameserver object\n"; +sub rd_addr { + my ($ttl, $addr) = @_; + + my $code = 'split(/\./, $addr)'; - $ns->main_loop; + pack 'n3N nC4', 0xc00c, A, IN, $ttl, eval "scalar $code", eval($code); } -sub start_bind { - if (defined $bind_server_port) { +sub expand_ip6 { + my ($addr) = @_; - print "+ DNS server: try to bind server port: $bind_server_port\n"; + substr ($addr, index($addr, "::"), 2) = + join "0", map { ":" } (0 .. 8 - (split /:/, $addr) + 1); + map { hex "0" x (4 - length $_) . "$_" } split /:/, $addr; +} - $t->run_daemon(\&bind_daemon); - $bind_pid = pop @{$t->{_daemons}}; +sub rd_addr6 { + my ($ttl, $addr) = @_; - print "+ DNS server: daemon pid: $bind_pid\n"; + pack 'n3N nn8', 0xc00c, AAAA, IN, $ttl, 16, expand_ip6($addr); +} - my $s; - my $i = 1; - while (not $s) { - $s = IO::Socket::INET->new( - Proto => 'tcp', - PeerAddr => "127.0.0.1", - PeerPort => $bind_server_port - ); - sleep 0.1; - $i++ > 20 and last; - } - sleep 0.1; - $s or die "cannot connect to DNS server"; - close($s) or die 'can not connect to DNS server'; +sub dns_daemon { + my ($port, $t) = @_; - print "+ DNS server: working\n"; + my ($data, $recv_data); + my $socket = IO::Socket::INET->new( + LocalAddr => '127.0.0.1', + LocalPort => $port, + Proto => 'udp', + ) + or die "Can't create listening socket: $!\n"; - END { - print("+ try to stop $bind_pid\n"); - stop_bind(); - } - } + # track number of relevant queries + + my %state = ( + cnamecnt => 0, + twocnt => 0, + manycnt => 0, + ); + + # signal we are ready + + open my $fh, '>', $t->testdir() . '/' . $port; + close $fh; + + while (1) { + $socket->recv($recv_data, 65536); + $data = reply_handler($recv_data, $port, \%state); + $socket->send($data); + } } -sub stop_bind { - if (defined $bind_pid) { - # kill dns daemon - kill $^O eq 'MSWin32' ? 15 : 'TERM', $bind_pid; - wait; +################################################################################ - $bind_pid = undef; - print ("+ DNS server: stop\n"); - } +sub stream_daemon { + my $server = IO::Socket::INET->new( + Proto => 'tcp', + LocalAddr => '127.0.0.1:' . port(8081), + Listen => 5, + Reuse => 1 + ) + or die "Can't create listening socket: $!\n"; + + print("+ stream daemon started.\n"); + + my $sel = IO::Select->new($server); + + local $SIG{PIPE} = 'IGNORE'; + + while (my @ready = $sel->can_read) { + foreach my $fh (@ready) { + if ($server == $fh) { + my $new = $fh->accept; + $new->autoflush(1); + $sel->add($new); + + } elsif (stream_handle_client($fh)) { + $sel->remove($fh); + $fh->close; + } + } + } } -############################################################################### +sub stream_handle_client { + my ($client) = @_; + + log2c("(new connection $client)"); + + $client->sysread(my $buffer, 65536) or return 1; + + log2i("$client $buffer"); + $client->syswrite($buffer); + return 0; + + log2i("$client $buffer"); + + my $close = $buffer =~ /F/; + + log2o("$client $buffer"); + + $client->syswrite($buffer); + + return $close; +} + +sub log2i { Test::Nginx::log_core('|| <<', @_); } +sub log2o { Test::Nginx::log_core('|| >>', @_); } +sub log2c { Test::Nginx::log_core('||', @_); } +############################################################################## From f95c93a849f8d0acd955f100266ac461d6d3d98a Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Tue, 29 Nov 2022 14:37:41 +0800 Subject: [PATCH 6/9] http_proxy_connect_resolve_variables.t: remove proxy_connect_send_lowat directive --- t/http_proxy_connect_resolve_variables.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/http_proxy_connect_resolve_variables.t b/t/http_proxy_connect_resolve_variables.t index d8093e3..7058f84 100644 --- a/t/http_proxy_connect_resolve_variables.t +++ b/t/http_proxy_connect_resolve_variables.t @@ -106,7 +106,6 @@ http { proxy_connect_allow all; proxy_connect_connect_timeout 10s; proxy_connect_read_timeout 10s; - proxy_connect_send_lowat 0; set $proxy_connect_connect_timeout "101ms"; set $proxy_connect_read_timeout "103ms"; @@ -158,6 +157,7 @@ http { server { access_log off; listen 8082; + rewrite_by_lua ' ngx.sleep(1) ngx.say("8082 server fbt") From 1916e6f2cd7e337caff1da5592b4c7a367f4d21f Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Tue, 29 Nov 2022 14:44:45 +0800 Subject: [PATCH 7/9] fixed t/http_proxy_connect_timeout.t: dont skip module --- t/http_proxy_connect_timeout.t | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/t/http_proxy_connect_timeout.t b/t/http_proxy_connect_timeout.t index 084c31f..139e48c 100644 --- a/t/http_proxy_connect_timeout.t +++ b/t/http_proxy_connect_timeout.t @@ -25,7 +25,7 @@ use Net::DNS::Nameserver; select STDERR; $| = 1; select STDOUT; $| = 1; -my $t = Test::Nginx->new()->has(qw/http proxy proxy_connect/)->plan(16); +my $t = Test::Nginx->new()->has(qw/http proxy/)->plan(16); ############################################################################### From 3858fa495e8c8a776fc9b10a3509db8136c4ba68 Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Tue, 29 Nov 2022 14:57:40 +0800 Subject: [PATCH 8/9] github workflow: use openresty/luajit2 instead --- .github/workflows/ci.yml | 9 ++++++--- .github/workflows/test_nginx_lastest_commit.yml | 10 ++++++---- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index dc58637..b14e8de 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -24,12 +24,15 @@ jobs: sudo apt install -y libpcre3 libpcre3-dev sudo apt-get install libnet-dns-perl sudo cpan -T -i Test::More + - name: 'checkout luajit2' + uses: actions/checkout@v3 + with: + repository: openresty/luajit2 + path: luajit2 - name: install luajit + working-directory: luajit2 run: | pwd - wget https://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz - tar xf LuaJIT-2.1.0-beta3.tar.gz - cd LuaJIT-2.1.0-beta3 make -j sudo make install ls /usr/local/lib/ |grep lua diff --git a/.github/workflows/test_nginx_lastest_commit.yml b/.github/workflows/test_nginx_lastest_commit.yml index e9a1e76..3794a8f 100644 --- a/.github/workflows/test_nginx_lastest_commit.yml +++ b/.github/workflows/test_nginx_lastest_commit.yml @@ -22,12 +22,14 @@ jobs: sudo apt install -y libpcre3 libpcre3-dev sudo apt-get install libnet-dns-perl sudo cpan -T -i Test::More + - name: 'checkout luajit2' + uses: actions/checkout@v3 + with: + repository: openresty/luajit2 + path: luajit2 - name: install luajit + working-directory: luajit2 run: | - pwd - wget https://luajit.org/download/LuaJIT-2.1.0-beta3.tar.gz - tar xf LuaJIT-2.1.0-beta3.tar.gz - cd LuaJIT-2.1.0-beta3 make -j sudo make install ls /usr/local/lib/ |grep lua From 0bc35f6957cf4a0d89325cfad7cbd7a75b57a39f Mon Sep 17 00:00:00 2001 From: Xiaochen Wang Date: Tue, 29 Nov 2022 15:41:58 +0800 Subject: [PATCH 9/9] new directive proxy_connect_data_timeout Use proxy_connect_data_timeout instead of proxy_connect_read_timeout and proxy_connect_send_timeout. Keep function of the directive proxy_connect_read_timeout as proxy_connect_data_timeout for compatibility. --- README.md | 45 ++++++++++++++++-------- ngx_http_proxy_connect_module.c | 31 +++++++++++----- t/http_proxy_connect.t | 5 ++- t/http_proxy_connect_resolve_variables.t | 16 ++++----- t/http_proxy_connect_timeout.t | 16 ++++----- 5 files changed, 71 insertions(+), 42 deletions(-) diff --git a/README.md b/README.md index 2ec668e..cccf067 100644 --- a/README.md +++ b/README.md @@ -24,8 +24,9 @@ Table of Contents * [proxy_connect](#proxy_connect) * [proxy_connect_allow](#proxy_connect_allow) * [proxy_connect_connect_timeout](#proxy_connect_connect_timeout) - * [proxy_connect_read_timeout](#proxy_connect_read_timeout) - * [proxy_connect_send_timeout](#proxy_connect_send_timeout) + * [proxy_connect_data_timeout](#proxy_connect_data_timeout) + * [proxy_connect_read_timeout(deprecated)](#proxy_connect_read_timeout) + * [proxy_connect_send_timeout(deprecated)](#proxy_connect_send_timeout) * [proxy_connect_address](#proxy_connect_address) * [proxy_connect_bind](#proxy_connect_bind) * [proxy_connect_response](#proxy_connect_response) @@ -34,8 +35,9 @@ Table of Contents * [$connect_port](#connect_port) * [$connect_addr](#connect_addr) * [$proxy_connect_connect_timeout](#proxy_connect_connect_timeout-1) - * [$proxy_connect_read_timeout](#proxy_connect_read_timeout-1) - * [$proxy_connect_send_timeout](#proxy_connect_send_timeout-1) + * [$proxy_connect_data_timeout](#proxy_connect_data_timeout-1) + * [$proxy_connect_read_timeout(deprecated)](#proxy_connect_read_timeout-1) + * [$proxy_connect_send_timeout(deprecated)](#proxy_connect_send_timeout-1) * [$proxy_connect_resolve_time](#proxy_connect_resolve_time) * [$proxy_connect_connect_time](#proxy_connect_connect_time) * [$proxy_connect_first_byte_time](#proxy_connect_first_byte_time) @@ -67,8 +69,7 @@ Configuration Example proxy_connect; proxy_connect_allow 443 563; proxy_connect_connect_timeout 10s; - proxy_connect_read_timeout 10s; - proxy_connect_send_timeout 10s; + proxy_connect_data_timeout 10s; # forward proxy for non-CONNECT request location / { @@ -329,6 +330,14 @@ Context: `server` Defines a timeout for establishing a connection with a proxied server. +proxy_connect_data_timeout +-------------------------- + +Syntax: **proxy_connect_data_timeout `time`** +Default: `60s` +Context: `server` + +Sets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed. proxy_connect_read_timeout -------------------------- @@ -337,7 +346,9 @@ Syntax: **proxy_connect_read_timeout `time`** Default: `60s` Context: `server` -Sets the timeout between two successive read or write operations on client or proxied server connections. If no data is transmitted within this time, the connection is closed. +Deprecated. + +It has the same function as the directive `proxy_connect_data_timeout` for compatibility. You can configure only one of the directives (`proxy_connect_data_timeout` or `proxy_connect_read_timeout`). proxy_connect_send_timeout -------------------------- @@ -346,8 +357,9 @@ Syntax: **proxy_connect_send_timeout `time`** Default: `60s` Context: `server` -Deprecated, it has no function. -Use the directive `proxy_connect_read_timeout` instead for both read and write operations. +Deprecated. + +It has no function. proxy_connect_address --------------------- @@ -450,27 +462,32 @@ For example: # Set default value proxy_connect_connect_timeout 10s; -proxy_connect_read_timeout 10s; -proxy_connect_send_timeout 10s; +proxy_connect_data_timeout 10s; # Overlap default value if ($host = "test.com") { set $proxy_connect_connect_timeout "10ms"; - set $proxy_connect_read_timeout "10ms"; - set $proxy_connect_send_timeout "10ms"; + set $proxy_connect_data_timeout "10ms"; } ``` +$proxy_connect_data_timeout +--------------------------- + +Get or set a timeout of [`proxy_connect_data_timeout` directive](#proxy_connect_data_timeout). + $proxy_connect_read_timeout --------------------------- -Get or set a timeout of [`proxy_connect_read_timeout` directive](#proxy_connect_read_timeout). +Deprecated. +It still can get or set a timeout of [`proxy_connect_data_timeout` directive](#proxy_connect_data_timeout) for compatibility. $proxy_connect_send_timeout --------------------------- Deprecated. +It has no function. $proxy_connect_resolve_time --------------------------- diff --git a/ngx_http_proxy_connect_module.c b/ngx_http_proxy_connect_module.c index 63bcfd1..2e6d258 100644 --- a/ngx_http_proxy_connect_module.c +++ b/ngx_http_proxy_connect_module.c @@ -28,7 +28,7 @@ typedef struct { ngx_flag_t allow_port_all; ngx_array_t *allow_ports; - ngx_msec_t read_timeout; + ngx_msec_t data_timeout; ngx_msec_t send_timeout; ngx_msec_t connect_timeout; @@ -101,7 +101,7 @@ typedef struct { ngx_msec_t connect_timeout; ngx_msec_t send_timeout; - ngx_msec_t read_timeout; + ngx_msec_t data_timeout; } ngx_http_proxy_connect_ctx_t; @@ -164,11 +164,18 @@ static ngx_command_t ngx_http_proxy_connect_commands[] = { 0, NULL }, + { ngx_string("proxy_connect_data_timeout"), + NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, + ngx_conf_set_msec_slot, + NGX_HTTP_LOC_CONF_OFFSET, + offsetof(ngx_http_proxy_connect_loc_conf_t, data_timeout), + NULL }, + { ngx_string("proxy_connect_read_timeout"), NGX_HTTP_MAIN_CONF|NGX_HTTP_SRV_CONF|NGX_CONF_TAKE1, ngx_conf_set_msec_slot, NGX_HTTP_LOC_CONF_OFFSET, - offsetof(ngx_http_proxy_connect_loc_conf_t, read_timeout), + offsetof(ngx_http_proxy_connect_loc_conf_t, data_timeout), NULL }, { ngx_string("proxy_connect_send_timeout"), @@ -260,10 +267,16 @@ static ngx_http_variable_t ngx_http_proxy_connect_vars[] = { offsetof(ngx_http_proxy_connect_ctx_t, connect_timeout), NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("proxy_connect_data_timeout"), + ngx_http_proxy_connect_variable_set_time, + ngx_http_proxy_connect_variable_get_time, + offsetof(ngx_http_proxy_connect_ctx_t, data_timeout), + NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_CHANGEABLE, 0 }, + { ngx_string("proxy_connect_read_timeout"), ngx_http_proxy_connect_variable_set_time, ngx_http_proxy_connect_variable_get_time, - offsetof(ngx_http_proxy_connect_ctx_t, read_timeout), + offsetof(ngx_http_proxy_connect_ctx_t, data_timeout), NGX_HTTP_VAR_NOCACHEABLE|NGX_HTTP_VAR_CHANGEABLE, 0 }, { ngx_string("proxy_connect_send_timeout"), @@ -620,7 +633,7 @@ ngx_http_proxy_connect_send_connection_established(ngx_http_request_t *r) r->write_event_handler = ngx_http_proxy_connect_send_handler; - ngx_add_timer(c->write, ctx->read_timeout); + ngx_add_timer(c->write, ctx->data_timeout); if (ngx_handle_write_event(c->write, clcf->send_lowat) != NGX_OK) { ngx_http_proxy_connect_finalize_request(r, u, @@ -784,7 +797,7 @@ ngx_http_proxy_connect_tunnel(ngx_http_request_t *r, } if (!c->read->delayed && !pc->read->delayed) { - ngx_add_timer(c->write, ctx->read_timeout); + ngx_add_timer(c->write, ctx->data_timeout); } else if (c->write->timer_set) { ngx_del_timer(c->write); @@ -1928,7 +1941,7 @@ ngx_http_proxy_connect_create_loc_conf(ngx_conf_t *cf) conf->connect_timeout = NGX_CONF_UNSET_MSEC; conf->send_timeout = NGX_CONF_UNSET_MSEC; - conf->read_timeout = NGX_CONF_UNSET_MSEC; + conf->data_timeout = NGX_CONF_UNSET_MSEC; conf->send_lowat = NGX_CONF_UNSET_SIZE; conf->buffer_size = NGX_CONF_UNSET_SIZE; @@ -1954,7 +1967,7 @@ ngx_http_proxy_connect_merge_loc_conf(ngx_conf_t *cf, void *parent, void *child) ngx_conf_merge_msec_value(conf->send_timeout, prev->send_timeout, 60000); - ngx_conf_merge_msec_value(conf->read_timeout, prev->read_timeout, 60000); + ngx_conf_merge_msec_value(conf->data_timeout, prev->data_timeout, 60000); ngx_conf_merge_size_value(conf->send_lowat, prev->send_lowat, 0); @@ -2346,7 +2359,7 @@ ngx_http_proxy_connect_post_read_handler(ngx_http_request_t *r) ctx->connect_timeout = pclcf->connect_timeout; ctx->send_timeout = pclcf->send_timeout; - ctx->read_timeout = pclcf->read_timeout; + ctx->data_timeout = pclcf->data_timeout; ngx_http_set_ctx(r, ctx, ngx_http_proxy_connect_module); } diff --git a/t/http_proxy_connect.t b/t/http_proxy_connect.t index 918e515..6416213 100644 --- a/t/http_proxy_connect.t +++ b/t/http_proxy_connect.t @@ -111,8 +111,7 @@ http { proxy_connect; proxy_connect_allow 443 80 8081; proxy_connect_connect_timeout 10s; - proxy_connect_read_timeout 10s; - proxy_connect_send_lowat 0; + proxy_connect_data_timeout 10s; proxy_connect_address $proxy_remote_address; proxy_connect_bind $proxy_local_address; @@ -614,7 +613,7 @@ sub start_bind { print "+ DNS server: working\n"; END { - print("+ try to stop $bind_pid\n"); + print("+ try to stop\n"); stop_bind(); } } diff --git a/t/http_proxy_connect_resolve_variables.t b/t/http_proxy_connect_resolve_variables.t index 7058f84..4e94f8e 100644 --- a/t/http_proxy_connect_resolve_variables.t +++ b/t/http_proxy_connect_resolve_variables.t @@ -105,10 +105,10 @@ http { proxy_connect; proxy_connect_allow all; proxy_connect_connect_timeout 10s; - proxy_connect_read_timeout 10s; + proxy_connect_data_timeout 10s; set $proxy_connect_connect_timeout "101ms"; - set $proxy_connect_read_timeout "103ms"; + set $proxy_connect_data_timeout "103ms"; if ($uri = "/200") { return 200; @@ -119,27 +119,27 @@ http { } if ($host = "test-read-timeout.com") { set $proxy_connect_connect_timeout "3ms"; - set $proxy_connect_read_timeout "1ms"; + set $proxy_connect_data_timeout "1ms"; } if ($request ~ "127.0.0.1:8082") { # must be larger than 1s (server 8082 lua sleep(1s)) - set $proxy_connect_read_timeout "1200ms"; + set $proxy_connect_data_timeout "1200ms"; } if ($request ~ "127.0.0.1:8083") { # must be larger than 0.5s (server 8082 lua sleep(0.5s)) - set $proxy_connect_read_timeout "700ms"; + set $proxy_connect_data_timeout "700ms"; } if ($request ~ "127.0.0.01:8082") { # must be less than 1s (server 8082 lua sleep(1s)) - set $proxy_connect_read_timeout "800ms"; + set $proxy_connect_data_timeout "800ms"; } if ($request ~ "127.0.0.01:8083") { # must be less than 0.5s (server 8082 lua sleep(1s)) - set $proxy_connect_read_timeout "300ms"; + set $proxy_connect_data_timeout "300ms"; } location / { @@ -419,7 +419,7 @@ sub start_bind { print "+ DNS server: working\n"; END { - print("+ try to stop $bind_pid\n"); + print("+ try to stop\n"); stop_bind(); } } diff --git a/t/http_proxy_connect_timeout.t b/t/http_proxy_connect_timeout.t index 139e48c..a7fc969 100644 --- a/t/http_proxy_connect_timeout.t +++ b/t/http_proxy_connect_timeout.t @@ -45,7 +45,7 @@ http { log_format connect '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent var:$connect_host-$connect_port-$connect_addr ' - ' c:$proxy_connect_connect_timeout,r:$proxy_connect_read_timeout'; + ' c:$proxy_connect_connect_timeout,r:$proxy_connect_data_timeout'; access_log %%TESTDIR%%/connect.log connect; error_log %%TESTDIR%%/connect_error.log error; @@ -60,17 +60,17 @@ http { proxy_connect; proxy_connect_allow all; proxy_connect_connect_timeout 10s; - proxy_connect_read_timeout 10s; + proxy_connect_data_timeout 10s; set $proxy_connect_connect_timeout "101ms"; - set $proxy_connect_read_timeout "103ms"; + set $proxy_connect_data_timeout "103ms"; if ($host = "test-connect-timeout.com") { set $proxy_connect_connect_timeout "1ms"; } if ($host = "test-read-timeout.com") { set $proxy_connect_connect_timeout "3ms"; - set $proxy_connect_read_timeout "1ms"; + set $proxy_connect_data_timeout "1ms"; } location / { @@ -140,7 +140,7 @@ http { log_format connect '$remote_addr - $remote_user [$time_local] "$request" ' '$status $body_bytes_sent var:$connect_host-$connect_port-$connect_addr ' - ' c:$proxy_connect_connect_timeout,r:$proxy_connect_read_timeout'; + ' c:$proxy_connect_connect_timeout,r:$proxy_connect_data_timeout'; access_log %%TESTDIR%%/connect.log connect; error_log %%TESTDIR%%/connect_timeout_error.log debug; @@ -155,12 +155,12 @@ http { proxy_connect; proxy_connect_allow all; - proxy_connect_read_timeout 10s; + proxy_connect_data_timeout 10s; proxy_connect_address "127.0.0.1:8081"; if ($http_x_timeout) { - set $proxy_connect_read_timeout $http_x_timeout; + set $proxy_connect_data_timeout $http_x_timeout; } location / { @@ -192,7 +192,7 @@ $t->waitforsocket('127.0.0.1:' . port(8081)) or die "Can't start stream backend server"; print("+ try to waitforsocket...done\n"); -# test time out of data proxying ( proxy_connect_read_timeout) +# test time out of data proxying ( proxy_connect_data_timeout) my $str = '1234567890' x 10 . 'F'; my $length = length($str); my $sport = port(8081);