diff --git a/src/lua/bsdsocket.lua b/src/lua/bsdsocket.lua index 67d5f9f60106ca47f2f6894aa96b3e1af588361f..266e2aad60552e3474bd0a9cd5d3a396081a3174 100644 --- a/src/lua/bsdsocket.lua +++ b/src/lua/bsdsocket.lua @@ -565,29 +565,27 @@ end local function readline_check(self, eols, limit) local rbuf = self.rbuf - if rbuf == nil then - return nil - end if string.len(rbuf) == 0 then return nil end local shortest - for i, eol in pairs(eols) do - if string.len(rbuf) >= string.len(eol) then - local data = string.match(rbuf, "^(.-" .. eol .. ")") - if data ~= nil then - if string.len(data) > limit then - data = string.sub(data, 1, limit) - end - if shortest == nil then - shortest = data - elseif #shortest > #data then - shortest = data - end + for i, eol in ipairs(eols) do + local data = string.match(rbuf, "^(.-" .. eol .. ")") + if data ~= nil then + if string.len(data) > limit then + data = string.sub(data, 1, limit) + end + if shortest == nil then + shortest = data + elseif #shortest > #data then + shortest = data end end end + if shortest == nil and #rbuf >= limit then + return string.sub(rbuf, limit) + end return shortest end @@ -597,6 +595,9 @@ local function readline(self, limit, eol, timeout) end self._errno = nil + if limit == 0 then + return '' + end local data = readline_check(self, eol, limit) if data ~= nil then self.rbuf = string.sub(self.rbuf, string.len(data) + 1) diff --git a/test/box/bsdsocket.result b/test/box/bsdsocket.result index 9f0b5a15c4cb434bba7c7dbee7151cd665a85d0b..1b589404087da3ac81e3cf90760790c63401d92b 100644 --- a/test/box/bsdsocket.result +++ b/test/box/bsdsocket.result @@ -1120,6 +1120,74 @@ lua server:close() --- - true ... +lua body = "a 10\nb 15\nx" +--- +... +lua remaining = #body +--- +... +lua server = box.socket.tcp_server("unix/", "%s", function(s) s:write(body) s:read() end) +--- +... +lua client = box.socket.tcp_connect("unix/", "%s") +--- +... +lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"}) +--- +... +lua buf == "a 10\n" +--- + - true +... +lua remaining = remaining - #buf +--- +... +lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"}) +--- +... +lua buf == "b 15\n" +--- + - true +... +lua remaining = remaining - #buf +--- +... +lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"}) +--- +... +lua buf == "x" +--- + - true +... +lua remaining = remaining - #buf +--- +... +lua remaining == 0 +--- + - true +... +lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"}) +--- +... +lua buf == "" +--- + - true +... +lua buf = client:read({ size = remaining, delimiter = "[\r\n]+"}) +--- +... +lua buf == "" +--- + - true +... +lua client:close() +--- + - true +... +lua server:close() +--- + - true +... lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 'ip') --- ... diff --git a/test/box/bsdsocket.test b/test/box/bsdsocket.test index 72907dbbf9d9220d05ce2d2892601e1301adff87..706061dd313a868df537dbab55bae0ba958ee8b4 100644 --- a/test/box/bsdsocket.test +++ b/test/box/bsdsocket.test @@ -360,6 +360,28 @@ exec admin "lua client:read(123)" exec admin "lua client:close()" exec admin "lua server:close()" +## gh-658: socket:read() incorrectly handles size and delimiter together +exec admin 'lua body = "a 10\\nb 15\\nx"' +exec admin 'lua remaining = #body' +exec admin 'lua server = box.socket.tcp_server("unix/", "%s", function(s) s:write(body) s:read() end)'.format(path) +exec admin 'lua client = box.socket.tcp_connect("unix/", "%s")'.format(path) +exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})' +exec admin 'lua buf == "a 10\\n"' +exec admin 'lua remaining = remaining - #buf' +exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})' +exec admin 'lua buf == "b 15\\n"' +exec admin 'lua remaining = remaining - #buf' +exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})' +exec admin 'lua buf == "x"' +exec admin 'lua remaining = remaining - #buf' +exec admin 'lua remaining == 0' +exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})' +exec admin 'lua buf == ""' +exec admin 'lua buf = client:read({ size = remaining, delimiter = "[\\r\\n]+"})' +exec admin 'lua buf == ""' +exec admin 'lua client:close()' +exec admin 'lua server:close()' + # Test that socket is closed on GC exec admin "lua s = box.socket('AF_UNIX', 'SOCK_STREAM', 'ip')" exec admin "lua s:bind('unix/', '{}')".format(path)