Skip to content

Commit f95c55f

Browse files
committed
bugfix: "closed" error would occur for long-running requests that hold the idle cosocket object for a period of time that is longer than the read timeout setting: we should delete the read event timer in time when the receive call has already got a read event. thanks 欧远宁 for reporting this issue.
1 parent 1b702e5 commit f95c55f

File tree

2 files changed

+205
-14
lines changed

2 files changed

+205
-14
lines changed

src/ngx_http_lua_socket.c

Lines changed: 8 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1716,6 +1716,12 @@ ngx_http_lua_socket_read_handler(ngx_http_request_t *r,
17161716
return;
17171717
}
17181718

1719+
#if 1
1720+
if (c->read->timer_set) {
1721+
ngx_del_timer(c->read);
1722+
}
1723+
#endif
1724+
17191725
if (u->buffer.start != NULL) {
17201726
(void) ngx_http_lua_socket_read(r, u);
17211727
}
@@ -1909,13 +1915,8 @@ ngx_http_lua_socket_connected_handler(ngx_http_request_t *r,
19091915
return;
19101916
}
19111917

1912-
if (c->read->timedout) {
1913-
1914-
ngx_log_error(NGX_LOG_ERR, r->connection->log, 0,
1915-
"lua socket connect timed out");
1916-
1917-
ngx_http_lua_socket_handle_error(r, u, NGX_HTTP_LUA_SOCKET_FT_TIMEOUT);
1918-
return;
1918+
if (c->write->timer_set) {
1919+
ngx_del_timer(c->write);
19191920
}
19201921

19211922
rc = ngx_http_lua_socket_test_connect(c);
@@ -1956,10 +1957,6 @@ ngx_http_lua_socket_connected_handler(ngx_http_request_t *r,
19561957
u->read_event_handler = ngx_http_lua_socket_dummy_handler;
19571958
u->write_event_handler = ngx_http_lua_socket_dummy_handler;
19581959

1959-
if (c->write->timer_set) {
1960-
ngx_del_timer(c->write);
1961-
}
1962-
19631960
ngx_log_debug0(NGX_LOG_DEBUG_HTTP, r->connection->log, 0,
19641961
"lua socket waking up the current request");
19651962

t/058-tcp-socket.t

Lines changed: 197 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,16 +5,16 @@ use Test::Nginx::Socket;
55

66
repeat_each(2);
77

8-
plan tests => repeat_each() * (blocks() * 2 + 5);
8+
plan tests => repeat_each() * (blocks() * 2 + 6);
99

1010
our $HtmlDir = html_dir;
1111

1212
$ENV{TEST_NGINX_CLIENT_PORT} ||= server_port();
1313
$ENV{TEST_NGINX_MEMCACHED_PORT} ||= 11211;
1414
$ENV{TEST_NGINX_RESOLVER} ||= '8.8.8.8';
1515

16-
#no_long_string();
17-
no_diff();
16+
no_long_string();
17+
#no_diff();
1818
run_tests();
1919

2020
__DATA__
@@ -1750,3 +1750,197 @@ subrequest: 200, OK\r
17501750
--- no_error_log
17511751
[error]
17521752
1753+
1754+
1755+
=== TEST 30: read timer cleared in time
1756+
--- config
1757+
server_tokens off;
1758+
location /t {
1759+
#set $port 5000;
1760+
set $port $TEST_NGINX_MEMCACHED_PORT;
1761+
1762+
content_by_lua '
1763+
local sock = ngx.socket.tcp()
1764+
local port = ngx.var.port
1765+
1766+
sock:settimeout(200)
1767+
1768+
local ok, err = sock:connect("127.0.0.1", port)
1769+
if not ok then
1770+
ngx.say("failed to connect: ", err)
1771+
return
1772+
end
1773+
1774+
ngx.say("connected: ", ok)
1775+
1776+
local req = "flush_all\\r\\n"
1777+
1778+
local bytes, err = sock:send(req)
1779+
if not bytes then
1780+
ngx.say("failed to send request: ", err)
1781+
return
1782+
end
1783+
ngx.say("request sent: ", bytes)
1784+
1785+
local line, err, part = sock:receive()
1786+
if line then
1787+
ngx.say("received: ", line)
1788+
1789+
else
1790+
ngx.say("failed to receive a line: ", err, " [", part, "]")
1791+
end
1792+
1793+
ngx.location.capture("/sleep")
1794+
1795+
local bytes, err = sock:send(req)
1796+
if not bytes then
1797+
ngx.say("failed to send request: ", err)
1798+
return
1799+
end
1800+
ngx.say("request sent again: ", bytes)
1801+
1802+
ok, err = sock:close()
1803+
ngx.say("close: ", ok, " ", err)
1804+
';
1805+
}
1806+
1807+
location /sleep {
1808+
echo_sleep 0.5;
1809+
}
1810+
1811+
location /foo {
1812+
echo foo;
1813+
more_clear_headers Date;
1814+
}
1815+
--- request
1816+
GET /t
1817+
--- response_body
1818+
connected: 1
1819+
request sent: 11
1820+
received: OK
1821+
request sent again: 11
1822+
close: 1 nil
1823+
--- no_error_log
1824+
[error]
1825+
1826+
1827+
1828+
=== TEST 31: connect timer cleared in time
1829+
--- config
1830+
server_tokens off;
1831+
location /t {
1832+
#set $port 5000;
1833+
set $port $TEST_NGINX_MEMCACHED_PORT;
1834+
1835+
content_by_lua '
1836+
local sock = ngx.socket.tcp()
1837+
local port = ngx.var.port
1838+
1839+
sock:settimeout(200)
1840+
1841+
local ok, err = sock:connect("127.0.0.1", port)
1842+
if not ok then
1843+
ngx.say("failed to connect: ", err)
1844+
return
1845+
end
1846+
1847+
ngx.say("connected: ", ok)
1848+
1849+
ngx.location.capture("/sleep")
1850+
1851+
local req = "flush_all\\r\\n"
1852+
local bytes, err = sock:send(req)
1853+
if not bytes then
1854+
ngx.say("failed to send request: ", err)
1855+
return
1856+
end
1857+
ngx.say("request sent: ", bytes)
1858+
1859+
ok, err = sock:close()
1860+
ngx.say("close: ", ok, " ", err)
1861+
';
1862+
}
1863+
1864+
location /sleep {
1865+
echo_sleep 0.5;
1866+
}
1867+
1868+
location /foo {
1869+
echo foo;
1870+
more_clear_headers Date;
1871+
}
1872+
--- request
1873+
GET /t
1874+
--- response_body
1875+
connected: 1
1876+
request sent: 11
1877+
close: 1 nil
1878+
--- no_error_log
1879+
[error]
1880+
1881+
1882+
1883+
=== TEST 32: send timer cleared in time
1884+
--- config
1885+
server_tokens off;
1886+
location /t {
1887+
#set $port 5000;
1888+
set $port $TEST_NGINX_MEMCACHED_PORT;
1889+
1890+
content_by_lua '
1891+
local sock = ngx.socket.tcp()
1892+
local port = ngx.var.port
1893+
1894+
sock:settimeout(200)
1895+
1896+
local ok, err = sock:connect("127.0.0.1", port)
1897+
if not ok then
1898+
ngx.say("failed to connect: ", err)
1899+
return
1900+
end
1901+
1902+
ngx.say("connected: ", ok)
1903+
1904+
local req = "flush_all\\r\\n"
1905+
1906+
local bytes, err = sock:send(req)
1907+
if not bytes then
1908+
ngx.say("failed to send request: ", err)
1909+
return
1910+
end
1911+
ngx.say("request sent: ", bytes)
1912+
1913+
ngx.location.capture("/sleep")
1914+
1915+
local line, err, part = sock:receive()
1916+
if line then
1917+
ngx.say("received: ", line)
1918+
1919+
else
1920+
ngx.say("failed to receive a line: ", err, " [", part, "]")
1921+
return
1922+
end
1923+
1924+
ok, err = sock:close()
1925+
ngx.say("close: ", ok, " ", err)
1926+
';
1927+
}
1928+
1929+
location /sleep {
1930+
echo_sleep 0.5;
1931+
}
1932+
1933+
location /foo {
1934+
echo foo;
1935+
more_clear_headers Date;
1936+
}
1937+
--- request
1938+
GET /t
1939+
--- response_body
1940+
connected: 1
1941+
request sent: 11
1942+
received: OK
1943+
close: 1 nil
1944+
--- no_error_log
1945+
[error]
1946+

0 commit comments

Comments
 (0)